Skip to main content
All errors share a consistent shape:
{
  "error": { "code": "not_found", "message": "Video not found" },
  "meta": { "request_id": "req_xxxxx" }
}
The error.code is a stable machine-readable string. The error.message is human-readable and may change between versions. Parse code, log message.

Error codes

CodeHTTPWhen it firesRecommended client action
unauthorized401Missing, malformed, or invalid Authorization headerCheck the header is Bearer lymo_...; re-issue the key if it’s been revoked
invalid_key_metadata401Key signature is valid but Lymo-specific metadata is missingRe-issue the key from the web app — it was created outside the normal flow
forbidden403Key lacks the required scope, or the organization is inactiveCheck your key’s scopes; contact support if the org should be active
not_found404Resource doesn’t exist, or it exists in a different organizationSee cross-tenant 404 below
bad_request400Malformed header — e.g. Idempotency-Key longer than 256 charactersFix the header and retry
validation_failed422Query parameters or request body failed schema validationRead message for the failing field path; fix and retry
invalid_webhook_url422POST /v1/webhooks destination URL isn’t on your org’s hostname allowlistSee Webhooks → Hostname allowlist
rate_limited429Too many requests for this key (when enforcement is configured — see below)Honor the Retry-After header (seconds); back off exponentially thereafter
service_unavailable503Key-verification service is temporarily unavailableRetry with backoff; escalate if it persists more than a minute
internal_error500Unexpected server errorRetry once; if it persists, report the request_id

Cross-tenant 404

Resources that belong to a different organization return 404 not_found, not 403 forbidden. This is intentional — 403 would leak the fact that an ID exists; 404 is indistinguishable from “never existed.” This applies to every resource path, not just videos. Concretely: if your key is for org A, calling GET /v1/videos/{id} with a video ID from org B returns:
{
  "error": { "code": "not_found", "message": "Video not found" },
  "meta": { "request_id": "req_xxxxx" }
}
If a resource you know exists returns 404, the most common cause is that the API key is scoped to a different organization than you expected. Check it with:
curl "$LYMO_BASE/v1/members/me" -H "Authorization: Bearer $LYMO_KEY"
The returned member’s organization is the only one this key can see.

Key self-revocation

If a key is compromised, the holder can revoke it without web UI access:
curl -X DELETE "$LYMO_BASE/v1/keys/me" -H "Authorization: Bearer $LYMO_KEY"
# → { "data": { "revoked": true }, "meta": {...} }
This endpoint requires no permission scope — any key can always revoke itself. After revocation, every subsequent request with the same key returns 401 unauthorized.

Using request_id

Every response — success or error — includes meta.request_id. When reporting issues, include it: we can trace the exact request server-side, including timing, inputs, and which backend service handled it.
{
  "error": { "code": "internal_error", "message": "An unexpected error occurred" },
  "meta": { "request_id": "req_fa29e58a3cfb4c0fbab0a75f82c4c7a3" }
}
Format is req_ followed by 32 lowercase hex characters (a UUID with dashes removed). The same ID is echoed on the X-Request-Id response header so you can grep logs end-to-end.

Rate limits

Rate-limit enforcement is per-API-key. When a limit is exceeded the response is 429 rate_limited with a Retry-After header specifying seconds to wait:
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{ "error": { "code": "rate_limited", "message": "Rate limit exceeded" }, "meta": {...} }
Rate limits are not yet enforced on all issued keys. Future versions will apply sensible defaults per scope. Design clients to always honor Retry-After rather than hard-coding intervals, so the switch to enforcement is a no-op for you.

Validation errors

validation_failed (422) is the most common error during development. The message field names the offending field path:
{
  "error": {
    "code": "validation_failed",
    "message": "limit: Number must be less than or equal to 100"
  },
  "meta": { "request_id": "req_..." }
}
Common causes:
  • limit outside 1–100 (default is 25)
  • created_after / created_before not a valid ISO 8601 timestamp
  • status filter not in the allowed enum — see the API Reference tab for per-resource status values
  • Missing required body field on POST /v1/webhooks