Error codes
Every error uses one envelope with a stable machine-readable code. Branch on error.code, not the mutable message or HTTP status alone.
{
"error": {
"code": "validation_failed",
"message": "Request validation failed.",
"request_id": "req_01HQ...",
"details": [
{
"field": "territories",
"issue": "zod_invalid_format",
"message": "The value has an invalid format."
}
]
}
}request_id echoes your X-NU-Request-Id, or a server-generated value. Include it in support requests. details is present for validation errors.
Code reference
| Code | HTTP | Meaning | Typical action |
|---|---|---|---|
invalid_api_key | 401 | Key missing, malformed, unknown, or expired | Send a valid Authorization: Bearer key for the correct environment |
api_key_revoked | 401 | Key has been revoked | Replace it with an active key (04) |
invalid_approval_token | 401 | Approval token is invalid, expired, or already used for bootstrap | Request a new approval token and bootstrap it once (04) |
invalid_application_token | 401 | Application reference or status token is wrong or expired | Use the one-time status credentials from the initial application response |
missing_scope | 403 | Key lacks the required scope | Grant the scope; see the scope table (03) |
production_key_required | 403 | Sandbox key called a Production-only endpoint | Retry the settlement request with an nsp_live_ key |
organization_not_approved | 403 | Organization is not approved yet | Wait for approval or complete onboarding (02) |
resource_not_found | 404 | Resource does not exist or is not visible to your organization | Check the ID and your organization’s access |
validation_failed | 422 | Request body or parameter validation failed | Fix the fields listed in details |
rate_limit_exceeded | 429 | Per-key rate limit reached | Back off using Retry-After (12) |
license_not_active | 403 | No ACTIVE agreement authorizes this playback | Activate the agreement or enable its Production API (06) |
territory_not_allowed | 403 | Production country missing, or country, origin, or IP is not allowed by the agreement or key | Send an allowed Production country; include an allowed origin when configured and check allowed_ips |
episode_not_licensed | 403 | Episode is not ready, lacks a ready video asset, or is outside the licensed asset set | License the ready video asset or use an eligible ready episode |
duplicate_event_id | 409 | event_id was already accepted; idempotent no-op | Treat as success; do not retry with a different ID |
invalid_playback_session | 400 | Unknown or invalid playback session | Use the playback_session_id returned by the Playback API |
playback_concurrency_limit | 429 | Too many active sessions for this viewer and agreement or title | Revoke an existing session or let it complete or expire before issuing another |
settlement_not_disputable | 409 | Settlement is not in a disputable state | Dispute only while the state permits it (09) |
conflict | 409 | Resource already exists or a concurrent or in-progress request holds the operation | Retry the idempotent request or reconcile the existing resource |
service_unavailable | 503 | The required service is temporarily unavailable. | Retry idempotent calls with exponential backoff. |
internal_error | 500 | Unexpected server error | Retry with backoff; if it persists, contact support with request_id |
Handling guidance
- 401 — Fix authentication; do not retry blindly.
- 403 — Authorization issue involving scope, organization, or rights. Retrying is not useful until the underlying permission changes.
- 404 — Check the ID and organization visibility.
- 422 — Inspect
details[]and correct the request. - 409 — Depends on the code:
duplicate_event_idmeans the event was already accepted and should be treated as success;settlement_not_disputablemeans the action is not currently allowed;conflictmeans a resource exists or a concurrent request is in progress. Retry the idempotent call or reconcile the existing resource as appropriate. - 429 — Honor
Retry-After; see Rate limits. - 5xx — Retry idempotent calls with exponential backoff.
Database constraint mapping
Known database errors map to clean 4xx responses instead of a generic 500, including read-then-write races against concurrently deleted rows:
| Database condition | HTTP | error.code |
|---|---|---|
| Row not found during write (P2025) | 404 | resource_not_found |
| Unique constraint violation (P2002) | 409 | conflict |
| Foreign-key constraint violation (P2003) | 422 | validation_failed |