# OneCloud API Best Practices
# Token Lifecycle Management ## Access Tokens Access tokens are valid for 1 hour while refresh tokens are valid for 24 hours. Please use an access token until it has fully expired then use the refresh token to obtain a new one. ## JWT Tokens JWT tokens are recommended over access tokens and can be decrypted using the jwks file to establish when the token expires. When the token expires, you will need to obtain a new token. ## API Keys API keys can be requested that are valid for an extended time and do not require refresh tokens. This is good for machine-to-machine applications. *** # Rate Limiting ## Thresholds The OneCloud platform enforces rate limiting at the network level. Exceeding these limits will result in your IP being temporarily blocked with an **HTTP 403** response for **all** http requests — not just the offending endpoint. These thresholds vary by server configuration. There is no warning before a block is applied — the block takes effect immediately. ## Backoff Strategy If you receive a 403 or 429 response, stop making requests and wait before retrying. Use exponential backoff (e.g., 1s, 2s, 4s, 8s) rather than retrying immediately, as immediate retries will extend the block duration. *** # Request Requirements ## Allowed HTTP Methods Only the following HTTP methods are accepted: `GET` `HEAD` `POST` `OPTIONS` `PUT` `PATCH` `DELETE` Requests using other methods (e.g., TRACE, CONNECT) will be blocked. ## Allowed Content Types Requests must use one of the following content types: * `application/json` (recommended) * `application/x-www-form-urlencoded` * `multipart/form-data` * `text/xml` * `application/xml` Requests with unsupported content types will be rejected. ## Request Body Size The maximum request body size is **25 MB** (26,214,400 bytes). Requests exceeding this limit will receive an **HTTP 400** response. ## Request Body Formatting Request bodies must be well-formed. Malformed JSON or XML payloads will be rejected with an **HTTP 400** response. Multipart form boundaries must also be strictly valid. *** # Data Retrieval ## Pagination Always paginate list endpoints. Never attempt to retrieve an entire dataset in a single request. Use `limit` and `offset` parameters to fetch data in bounded pages (e.g., 50-200 records per request). ``` GET /ns-api/v2/resource?limit=100&offset=0 GET /ns-api/v2/resource?limit=100&offset=100 ``` ## Avoid Unbounded Loops Do not use forEach or similar loop patterns that fire many parallel API requests. This will quickly exceed rate limits and result in your IP being blocked. ```javascript // BAD - fires all requests at once, will trigger rate limiting (HTTP 403) items.forEach(item => fetch(`/ns-api/v2/resource/${item.id}`)); ``` Instead: * **Use list endpoints with filters** to retrieve multiple records in a single request rather than fetching them individually. * **Serialize requests** if you must loop — process one at a time with a delay between each. * **Use server-side filtering** to reduce the dataset at the source. ```javascript // GOOD - single request with server-side filtering const response = await fetch('/ns-api/v2/resource?filter=domain+eq+example.com&limit=100&offset=0'); ``` ```javascript // ACCEPTABLE - sequential requests with delay for (const item of items) { await fetch(`/ns-api/v2/resource/${item.id}`); await new Promise(resolve => setTimeout(resolve, 100)); // 100ms delay } ``` ## CDR and Stats Retrieval Call Detail Records and statistics endpoints can return very large datasets. Pulling unbounded CDR or stats queries is one of the most common causes of rate limiting, timeouts, and degraded platform performance. ### Always Constrain Your Date Range Never query CDRs or stats without a date range. Use the narrowest window that meets your needs. ``` // BAD - no date range, attempts to pull all historical CDRs GET /ns-api/v2/cdrs?domain=example.com // GOOD - constrained to a single day GET /ns-api/v2/cdrs?domain=example.com&time_start=ge(2026-04-01T00:00:00)&time_start=le(2026-04-01T23:59:59) ``` **Recommended maximums:** * CDR queries: **24 hours** per request * Stats/analytics queries: **7 days** per request If you need a larger window, break it into multiple smaller requests processed sequentially. ### Paginate CDR Results CDR endpoints can return thousands of records even for a single day. Always use `start` and `limit` to paginate results. ``` GET /ns-api/v2/cdrs?domain=example.com&time_start=ge(2026-04-01T00:00:00)&time_start=le(2026-04-01T23:59:59)&start=1&limit=200 ``` ### Do Not Loop CDRs Per User A common anti-pattern is looping through every user or extension to pull individual CDRs. This generates hundreds or thousands of API calls when a single domain-level query with filters would return the same data. ```javascript // BAD - one API call per user, will trigger rate limiting users.forEach(user => fetch(`/ns-api/v2/cdrs?user=${user.id}&limit=1000`)); // GOOD - single query filtered by domain, paginated GET /ns-api/v2/cdrs?domain=example.com&time_start=ge(2026-04-01T00:00:00)&time_start=le(2026-04-01T23:59:59)&start=1&limit=200 ``` ### Do Not Poll CDRs for Real-Time Data CDRs are post-call records. If you need real-time call activity, use **WebSockets** or **Event Subscriptions** instead of repeatedly polling the CDR endpoint. Polling CDRs every few seconds will result in connection termination. ### Stats Aggregation When pulling statistics, use the highest level of aggregation that meets your needs. Requesting per-extension stats across an entire reseller territory when you only need domain-level totals wastes resources and may time out. * Query at the **domain** level, not the user level, when possible. * Use date-bounded requests — avoid open-ended stat pulls. * Cache results client-side rather than re-fetching the same data repeatedly. ## Polling We do not allow excessive polling of the OneCloud APIs. If we detect excessive amounts of polling, we will terminate any connections without notice. You may receive a 429 or 403 from your IP when this happens. ## WebSockets We recommend the use of WebSocket connections for real-time data retrieval inside a client application. Socket event listeners will need to be configured on the client application side to respond to updates. This is recommended for always-on client applications. ## Subscriptions We recommend the use of subscriptions when using the APIs for server-to-server communication. Subscriptions will require a callback URL where subscription events will be posted to. *** # Error Reference | HTTP Status | Cause | Action | | ----------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | **400** | Malformed JSON/XML, oversized request body, invalid multipart boundary | Fix the request format or reduce payload size | | **403** | Rate limit exceeded or WAF block — your IP is temporarily blocked for all requests | Stop all requests, wait for the block to expire, then retry with backoff | | **429** | Excessive polling detected at the application level | Reduce request frequency, switch to WebSockets or subscriptions |