Resources
Error codes
Complete reference of npayload API error codes and HTTP status codes
All npayload API errors follow a consistent format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of what went wrong.",
"details": {}
}
}
| Status | Meaning |
|---|
200 | Success |
201 | Created |
204 | No content (successful deletion) |
400 | Bad request. Invalid parameters or payload |
401 | Unauthorised. Missing or invalid credentials |
403 | Forbidden. Valid credentials but insufficient permissions |
404 | Not found. Resource does not exist |
409 | Conflict. Resource already exists or state conflict |
422 | Unprocessable entity. Validation error |
429 | Too many requests. Rate limit exceeded |
500 | Internal server error |
503 | Service unavailable. Temporary outage |
| Code | Status | Description |
|---|
AUTH_REQUIRED | 401 | No authentication credentials provided |
AUTH_INVALID | 401 | Invalid client ID or HMAC secret |
TOKEN_EXPIRED | 401 | Access token has expired; request a new one |
TOKEN_INVALID | 401 | Access token is malformed or revoked |
DPOP_INVALID | 401 | DPoP proof is invalid, expired, or does not match the request |
DPOP_NONCE_INVALID | 401 | DPoP nonce has expired; use the nonce from the response header |
SCOPE_INSUFFICIENT | 403 | Token does not have the required scope for this operation |
| Code | Status | Description |
|---|
CHANNEL_NOT_FOUND | 404 | Channel does not exist or has been archived |
CHANNEL_ALREADY_EXISTS | 409 | A channel with this name already exists in the app |
CHANNEL_ARCHIVED | 409 | Cannot modify an archived channel |
CHANNEL_PAUSED | 409 | Cannot publish to a paused channel |
| Code | Status | Description |
|---|
PAYLOAD_TOO_LARGE | 400 | Message payload exceeds 256 KB |
BATCH_TOO_LARGE | 400 | Batch contains more than 100 messages |
BATCH_PAYLOAD_TOO_LARGE | 400 | Total batch payload exceeds 10 MB |
VALIDATION_ERROR | 422 | Payload does not match the channel's event catalogue schema |
IDEMPOTENCY_CONFLICT | 409 | A message with this idempotency key already exists |
MESSAGE_NOT_FOUND | 404 | Message does not exist |
| Code | Status | Description |
|---|
SUBSCRIPTION_NOT_FOUND | 404 | Subscription does not exist |
ENDPOINT_INVALID | 400 | Webhook URL is invalid, unreachable, or uses a non-HTTPS scheme |
SUBSCRIPTION_ARCHIVED | 409 | Cannot modify an archived subscription |
CIRCUIT_OPEN | 503 | Circuit breaker is open; endpoint is temporarily unavailable |
| Code | Status | Description |
|---|
DLQ_ENTRY_NOT_FOUND | 404 | DLQ entry does not exist or has been purged |
DLQ_REPLAY_FAILED | 500 | Failed to replay the DLQ entry |
| Code | Status | Description |
|---|
RATE_LIMITED | 429 | Request rate limit exceeded; check Retry-After header |
| Code | Status | Description |
|---|
QUOTA_EXCEEDED | 403 | Organisation or app quota reached (channels, subscriptions, or messages) |
PLAN_LIMIT_REACHED | 403 | Current billing plan does not support this feature or limit |
| Code | Status | Description |
|---|
SESSION_NOT_FOUND | 404 | ASP session does not exist |
SESSION_EXPIRED | 409 | Session TTL has elapsed |
PARTICIPANT_NOT_FOUND | 404 | Agent is not a participant in this session |
INVALID_PERFORMATIVE | 400 | Unknown or invalid performative type |
COMMITMENT_NOT_FOUND | 404 | Commitment does not exist |
COMMITMENT_ALREADY_FULFILLED | 409 | Commitment has already been fulfilled |
import { NPayloadError, RateLimitError, AuthenticationError } from '@npayload/node';
try {
await npayload.messages.publish({ channel: 'orders', payload: data });
} catch (error) {
if (error instanceof RateLimitError) {
// Wait for error.retryAfter seconds, then retry
} else if (error instanceof AuthenticationError) {
// Token expired: the SDK handles refresh automatically
} else if (error instanceof NPayloadError) {
console.error(`[${error.code}] ${error.message}`);
}
}