Rate limits and quotas
API usage is bounded by your plan. Two limits apply, both set by the tier on your partner account (and, for a sub-account key, the sub-account's tier as well, whichever is lower):
- Requests per minute: a short-term ceiling on how fast a single key can call the API.
- Daily request quota: a longer-term cap on total calls per day.
Your exact numbers depend on your plan. Contact your account manager if you need higher limits.
When you hit a limit
A request that exceeds the per-minute rate receives:
HTTP 429 Too Many Requests
Retry-After: 30
{ "error": { "code": "rate_limited", "message": "API rate limit exceeded." } }
Wait for the number of seconds in the Retry-After header before trying again. Responses also carry X-RateLimit-Limit and X-RateLimit-Remaining headers so a well-behaved client can slow down before it hits the wall.
Back off, do not hammer. When you receive a 429, pause and retry after Retry-After seconds. Retrying immediately in a tight loop just keeps you rate-limited.
Poll efficiently with conditional requests
The fastest way to stay within quota is to not ask for data you already have. The latest-value endpoint supports conditional requests:
- Call
GET /devices/{id}/latest. Read theETagheader from the response and store it. - On your next call, send that value back as
If-None-Match. - If nothing has changed, ioX-Pulse replies
304 Not Modifiedwith an empty body.
# First call: capture the ETag
curl -D - -H "Authorization: Bearer $KEY" \
https://portal.example.com/api/v1/devices/0011223344556677/latest
# ... ETag: "e2cb84...d40"
# Next call: revalidate cheaply
curl -H "Authorization: Bearer $KEY" \
-H 'If-None-Match: "e2cb84...d40"' \
https://portal.example.com/api/v1/devices/0011223344556677/latest
# -> HTTP 304 Not Modified
A 304 is small and fast. It still counts as a request, so it does not let you poll infinitely, but it makes a polling loop far lighter than re-fetching the full body every time.
The better answer: do not poll
Conditional requests make polling cheap, but the best pattern for real-time and latest-value data is to not poll at all. Webhook delivery, where ioX-Pulse pushes each event to your endpoint as it arrives, is the recommended approach for those use cases. See the overview for the push-versus-pull guidance.
Conditional requests keep a polled latest value cheap when you cannot use a webhook. Reserve the pull API itself for history, exports, and ad-hoc reads, which is what it is built for.