Atera API Patterns
Atera REST API fundamentals: X-API-KEY header authentication, OData-style pagination, the 700 requests/minute rate limit, endpoint conventions, and error handling.
Install
npx skills add https://github.com/WYRE-AI/msp-claude-plugins/tree/main/msp-claude-plugins/atera/atera/skills/api-patterns
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wyre-ai-msp-claude-plugins@llmmart
git clone https://github.com/WYRE-AI/msp-claude-plugins.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole wyre-ai/msp-claude-plugins collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Atera API Patterns
Overview
The Atera REST API (v3) provides access to all major entities in the RMM/PSA platform. This skill covers authentication, pagination, rate limiting, error handling, and performance optimization patterns.
Authentication
X-API-KEY Header Authentication
Atera uses a simple API key authentication via the X-API-KEY header:
GET /api/v3/tickets
X-API-KEY: YOUR_API_KEY
Content-Type: application/json
Accept: application/json
Required Headers:
| Header | Value | Description |
|---|---|---|
X-API-KEY |
{your_api_key} |
API key from Atera portal |
Content-Type |
application/json |
For POST/PUT requests |
Accept |
application/json |
Optional, for explicit format |
Obtaining API Key
- Log into Atera portal
- Navigate to Admin > API
- Generate or copy your API key
- Store securely (treat as a password)
Environment Variable Setup
export ATERA_API_KEY="your-api-key-here"
Base URL
All API requests use the following base URL. Atera requires HTTPS; plain HTTP is rejected.
https://app.atera.com/api/v3
Pagination
OData-Style Pagination
Atera uses OData-style pagination with page and itemsInPage parameters:
GET /api/v3/tickets?page=1&itemsInPage=50
X-API-KEY: {api_key}
Pagination Parameters:
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
page |
int | 1 | - | Page number (1-indexed) |
itemsInPage |
int | 20 | 50 | Items per page |
Response Structure
{
"items": [...],
"totalItems": 2847,
"page": 1,
"itemsInPage": 50,
"totalPages": 57
}
Response Fields:
| Field | Type | Description |
|---|---|---|
items |
array | Array of entities |
totalItems |
int | Total count across all pages |
page |
int | Current page number |
itemsInPage |
int | Items in current page |
totalPages |
int | Total number of pages |
Pagination Best Practices
- Use maximum page size - 50 items reduces API calls
- Add delays between pages - Avoid hitting rate limits
- Cache total counts - Don't re-fetch unnecessarily
- Implement retry logic - Handle transient failures
See references/examples.md for a working page-walking implementation.
Rate Limiting
Rate Limit: 700 Requests per Minute
Atera enforces a rate limit of 700 requests per minute per API key.
Rate Limit Headers
Atera may return rate limit information in response headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests per window |
X-RateLimit-Remaining |
Remaining requests |
X-RateLimit-Reset |
Seconds until reset |
Rate Limit Response
When rate limited (HTTP 429):
{
"Message": "Rate limit exceeded. Please wait before making more requests."
}
See references/examples.md for exponential-backoff retry and a sliding-window throttler.
Error Handling
HTTP Status Codes
| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Process response |
| 201 | Created | Entity created successfully |
| 400 | Bad Request | Check request format/values |
| 401 | Unauthorized | Verify API key |
| 403 | Forbidden | Check permissions |
| 404 | Not Found | Entity doesn't exist |
| 429 | Rate Limited | Implement backoff |
| 500 | Server Error | Retry with backoff |
Error Response Format
{
"Message": "Error description here",
"ErrorCode": "SPECIFIC_ERROR_CODE"
}
See references/examples.md for a request wrapper that maps these statuses to actionable errors.
CRUD Operations
Atera does not use PUT. Updates are a POST to the entity's ID URL — the same verb as create, distinguished only by whether the URL carries an ID:
POST /api/v3/tickets # create
POST /api/v3/tickets/54321 # update
DELETE /api/v3/tickets/54321 # delete
Write responses return an ActionID alongside the entity ID rather than the full entity, so re-read the record if you need its post-write state.
See references/api.md for the complete endpoint catalog and full request/response shapes.
Performance Optimization
- Batch operations - group related requests, with a delay between batches
- Cache reference data - customers, contacts, and contracts change slowly
- Parallelize independent reads - but count them against the 700/min budget
See references/examples.md for batching, caching, and parallel-fetch implementations.
Related Skills
- Atera Tickets - Ticket management
- Atera Agents - Agent management
- Atera Customers - Customer management
- Atera Alerts - Alert management
- Atera Devices - Device monitors
Files (msp-claude-plugins)
-
references
-
api.md 2.1 KB
# Atera API Endpoint Catalog Base URL for all requests: `https://app.atera.com/api/v3` ## Core Resources | Endpoint | Methods | Description | |----------|---------|-------------| | `/tickets` | GET, POST, DELETE | Service tickets | | `/tickets/{id}/comments` | GET, POST | Ticket comments | | `/tickets/{id}/workhours` | GET | Work hour entries | | `/agents` | GET, DELETE | RMM agents | | `/agents/{id}/powershell` | POST | Run PowerShell | | `/customers` | GET, POST, DELETE | Customers | | `/contacts` | GET, POST, DELETE | Contacts | | `/alerts` | GET, POST, DELETE | Alerts | ## Device Monitors | Endpoint | Methods | Description | |----------|---------|-------------| | `/devices/generic` | GET | All devices | | `/devices/http` | GET, POST, DELETE | HTTP monitors | | `/devices/snmp` | GET, POST, DELETE | SNMP v1/v2c monitors | | `/devices/snmpv3` | GET, POST, DELETE | SNMP v3 monitors | | `/devices/tcp` | GET, POST, DELETE | TCP monitors | ## Additional Resources | Endpoint | Methods | Description | |----------|---------|-------------| | `/contracts` | GET | Service contracts | | `/billing/invoices` | GET | Billing invoices | | `/customvalues` | GET, POST, DELETE | Custom field values | | `/knowledgebases` | GET | Knowledge base articles | | `/rates` | GET, POST | Product/expense rates | ## CRUD Request Shapes ### Create (POST) ```http POST /api/v3/tickets X-API-KEY: {api_key} Content-Type: application/json { "TicketTitle": "New ticket", "Description": "Issue description", "EndUserID": 12345, "TicketPriority": "Medium" } ``` **Response:** ```json { "ActionID": 54321, "TicketID": 54321 } ``` ### Read (GET) **Single entity:** ```http GET /api/v3/tickets/54321 X-API-KEY: {api_key} ``` **List with pagination:** ```http GET /api/v3/tickets?page=1&itemsInPage=50 X-API-KEY: {api_key} ``` ### Update (POST to specific ID) ```http POST /api/v3/tickets/54321 X-API-KEY: {api_key} Content-Type: application/json { "TicketStatus": "Resolved", "TicketPriority": "Low" } ``` ### Delete (DELETE) ```http DELETE /api/v3/tickets/54321 X-API-KEY: {api_key} ``` **Response:** ```json { "ActionID": 54321, "Success": true } ``` -
examples.md 4.9 KB
# Atera API Code Examples Reference implementations for pagination, retry, throttling, error handling, and performance patterns against the Atera v3 REST API. ## Efficient Pagination ```javascript async function fetchAllItems(endpoint) { const allItems = []; let page = 1; let hasMore = true; while (hasMore) { const response = await fetch( `https://app.atera.com/api/v3/${endpoint}?page=${page}&itemsInPage=50`, { headers: { 'X-API-KEY': process.env.ATERA_API_KEY } } ); const data = await response.json(); allItems.push(...data.items); hasMore = page < data.totalPages; page++; // Respect rate limits if (hasMore) { await sleep(100); // 100ms between requests } } return allItems; } ``` ## Retry with Exponential Backoff ```javascript async function requestWithRetry(url, options, maxRetries = 5) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await fetch(url, options); if (response.status === 429) { // Rate limited - wait and retry const retryAfter = parseInt(response.headers.get('Retry-After')) || 30; const jitter = Math.random() * 1000; console.log(`Rate limited. Waiting ${retryAfter}s...`); await sleep(retryAfter * 1000 + jitter); continue; } if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } catch (error) { if (attempt === maxRetries - 1) throw error; // Exponential backoff with jitter const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000; console.log(`Attempt ${attempt + 1} failed. Retrying in ${delay}ms...`); await sleep(delay); } } } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } ``` ## Request Throttling ```javascript class RateLimiter { constructor(maxRequests = 700, windowMs = 60000) { this.maxRequests = maxRequests; this.windowMs = windowMs; this.requests = []; } async throttle() { const now = Date.now(); // Remove requests outside window this.requests = this.requests.filter(t => t > now - this.windowMs); if (this.requests.length >= this.maxRequests) { // Wait until oldest request expires const waitTime = this.requests[0] - (now - this.windowMs) + 100; await sleep(waitTime); } this.requests.push(Date.now()); } } const limiter = new RateLimiter(); async function makeRequest(endpoint) { await limiter.throttle(); return fetch(`https://app.atera.com/api/v3/${endpoint}`, { headers: { 'X-API-KEY': process.env.ATERA_API_KEY } }); } ``` ## Error Handling Wrapper ```javascript async function handleAteraRequest(endpoint, options = {}) { const response = await fetch( `https://app.atera.com/api/v3/${endpoint}`, { ...options, headers: { 'X-API-KEY': process.env.ATERA_API_KEY, 'Content-Type': 'application/json', ...options.headers } } ); if (!response.ok) { const error = await response.json().catch(() => ({})); switch (response.status) { case 401: throw new Error('Invalid API key. Check ATERA_API_KEY.'); case 403: throw new Error('Permission denied. Check API key permissions.'); case 404: throw new Error(`Resource not found: ${endpoint}`); case 429: throw new Error('Rate limit exceeded. Implement backoff.'); default: throw new Error(error.Message || `API error: ${response.status}`); } } return response.json(); } ``` ## Batch Operations When processing multiple items, batch requests: ```javascript async function batchProcess(items, batchSize = 10, delayMs = 1000) { const results = []; for (let i = 0; i < items.length; i += batchSize) { const batch = items.slice(i, i + batchSize); const batchResults = await Promise.all( batch.map(item => processItem(item)) ); results.push(...batchResults); // Delay between batches to respect rate limits if (i + batchSize < items.length) { await sleep(delayMs); } } return results; } ``` ## Caching Strategy Cache slowly-changing data to reduce API calls: ```javascript const cache = new Map(); async function getCachedData(key, fetchFn, ttlMs = 300000) { const cached = cache.get(key); if (cached && cached.expires > Date.now()) { return cached.data; } const data = await fetchFn(); cache.set(key, { data, expires: Date.now() + ttlMs }); return data; } // Usage const customers = await getCachedData( 'customers', () => fetchAllItems('customers'), 5 * 60 * 1000 // 5 minute cache ); ``` ## Parallel Requests For independent requests, use parallel execution: ```javascript const [tickets, agents, alerts] = await Promise.all([ fetchAllItems('tickets'), fetchAllItems('agents'), fetchAllItems('alerts') ]); ```
-
-
SKILL.md 5.3 KB
--- name: "Atera API Patterns" description: > Atera REST API fundamentals: X-API-KEY header authentication, OData-style pagination, the 700 requests/minute rate limit, endpoint conventions, and error handling. when_to_use: >- When authenticating to or calling the Atera REST API. Use when: atera api, atera authentication, api key atera, atera pagination, api rate limit, atera rest api, api error atera, or odata pagination. --- # Atera API Patterns ## Overview The Atera REST API (v3) provides access to all major entities in the RMM/PSA platform. This skill covers authentication, pagination, rate limiting, error handling, and performance optimization patterns. ## Authentication ### X-API-KEY Header Authentication Atera uses a simple API key authentication via the `X-API-KEY` header: ```http GET /api/v3/tickets X-API-KEY: YOUR_API_KEY Content-Type: application/json Accept: application/json ``` **Required Headers:** | Header | Value | Description | |--------|-------|-------------| | `X-API-KEY` | `{your_api_key}` | API key from Atera portal | | `Content-Type` | `application/json` | For POST/PUT requests | | `Accept` | `application/json` | Optional, for explicit format | ### Obtaining API Key 1. Log into Atera portal 2. Navigate to **Admin** > **API** 3. Generate or copy your API key 4. Store securely (treat as a password) ### Environment Variable Setup ```bash export ATERA_API_KEY="your-api-key-here" ``` ## Base URL All API requests use the following base URL. Atera requires HTTPS; plain HTTP is rejected. ``` https://app.atera.com/api/v3 ``` ## Pagination ### OData-Style Pagination Atera uses OData-style pagination with `page` and `itemsInPage` parameters: ```http GET /api/v3/tickets?page=1&itemsInPage=50 X-API-KEY: {api_key} ``` **Pagination Parameters:** | Parameter | Type | Default | Max | Description | |-----------|------|---------|-----|-------------| | `page` | int | 1 | - | Page number (1-indexed) | | `itemsInPage` | int | 20 | 50 | Items per page | ### Response Structure ```json { "items": [...], "totalItems": 2847, "page": 1, "itemsInPage": 50, "totalPages": 57 } ``` **Response Fields:** | Field | Type | Description | |-------|------|-------------| | `items` | array | Array of entities | | `totalItems` | int | Total count across all pages | | `page` | int | Current page number | | `itemsInPage` | int | Items in current page | | `totalPages` | int | Total number of pages | ### Pagination Best Practices 1. **Use maximum page size** - 50 items reduces API calls 2. **Add delays between pages** - Avoid hitting rate limits 3. **Cache total counts** - Don't re-fetch unnecessarily 4. **Implement retry logic** - Handle transient failures See [references/examples.md](references/examples.md) for a working page-walking implementation. ## Rate Limiting ### Rate Limit: 700 Requests per Minute Atera enforces a rate limit of **700 requests per minute** per API key. ### Rate Limit Headers Atera may return rate limit information in response headers: | Header | Description | |--------|-------------| | `X-RateLimit-Limit` | Maximum requests per window | | `X-RateLimit-Remaining` | Remaining requests | | `X-RateLimit-Reset` | Seconds until reset | ### Rate Limit Response When rate limited (HTTP 429): ```json { "Message": "Rate limit exceeded. Please wait before making more requests." } ``` See [references/examples.md](references/examples.md) for exponential-backoff retry and a sliding-window throttler. ## Error Handling ### HTTP Status Codes | Code | Meaning | Action | |------|---------|--------| | 200 | Success | Process response | | 201 | Created | Entity created successfully | | 400 | Bad Request | Check request format/values | | 401 | Unauthorized | Verify API key | | 403 | Forbidden | Check permissions | | 404 | Not Found | Entity doesn't exist | | 429 | Rate Limited | Implement backoff | | 500 | Server Error | Retry with backoff | ### Error Response Format ```json { "Message": "Error description here", "ErrorCode": "SPECIFIC_ERROR_CODE" } ``` See [references/examples.md](references/examples.md) for a request wrapper that maps these statuses to actionable errors. ## CRUD Operations Atera does not use `PUT`. **Updates are a `POST` to the entity's ID URL** — the same verb as create, distinguished only by whether the URL carries an ID: ```http POST /api/v3/tickets # create POST /api/v3/tickets/54321 # update DELETE /api/v3/tickets/54321 # delete ``` Write responses return an `ActionID` alongside the entity ID rather than the full entity, so re-read the record if you need its post-write state. See [references/api.md](references/api.md) for the complete endpoint catalog and full request/response shapes. ## Performance Optimization - **Batch operations** - group related requests, with a delay between batches - **Cache reference data** - customers, contacts, and contracts change slowly - **Parallelize independent reads** - but count them against the 700/min budget See [references/examples.md](references/examples.md) for batching, caching, and parallel-fetch implementations. ## Related Skills - [Atera Tickets](../tickets/SKILL.md) - Ticket management - [Atera Agents](../agents/SKILL.md) - Agent management - [Atera Customers](../customers/SKILL.md) - Customer management - [Atera Alerts](../alerts/SKILL.md) - Alert management - [Atera Devices](../devices/SKILL.md) - Device monitors
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.