Error response shape: { "error": "code", "message": "Human readable", "error_code": "SH_xxx", "doc_url": "https://docs.shernova.com/errors/SH_xxx", "request_id": "…" }. Validation failures use validation_error (400).
Stable error_code (SH_xxx)
| SH | Legacy code | HTTP | Meaning |
|---|---|---|---|
| SH_001 | unauthorized, invalid_credentials, invalid_refresh | 401 | Missing or invalid auth |
| SH_002 | not_found | 404 | Resource not found |
| SH_003 | invalid_state | 400 | Session not in valid state |
| SH_004 | verification_rate_limited, concurrent_limit_exceeded | 429 | Rate or concurrency limit |
| SH_005 | invalid_phone | 400 | Phone validation failed |
| SH_006 | gateway_unavailable | 503 | No online gateway (legacy - session creation now queues instead, see below) |
| SH_007 | receipt_invalid | 401 | Receipt JWT invalid or expired |
| SH_008 | signature_not_registered | 403 | Android SHA256 not registered |
| SH_009 | package_mismatch | 403 | Package name mismatch |
| SH_010 | insufficient_credits, plan_expired | 402 | Billing blocked |
| SH_013 | test_mode_only | 403 | Endpoint requires sk_test_ / pk_test_ |
| SH_014 | receipt_already_used | 409 | Receipt replay detected |
| SH_015 | idempotency_conflict | 409 | Idempotency-Key reused with different body |
Verification creation never fails with SH_006: when no gateway line is free the API answers 201 with "status": "queued", "gateway_phone_number": null and queue_reason (none_online | country_unavailable | all_busy). Keep polling until waiting.
4xx Client Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | invalid_phone | Phone number failed normalization/validation |
| 400 | invalid_state | Session not in valid state for action (cancel) |
| 400 | invalid_range | Analytics date range invalid (0-90 days) |
| 400 | invalid_organization | Malformed X-Shernova-Organization-Id |
| 400 | invalid_invitation | Invitation expired or invalid |
| 400 | owner_protected | Cannot change/remove organization owner |
| 400 | invalid_request | Invalid billing request (e.g. non-positive credits) |
| 400 | invalid_webhook_url | Webhook URL malformed |
| 400 | webhook_https_required | Webhook URL must use HTTPS |
| 400 | webhook_private_address | Webhook URL resolves to a private/reserved address |
| 400 | validation_error | Request body failed Zod schema validation |
| 401 | unauthorized | Missing or invalid auth token/key |
| 401 | invalid_credentials | Wrong email/password on login |
| 401 | invalid_refresh | Refresh token invalid or already used |
| 402 | plan_expired | Application plan has expired |
| 402 | insufficient_credits | No available credits for verification |
| 403 | account_inactive | Developer account disabled |
| 403 | forbidden | Insufficient permission for resource |
| 403 | app_disabled | Application is disabled |
| 403 | app_frozen | Application billing frozen by admin |
| 403 | package_mismatch | SDK package_name doesn't match registered app |
| 403 | app_limit_reached | Organization reached the maximum applications allowed by its package |
| 403 | signature_not_registered | Android SHA256 not registered |
| 403 | test_mode_only | Live key used where test keys are required (SH_013) |
| 404 | not_found | Resource not found |
| 404 | organization_not_found | No active organization for user |
| 409 | email_exists | Email already registered |
| 409 | member_exists | User already organization member |
| 409 | gateway_number_mismatch | Gateway heartbeat number mismatch |
| 409 | last_admin | Cannot demote last platform admin |
| 409 | self_protected | Cannot remove own admin access |
| 409 | receipt_already_used | Receipt JWT already verified (replay) |
| 409 | idempotency_conflict | Idempotency-Key conflict |
| 401 | receipt_invalid | Receipt JWT malformed or expired |
| 422 | webhook_redirect | Webhook URL redirected (not allowed) |
| 422 | webhook_rejected | Webhook endpoint rejected request |
| 422 | webhook_dns_failed | Webhook hostname DNS lookup failed |
| 422 | webhook_connection_failed | Could not connect to webhook URL |
| 429 | concurrent_limit_exceeded | Too many waiting sessions for app |
5xx Server Errors
| HTTP | Code | Description |
|---|---|---|
| 502 | email_delivery_failed | Invitation email could not be sent |
| 503 | gateway_unavailable | No online gateway (legacy - POST /v1/verifications returns 201 `queued` instead) |
| 503 | email_not_configured | Email service not configured |
| 504 | webhook_timeout | Webhook test timed out (10s) |
| 500 | internal_error | Unhandled server error |
Include request_id when contacting support - it appears in API logs.
