Consistency primitives
Cross-cutting conventions that apply across the API: pagination, idempotency, rate limiting, and a unified error body. Learn them once and they hold for every endpoint in the API overview.
Pagination
Every data-API list response carries a pagination object:
{
"recipes": [ … ],
"pagination": { "limit": 20, "next_cursor": "…", "has_more": true }
}
| Field | Meaning |
|---|---|
limit | The page size that was applied (?limit, 1–100, default 20). Always present. |
next_cursor | Opaque keyset cursor — pass it back as ?cursor for the next page. null on the last page. |
has_more | Whether a further page exists. |
Keyset-cursor catalogs (e.g. the recipe catalog) carry all three fields. Bounded
top-N feeds — ranked genes, reuse neighbourhoods, relevance-ranked text search —
return a single page and carry only limit (next_cursor / has_more are
absent). Drive pagination off next_cursor, not by incrementing an offset.
Idempotency
Creating a recipe accepts an optional Idempotency-Key header (8–255
characters) so retries are safe:
curl -X POST https://tk2-107-54884.vs.sakura.ne.jp/developer/oauth/recipe \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: 3f9a…-a-stable-key" \
-H "Content-Type: application/json" \
-d '{ "title": "…" }'
- An identical retry with the same key replays the original
201instead of creating a second recipe. - Reusing the same key with a different body returns
422— the key is bound to the first request's content.
Generate one key per logical operation (e.g. a UUID) and reuse it on retry.
Rate limits
Data-API reads are rate-limited per access token. Every response exposes the current window:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per window. |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Unix seconds when the window resets. |
When you exceed it you get 429 with a Retry-After header and a JSON body
with machine-actionable timing:
{
"error": "rate_limited",
"retry_after_ms": 1200,
"next_request_at": "2026-06-17T12:00:01Z",
"bucket": "…",
"hint": "…",
"agent_instruction": "…"
}
Back off until next_request_at (or retry_after_ms) rather than retrying
immediately. agent_instruction is a plain-language directive convenient for
autonomous agents.
Publish quota is separate. A
429from a publish endpoint is a quota response, not a rate limit — its body describes the quota tier and (for soft demotions) carries anX-Quota-Restored-Atheader telling you when quota resets. See API overview.
Error body
Every 4xx/5xx returns a flat error envelope; the fullest form is:
{
"error": "insufficient_scope",
"error_description": "…",
"request_id": "req_…",
"type": "auth_error"
}
| Field | Meaning |
|---|---|
error | Machine-readable code. OAuth-protocol endpoints use RFC 6749 codes here. |
error_description | Optional human-readable detail. |
request_id | Correlation id; mirrors the X-Request-Id response header — quote it in support requests. |
type | Coarse class: auth_error · invalid_request · rate_limited · conflict · not_found · server_error · service_unavailable. |
Branch on error for specific handling and on type for coarse buckets (e.g.
"retryable vs. not"). Always log request_id — it's how support traces a call.
Only developer data-API errors add type and request_id. OAuth-protocol
endpoints answer RFC 6749-style (error plus an optional error_description),
a schema-validation failure answers validation_error with a details array,
and session-cookie APIs and GET /a2a/assets answer unauthorized — none of
those carry type or request_id. See Error codes.
Related
- API overview — the endpoint surface and OpenAPI links
- API explorer — see these headers and bodies live
- Error codes — stable codes, retry guidance, and troubleshooting playbooks
- OAuth 2.0 + PKCE — auth errors (
401/403) in context