Error reference
Every error code the API can return, what triggers it, and how to recover.
account.suspendedReturned on any state-mutating request when the workspace status is suspended. No operations are permitted until an admin reinstates the workspace.accounts.admin_requiredReturned when an endpoint requires at least the admin workspace role but the authenticated member has a lesser role such as member or viewer.accounts.last_ownerReturned when a demotion or removal would eliminate the last workspace owner. Promote another member to owner first before proceeding.accounts.remove_deniedReturned when a removal is attempted without sufficient role authority. Self-removal is allowed for any non-sole-owner. Removing others requires owner or admin role.accounts.role_change_deniedReturned when a role change is attempted by someone who is not an owner or admin, or when a non-owner tries to mint another owner.accounts.write_deniedReturned when a viewer or read-only member attempts a state-mutating request. Applies across numbers, wallet, webhooks, API keys, storage, and memberships.api_key.already_revokedReturned when a revoke request targets a key that is already in revoked state. No action is taken; the key remains revoked.api_key.expiredReturned when the API key JWT has passed its expiry timestamp. Revoke the expired key and mint a new one with an appropriate expiry.api_key.invalidReturned when the API key JWT is structurally invalid or fails cryptographic verification. The key cannot be used; mint a new one if the original is lost.api_key.name_requiredReturned when a key creation request omits the label field. Provide a non-empty label to identify the key and resubmit.api_key.not_foundReturned when an API key management operation targets an ID that does not exist or belongs to a different workspace. Verify the key ID.api_key.revokedReturned when the API key was explicitly revoked via the key management UI or API. The key cannot be used regardless of its expiry. Mint a new key.api_key.scope_deniedReturned when the API key is valid but lacks the specific scope the route requires. Mint a new key with the needed scope or use a broader-scope key.api_key.scope_invalidReturned at key mint time when a scope string is not recognized by the platform. Use only scopes from the documented scope list.audit.invalid_action_kindReturned when an audit log filter or query uses an action_kind value that is not recognized. Use only values from the audit types allowlist.auth.admin_requiredReturned on admin-only routes when the request lacks the required admin session marker. End-user sessions cannot access admin routes.auth.cannot_unlink_only_authReturned when unlinking Google OAuth would leave the account with no sign-in method. Add another authentication method before unlinking.auth.email_takenReturned when a signup is attempted with an email that is already registered. Direct the user to sign in or use a different email address.auth.google_exchange_failedReturned when the server-side call to Google's token endpoint fails. This is a transient upstream error; retry the sign-in flow after a short delay.auth.google_not_configuredReturned when Google sign-in is attempted but the OAuth client is not set up on this deployment. Use magic-link sign-in instead.auth.google_state_mismatchReturned when the Google OAuth callback state cookie is absent or tampered with. This is a CSRF protection check; restart the sign-in flow to get a fresh state.auth.invite_email_mismatchReturned when accepting an invite with a session whose email differs from the invite target. Sign in with the invited email address to accept.auth.no_workspaceReturned when a signed-in user attempts to access a workspace route but has not yet completed onboarding. Redirect to the workspace creation flow.auth.session_invalidReturned on any authenticated route when no valid session is present. The client should redirect to the sign-in page to obtain a fresh session.auth.token_expiredReturned when a magic-link token is presented after its 15-minute validity window. The user must request a fresh link to sign in.auth.token_invalidReturned when a magic-link token does not pass HMAC verification or has a malformed structure. Do not retry; request a new link.auth.token_usedReturned when a single-use magic-link token is presented after it was already redeemed. The user must request a new link to sign in again.auth.workspace_forbiddenReturned when the authenticated identity attempts to access a workspace it is not a member of. Ensure the correct workspace ID is being used.calls.events_failedReturned when GET /v1/calls/{id}/events encounters an internal failure. Retryable with exponential backoff per the 5xx policy.calls.get_failedReturned when GET /v1/calls/{id} encounters an internal failure. Retryable with exponential backoff per the 5xx policy.calls.list_failedReturned when GET /v1/calls encounters an internal failure. Retryable with exponential backoff per the 5xx policy.calls.not_foundReturned when a call lookup, events, or recording request targets an ID that does not exist or is cross-workspace. Verify the call ID and workspace context.calls.recording_expiredReturned when a recording that existed has since been deleted by the retention sweep. Upgrade the storage tier or archive recordings before retention expires.calls.recording_failedReturned when generating a presigned download URL or fetching recording metadata fails internally. Retryable with exponential backoff per the 5xx policy.calls.recording_not_foundReturned when a recording is requested for a call that was not recorded or whose recording was never written. Check that recording was enabled for the call.calls.stats_failedReturned when GET /v1/calls/stats encounters an internal failure. Stats are driven off the call_stats_daily rollup. Retryable per the 5xx policy.currency.unsupportedReturned when a request specifies a currency not supported by the platform. Use one of KES, UGX, TZS, RWF, ZAR, GHS, or NGN.idempotency.conflictReturned when the same Idempotency-Key is sent with a different body than the original request. Resend the original body or use a new key.internal_errorReturned when an unhandled internal error occurs and no more specific code applies. Retryable with exponential backoff per the 5xx policy.invitations.not_foundReturned when an invite accept or lookup targets an invitation ID that does not exist or was previously revoked by a workspace owner or admin.invite_requires_loginReturned by POST /v1/auth/invite/accept when no session exists. The server stashes the invite as a handoff cookie so it can be completed after sign-in.method_not_allowedReturned when the request method (GET, POST, etc.) is not supported by the endpoint at this path. Check the API reference for the correct method.mpesa.unavailableReturned when M-Pesa top-up is attempted but the provider is not configured or the wallet is not KES-denominated. M-Pesa only supports KES wallets.not_foundReturned when a resource cannot be found and no subsystem-specific not-found code exists for the endpoint. Prefer module-specific codes where available.numbers.already_claimedReturned when a number claim is attempted on an inventory row that is already assigned. Choose a different available number from inventory.numbers.invalid_routing_urlReturned by PUT /v1/numbers/{id}/routing when the URL does not parse, uses a non-http/https scheme, or has an empty host segment.numbers.not_assignedReturned when a release or admin reassign targets a number that has no active workspace assignment. Verify the number ID and its current status.numbers.not_foundReturned when a number operation targets an ID that does not exist or belongs to a different workspace. Verify the number ID and workspace context.numbers.price_missingReturned when a number claim is attempted but the series has no price configured for the workspace's wallet currency. Contact support to resolve.numbers.retiredReturned when a claim targets a number that has been retired from inventory. The number cannot be assigned to any workspace in its retired state.numbers.series_invalidReturned when a series create or generate request has an end suffix not greater than start, a range exceeding 10,000, or no voice/sms/webrtc capability selected.numbers.series_not_activeReturned when inventory generation is attempted on a retired or inactive series. The series must be in active status to generate new numbers.numbers.sip_config_unavailableReturned when SIP configuration is requested but the gateway credentials are absent from the deployment environment. This is a deployment configuration issue.numbers.sip_credentials.already_revokedReturned when a rotate or revoke is attempted on a credential that is already in revoked state. No action is taken; the credential remains revoked.numbers.sip_credentials.not_foundReturned when a SIP credential lookup, rotate, or revoke targets an ID that does not exist for the given number. Verify the credential ID.numbers.sip_token_unavailableReturned when a SIP token request cannot be completed because the signing key is absent. This is a deployment configuration issue; contact support.numbers.suffix_collisionReturned when a series generation request specifies a suffix range that conflicts with numbers already in inventory. Choose a non-overlapping range.numbers.wallet_unavailableReturned when a number claim cannot proceed because the wallet service dependency is absent. This is a deployment configuration issue; contact support.paystack.unavailableReturned when a top-up request specifies a provider that is not enabled for this deployment or currency. Use M-Pesa STK push as the supported top-up method for KES wallets.pbx.body_read_failedReturned when body reading fails on POST /v1/webhooks/pbx/events due to size limits or stream errors. This is a transport-level issue on the gateway-go side.pbx.ingest_failedReturned when the PBX ingest endpoint cannot persist the event to the database. Retryable with backoff per the 5xx policy.pbx.payload_decode_failedReturned when the body of POST /v1/webhooks/pbx/events is not valid JSON or fails schema decoding. Fix the gateway-go serialization.pbx.resolve_failedReturned when the workspace lookup from tenant_pbx_id fails internally. Distinct from pbx.unknown_workspace; this is a database error, not a mapping miss.pbx.unknown_workspaceReturned when a PBX ingest event carries a tenant_pbx_id that cannot be matched to any workspace in the platform. Check the tenant mapping.provider.has_active_seriesReturned when a provider delete or retire is attempted while active series exist. Retire all associated series before removing the provider.provider.invalid_credentialsReturned when a provider create or update request has SIP credentials that fail validation. Fix the hostname, port, or password and resubmit.storage.tier_invalidReturned when PUT /v1/storage/tier specifies a tier_gb not in the allowed set of 5, 10, 25, 50, 100, or 250. Use an exact allowed value.storage.tier_switch_failedReturned when the tier change cannot be persisted internally. The tier may not have changed; verify before retrying per the 5xx backoff policy.topup.not_foundReturned when a top-up status or detail request references an ID that is absent or belongs to a different workspace. Verify the ID and workspace context.validation.bad_requestReturned when a request fails basic shape validation before reaching business logic. The message field carries the specific failure detail.validation.invalid_cursorReturned when a cursor query parameter cannot be decoded or does not match the current filter. Generate a new cursor by starting pagination from the first page.wallet.adjustment_invalid_kindReturned by the admin wallet adjustment endpoint when the kind field is not one of manual_credit, manual_debit, refund, or fee_waiver.wallet.alert_subscriber_existsReturned by the single-add POST path when the email is a duplicate. Use PUT to replace the full subscriber list with idempotent semantics.wallet.alert_subscriber_invalid_emailReturned by POST/PUT /v1/wallet/alert/subscribers when an email address does not match the required pattern. Fix the address and resubmit.wallet.alert_subscriber_not_foundReturned by DELETE /v1/wallet/alert/subscribers/{email} when the address is not in the subscriber list. Case-insensitive match is applied.wallet.alert_subscribers_maxReturned when an add or replace operation would push the subscriber count above MaxAlertSubscribers (20). Remove existing subscribers first.wallet.currency_mismatchReturned when a wallet operation specifies a currency that differs from the currency the wallet was provisioned with. Each workspace wallet is single-currency.wallet.insufficient_fundsReturned when a debit or purchase would overdraw the wallet. Not retryable until the wallet is topped up with sufficient funds.wallet.invalid_amountReturned when an amount field fails validation. Debits and credits must be positive integers in minor currency units; thresholds must be non-negative.wallet.not_foundReturned when a wallet operation is attempted before the workspace wallet is provisioned. Contact support or complete the onboarding flow to provision it.wallet.topup_below_minimumReturned when a top-up request is below the configured minimum for the wallet's currency. Increase the amount to meet the minimum floor and retry.webhooks.create_failedReturned when POST /v1/webhooks encounters an internal failure during the database write. Retryable with the same Idempotency-Key and body.webhooks.delete_failedReturned when DELETE /v1/webhooks/{id} encounters an internal failure. The subscription may or may not have been deleted; verify state before retrying.webhooks.deliver.secret_unsetInternal terminal state set on a delivery row when the subscription lacks a signing secret. Call POST /v1/webhooks/{id}/rotate-secret to recover and re-queue.webhooks.delivery_not_retryableReturned when a manual retry is requested for a delivery that is already succeeded or dead_letter. Terminal deliveries cannot be re-queued.webhooks.dispatcher_unavailableReturned when a test or manual retry endpoint is called but the dispatcher worker is not configured. This is a deployment configuration issue.webhooks.event_unsupportedReturned on POST/PATCH /v1/webhooks when an events array entry is not a recognized literal, wildcard, or family. Correct the event kind and resubmit.webhooks.list_failedReturned when GET /v1/webhooks encounters an internal failure. Retryable with exponential backoff per the 5xx policy.webhooks.not_foundReturned when a subscription lookup, update, delete, or delivery query targets an ID that does not exist or is cross-workspace. Verify the subscription ID.webhooks.patch_failedReturned when PATCH /v1/webhooks/{id} encounters an internal failure during the database write. Retryable with exponential backoff per the 5xx policy.webhooks.rotate_secret_failedReturned when POST /v1/webhooks/{id}/rotate-secret encounters an internal failure. The secret may not have been updated; retry before updating your receiver.