Error codes
Every /api/v1 error is returned in the same format, regardless of the endpoint or the cause.
Error format
{
"error": {
"code": "missing_scope",
"message": "The API key does not have the scope required by this endpoint.",
"hint": "Request the employees.read scope for this key.",
"docs_url": "https://smengo.com/api-docs/reference/errors#missing_scope",
"request_id": "8f14e45f-9e05-4f1a-8a3e-3d2b1c0f9b1b"
}
}
code— a machine-readable code from the catalog below; branch your integration's logic on it.message— a human-readable description, in English.hint— optional: what to do to fix the problem (for example, which scope to request).docs_url— a direct link to this code's description on this page.request_id— the same uuid as the response'sX-Request-Idheader. Include it when contacting support — it's how a specific request is found in the logs; without it, troubleshooting takes longer.
The HTTP status of the response matches the code (see the table at the end of the page). You can branch on either the status or error.code — but code is more reliable, since it uniquely identifies the cause, while a single HTTP status (for example, 403) covers two different codes.
Code catalog
unauthorized
HTTP status: 401.
The Authorization header is missing, malformed, the key is unknown to the system, or it was revoked. All four causes intentionally return the same response — this keeps the API from letting someone brute-force whether a particular key exists at all.
How to fix it: check that the header is sent as Authorization: Bearer smg_live_... and that the key is current. If the key is definitely correct, contact your organization owner — it may have been revoked.
missing_scope
HTTP status: 403.
The key is valid, but it doesn't have the scope this endpoint requires. Which scope is needed is in the response's hint and in Scopes & permissions.
How to fix it: ask the organization owner to issue a new key with the required scope, or reissue the current one with an expanded set.
subscription_inactive
HTTP status: 403.
The organization that owns the key has an inactive subscription (the trial ended and there's no active subscription). The API is disabled along with the rest of the paid functionality — the same gate as in the Smengo app.
How to fix it: renew the subscription in the Smengo app (Settings → Billing). Once the subscription is active again, the key starts working again without reissuing it.
not_found
HTTP status: 404.
The specific resource requested doesn't exist — or it exists but belongs to another organization (tenant isolation intentionally doesn't distinguish between the two, to avoid leaking other organizations' identifiers).
How to fix it: check the id in the request path. Note: for list filters (department_id, employee_id), an unrecognized id does not return 404 — it just returns an empty list, see Conventions → Filters.
validation_error
HTTP status: 400.
The request parameters failed validation: an unknown or unexpected parameter, from later than to, a date range longer than 366 days, from/to on a resource with no time dimension, and so on. The reason is in hint.
How to fix it: read hint and adjust the request parameters per the Conventions.
invalid_cursor
HTTP status: 400.
The cursor value is malformed or belongs to a different dataset — for example, a cursor obtained with one set of filters was passed into a request with different filters.
How to fix it: don't construct a cursor by hand — use only meta.next_cursor from the previous response of the same request. If the error persists with a "fresh" cursor, restart pagination without cursor.
rate_limited
HTTP status: 429.
The key's requests-per-minute limit was exceeded — rate_limit_per_min (default 60, configurable per key). The window is a sliding window (Cloudflare-style), not a fixed one: a sharp burst right at the minute boundary can't be used to double the effective limit. The response includes a Retry-After header — how many seconds to wait before retrying — and, like every API response, the X-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Reset headers; see Conventions → Rate limiting for details.
How to fix it: reduce your request rate, or wait for the window given in Retry-After. If the limit is consistently too low for your use case, contact Smengo support to raise the key's limit (the limit is configured per key, not per organization).
internal_error
HTTP status: 500.
An unexpected error on Smengo's side. These errors are logged and investigated by the team — there's no need to work around them on your end.
How to fix it: retry the request later. If the error persists, contact Smengo support and include the request_id from the response.
Status table
| Code | HTTP status |
|---|---|
unauthorized |
401 |
missing_scope |
403 |
subscription_inactive |
403 |
not_found |
404 |
validation_error |
400 |
invalid_cursor |
400 |
rate_limited |
429 |
internal_error |
500 |
The catalog is exhaustive for v1 — there are no error codes beyond the ones listed.
What's next
- Conventions — response format, pagination, filters.
- Scopes & permissions — which permission is required for each scope.