Rate limits & usage
How Zenode meters usage for billing and throttles REST requests per minute.
Both the REST and GraphQL APIs share the same API key, billing balance, and usage ledger. This page covers how work is counted for billing across both APIs, and how the REST API throttles requests per minute.
Per-minute rate limits (REST)
The REST API (/v1) enforces a per-API-key sliding window: 60 HTTP requests per 60 seconds by default. Each authenticated /v1 response carries standard rate-limit headers:
1X-RateLimit-Limit: 602X-RateLimit-Remaining: 573X-RateLimit-Reset: 1717000000| Header | Meaning |
|---|---|
X-RateLimit-Limit | Max requests allowed in the window |
X-RateLimit-Remaining | Requests remaining (0 on 429) |
X-RateLimit-Reset | Unix epoch seconds when the oldest counted request ages out of the window |
Retry-After | Seconds to wait before retrying (429 only) |
When you exceed the per-minute limit you get 429 with error.type: rate_limit_exceeded and a Retry-After header:
1{2 "error": {3 "type": "rate_limit_exceeded",4 "message": "Rate limit exceeded. Try again later.",5 "request_id": "req_8f3a..."6 }7}See the full REST error envelope. Enforcement runs before API key validation, so repeated requests with invalid keys still count toward your limit. Unauthenticated routes such as /v1/health are not throttled.
One HTTP request counts as one toward this limit — a 250-line batch is still a single request for rate limiting (billing is different; see below).
Monthly anti-abuse request cap (REST)
Separately from the per-minute throttle, REST also enforces a monthly cap on the number of API calls (anti-abuse). When exhausted, you get 429 with error.type: rate_limit_exceeded and message "Monthly API request limit reached."
Usage is metered per unit of work
Usage is counted per unit of work, not per HTTP request. REST and GraphQL draw from the same credits ledger.
REST has two paid classes plus free endpoints for matching, catalog search, catalog metadata, job management, and account reads. See REST usage billing for the full endpoint table.
REST — paid classes
| Class | One unit is… | Endpoints |
|---|---|---|
| Part records | 1 full part record fetched | GET /v1/parts/{manufacturer}/{mpn} |
| AI tokens | LLM tokens on the job (usage.total_tokens) | POST /v1/parts/discover, POST /v1/parts/{manufacturer}/{mpn}/deep-dive |
Batching is an ergonomic convenience, not a discount: a 250-line batch counts as 250 match requests.
For part-data endpoints the unit is the part record, so the allowance is effectively a cap on data
returned. The per-minute rate limit counts HTTP requests, not batch lines — one batch request is
one toward the 60/min window. X-RateLimit-* headers on any /v1 response reflect your remaining
requests in the current sliding window.
REST — free endpoints
These endpoints do not consume part-record or AI-token allowance (abuse-tracked only):
- Matching & search —
POST /v1/parts/match,POST /v1/parts/match/batch,POST /v1/parts/search,POST /v1/parts/search/facets(return summaries / metadata) - Taxonomy & metadata —
POST /v1/manufacturers/match,GET /v1/manufacturers/{manufacturer},POST /v1/categories/match,GET /v1/categories,GET /v1/categories/{slug} - Job management — poll, stream, list, and cancel AI jobs (billing happens when you create the job)
- Account —
GET /v1/usage
GraphQL
| Query | Billing |
|---|---|
supSearchMpn, supSearch, supMultiMatch, supParts | Paid — one unit per part returned (part_match) |
supManufacturers, supCategories | Free — abuse-tracked only |
Paid GraphQL queries require an active subscription with remaining monthly API units. If the
requested result count exceeds your remaining quota, the query is capped to what you have left
and a warning is included in the response (warnings on search results, errorString on individual
supMultiMatch lines). See Usage billing for the full query table.
AI calls bill by tokens, so every AI job reports a usage object —
{ input_tokens, output_tokens, total_tokens }. For deep dive, the job's usage is the exact
total of all tokens used to research the request (across every deliverable); it is not broken
out per deliverable.
Check your usage
Read your running total in each class for the current billing period with
GET /v1/usage. The per-minute limits are live on the X-RateLimit-*
headers above; /v1/usage is the per-period view across all three REST classes. You can also
monitor balance and top up from your zenode.ai account.
When quotas are exhausted
| Condition | REST | GraphQL |
|---|---|---|
| Monthly usage quota exhausted | 402 — usage_limit_exceeded | 402 — extensions.code: usage_limit_exceeded |
| Paid endpoints without subscription | 403 | 403 — extensions.code: subscription_required |
| Per-minute throttle exceeded | 429 — rate_limit_exceeded ("Rate limit exceeded. Try again later.") | 429 — extensions.code: rate_limit_exceeded |
REST may also return 429 rate_limit_exceeded with "Monthly API request limit reached." when the monthly anti-abuse request cap is hit.
See REST errors and GraphQL errors for response shapes.
Next
- Usage billing — which REST endpoints cost what
- Usage endpoint — current-period consumption per class
- Async AI jobs — where AI
usageis reported - Authentication — API keys and account setup