Every request to a data endpoint (/api/v1/..., /api/v2/...) must carry an API key in the x-api-key header. The header is the only accepted mechanism: keys in a query parameter or an Authorization: Bearer header are not read and the request is rejected with 401.System endpoints (/health, /about, /services, /sources) are public and need no key.API keys#
Keys look like sugra_ab1_ followed by a 24-character random suffix. Treat the whole string as the secret.Manage keys in the dashboard at app.sugra.ai (Developer, Keys):Create as many keys as your plan allows, see Plans and billing. All keys share the account's daily quota; each key keeps its own usage counter, so you can see which integration spends the budget. Rotate a key at any time. Rotation issues a new random suffix and invalidates the old key immediately.
Delete keys you no longer use. At least one key must remain; to replace your last key, rotate it instead of deleting.
There is no key expiry. A key stays valid until you rotate or delete it, or the account plan changes it.Error responses#
| Status | Meaning | What to do |
|---|
| 401 | Missing or invalid x-api-key | Send a current key from the dashboard |
| 403 | Not used for key errors on data endpoints | See note below |
| 429 | Daily request quota exhausted, or an upstream or our queue for it asks you to slow down | Quota: wait for the UTC midnight reset or upgrade the plan. Otherwise: retry after Retry-After, see Rate limits and errors |
401 Unauthorized#
Both a missing key and an unrecognized key return 401 with a JSON body. Its code field tells the cases apart:HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": "Unauthorized",
"detail": "Missing API key",
"code": "missing_api_key",
"reason": "The request carried no x-api-key header.",
"hint": "Send a valid x-api-key header. Keys are issued at https://sugra.systems/api.",
"plan": null
}
missing_api_key - the request carried no x-api-key header.
invalid_api_key - a header was sent but the key was not accepted: unknown, revoked, rotated away or mistyped.
unauthorized - any other authentication failure; reason carries its detail.
Branch on code, not on the wording of detail or reason. plan is always null on a 401, because an unauthenticated request has no plan. There is no separate status for "expired": if the key is rejected, it is always 401.403 Forbidden#
Data endpoints do not use 403 for authentication. A 403 from sugra.ai means the path itself is restricted (internal, non-public surfaces), not that your key is wrong. Client retry logic should treat 401 as "fix the key" and 403 as "this route is not for API keys".429 Too Many Requests#
Your account has one daily request quota, set by the plan and shared by all of its keys (see Rate limits and errors). The counter resets at UTC midnight. Over quota, requests return 429 with a JSON body and a Retry-After header giving the whole seconds until the reset:HTTP/1.1 429 Too Many Requests
Retry-After: 19722
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 2026-07-18T23:59:59Z
{"detail": "Daily limit of 50 requests reached. Current plan: free. Upgrade for a higher daily limit: https://app.sugra.ai/plans?from=api.ratelimit.upgrade"}
detail stays a single string - the shape is unchanged, only the sentence is longer. Treat it as human-readable text: the machine-readable quota state is in the headers above.Every authenticated response includes the current quota state:HTTP/1.1 200 OK
x-ratelimit-limit: 1000000
x-ratelimit-remaining: 999968
x-ratelimit-reset: 2026-07-18T23:59:59Z
X-RateLimit-Limit - your account's daily quota
X-RateLimit-Remaining - requests left today, across all your keys
X-RateLimit-Reset - the UTC timestamp when the counter resets
Header names are case-insensitive; HTTP/1.1 responses emit them lowercase.Key security#
Call the API from your server or agent backend only. Never embed a key in browser JavaScript, mobile app binaries, or public repositories: anything shipped to a client is public.
Load the key from an environment variable or secret store, not from source code.
If a key leaks, rotate it in the dashboard immediately. The old value stops working at once and your integrations only need the new suffix.
Use separate keys per application or environment, so one leak is contained by one rotation. Separate keys do not add quota: all of them draw on the same account budget.
Modified at 2026-10-03 20:17:16