Errors
The error envelope every v1 endpoint uses, plus every error code you can actually get back.
Every error response is JSON, always shaped { "error": "<message>" },
occasionally with one extra field for a specific error:
{ "error": "A human-readable message" }
Authentication (401 / 403)
| Status | When | Message |
|---|---|---|
| 401 | Missing or malformed Authorization header | Missing or malformed Authorization header |
| 401 | Key doesn't start with jot_live_ | Malformed API key |
| 401 | Key is invalid, revoked, or its org is deactivated | Invalid or revoked API key |
| 403 | Key is missing the required read/write scope | This API key doesn't have the "<scope>" scope |
Rate limiting (429)
{ "error": "Too many requests" }, with a Retry-After: <seconds>
header. See Rate limits.
Quota (422)
{ "error": "Monthly link quota exceeded", "remaining": 0 } — the one
error that carries an extra field. See
Rate limits.
Validation (400)
Invalid JSON body: { "error": "Invalid JSON body" }. A body that
doesn't match the endpoint's schema: { "error": "Invalid request body" } —
field-level detail isn't returned today, check the endpoint's
documented shape in Links or
Webhooks.
Not found (404)
A link or webhook id that doesn't exist, or belongs to a different org,
both return 404 — never 403 — so a request can't be used to confirm
another org's resource ids exist.
Usage endpoint (502)
GET /v1/usage depends on a downstream analytics query; if that query
itself fails, you get 502 with
{ "error": "Usage data is temporarily unavailable" } — distinct from
every other error on this page, since it reflects a transient backend
issue rather than anything wrong with your request. Safe to retry.
Bulk-create per-item codes
A bulk-create response's failed results
each carry a code, not a shared top-level error:
| Code | Meaning |
|---|---|
back_half_taken | The requested customBackHalf is already in use |
invalid_url | destinationUrl isn't a valid http(s) URL |
quota_exceeded | Creating this item would exceed your monthly link quota |
screening_rejected | The destination failed malicious-URL screening |
reserved_slug | The requested back-half collides with a reserved path |
allocation_failed | An internal short-code allocation error (rare — retry the item) |
Whole-request errors for bulk-create (not per-item): 400 if the batch
exceeds your plan's per-request cap, 403 if bulk-create isn't
available on your plan.