Overview
ION applies fair-use guardrails to the/graphql endpoint so one caller’s heavy queries can’t degrade the API for everyone. To make guardrails discoverable rather than surprising, responses that touch a guardrail carry a limits block inside GraphQL extensions:
violations: a list of guardrails your request bumped against. Only present when non-empty. A clean request omits the block entirely.
Static caps (page size, depth, aliases, tokens, root fields) carry
actual and limit numbers as shown. Rate-limit entries carry only the rule, retryAfter when applicable, and a message. The underlying rate budget is plan-dependent and intentionally not published in responses; follow the guidance in message rather than keying off a threshold.When the block appears
Thelimits block is part of the response extensions, alongside anything else ION reports there. Treat it as optional and additive: parse it if present, ignore it if absent. Your existing data / errors handling does not change.
A guardrail surfaces one of two ways, depending on where ION is in rolling a limit out to your org:
Advisory is your window to adapt a query before it starts getting rejected. Treat any
violations entry as “fix this and you’ll be fine when enforcement turns on.”
A successful response with no violations carries no
limits block at all. If you see extensions.limits, there’s something to address.The violations array
Each entry is an object identified by its rule. Every entry carries a human-readable message; the other fields depend on the rule family.
Structural (query shape)
Static caps on the shape of the query document: page size, nesting depth, aliases, document size, and number of top-level fields.actual and limit are always present on structural entries. field is included where a specific field is implicated (for example, pagination or depth) to point you at the offending part of the query.
Rate limit
A per-tenant token bucket meters sustained throughput. Because it’s a throughput signal, this entry carries the retry hint you need to back off:
Back off for
retryAfter seconds, then resume. Spacing requests out helps you stay under the sustained rate.
A
rate_limit entry without retryAfter is a permanent block: { "rule": "rate_limit", "message": "Access blocked. Contact support if you believe this is in error." }. Retrying doesn’t succeed until an operator lifts the block. Surface the message to the user and contact FirstResonance support, and don’t build a retry loop around it.What enforcement looks like
When a guardrail is enforced rather than advisory, the same condition comes back as a GraphQL error carrying a machine-readablecode, and the request is rejected. Key off errors[].extensions.code, not the message text:
Full payload shapes and remediation live in Error Codes. The field vocabulary matches the advisory
violations entries, so one parser can handle both paths.
Recommended client handling
For any integration, and especially unattended or agentic workflows that generate queries dynamically:- Check
extensions.limits.violationson every response. Nolimitsblock means everything is clean; if the block is present, treat each entry as a to-do before enforcement flips on. - On a transient
rate_limit(or HTTP 429), honorretryAfterwith backoff and jitter. Don’t hot-loop. - On a
rate_limitwithoutretryAfter(or theBLOCKEDerror code), stop retrying. This is a permanent block that only lifts when an operator changes the configuration. Surface the message and contact support. - On structural violations, adapt the query. Use smaller pages, fewer fields, paginate, or split the operation. Retrying the same shape won’t help.
- Don’t hard-code specific limit values. Structural
actualandlimitnumbers are stable but plan-dependent; read them from the response so your client stays correct as plans evolve.
Related
- Error Codes: enforcement payloads (
QUERY_COMPLEXITY_EXCEEDED,RATE_LIMITED,BLOCKED) and HTTP status reference. - Pagination: cursor paging to keep page sizes down.
- Build a Production Integration: retry, backoff, and resilience patterns for unattended clients.