Skip to content
Akedly
V1.2 REST API

Errors and troubleshooting

Look up V1.2 error codes by category, and the expiry limits that apply.

Error Reference

V1.2 errors use status, code, and message. Middleware-generated errors may also include retryable, retryAfter, cooldownSeconds, and details; the response fields depend on the endpoint and error path.

json
{
  "status": "error",
  "code": "ERROR_CODE",
  "message": "Human-readable description",
  "retryable": true,
  "retryAfter": "2026-03-25T12:01:00.000Z",
  "cooldownSeconds": 3600,
  "details": {}
}

Expiration fields

LimitValue
Challenge expiryScales with difficulty — 90s at difficulty 2–3, 120s at 4, 240s at 5, 300s at 6. The default difficulty is 3, so most pipelines get 90 seconds. Read expiresAt from the challenge response; see Challenge expiry scales with difficulty.
Captcha token expiry2 minutes
Transaction expiry3 minutes. Use data.expiresAt from the send response when deciding whether to request a new OTP.

Authentication Errors

StatusCodeCause and Solution
400MISSING_REQUIRED_FIELDSAPIKey and pipelineID are required for the challenge request; transactionReqID and otp are required for verification.
401INVALID_API_KEYAPI key is invalid or does not match any account. Verify in your dashboard.
403API_KEY_SCOPE_DENIEDThe key is limited to some pipelines and this pipeline is not one of them. Use a key whose scope covers it. Returned by /challenge, /send and the passkey auth-options call.
503API_KEY_INDEX_UNAVAILABLEThe key could not be checked right now. The response carries retryable: true: try again shortly. Returned by /challenge, /send and the passkey auth-options call.

Pipeline and Configuration Errors

StatusCodeCause and Solution
403PIPELINE_OWNERSHIP_MISMATCHThe pipeline belongs to a different account. Use a pipeline owned by the account identified by APIKey.
403INVALID_API_VERSIONThe pipeline is not configured for V1.2.
403PIPELINE_INACTIVEThe pipeline is inactive. Activate it in the pipeline editor.
403UTILITY_PIPELINE_ON_OTP_ENDPOINTThe selected pipeline is a Utilities pipeline. Use the Utilities API instead.
404PIPELINE_NOT_FOUNDThe pipelineID does not identify an existing pipeline.
500PIPELINE_NOT_LOADEDThe server could not load pipeline data for a security check. Retry the request.

Channel Choice Errors

Returned only when you pass channel. The three validation codes are lower-case, unlike the rest of this reference — that is what the API actually returns. Validation runs before the availability check, so an unrecognised channel value is reported as invalid_channel even on a pipeline where channel choice is switched off.

StatusCodeCause and Solution
400invalid_channelchannel was not one of whatsapp, telegram, sms — or you passed it without a verificationAddress.phoneNumber. Sending channel: null counts as passing it: omit the field entirely to use the pipeline's normal routing.
400channel_choice_not_enabledNot available for this account and pipeline. Covers the account entitlement, the pipeline switch, the platform-wide switch, legacy (non-granular) pricing and accounts not billed per message. Check the pipeline switch in Dashboard > Pipelines first; if that is on, ask Akedly.
400channel_not_eligibleA valid channel, but not one this pipeline sends on. The response carries eligibleChannels, in the pipeline's own configured order — offer the user those. The order reflects your pipeline configuration, not any ranking by us.
422pre_send_failureThe channel was refused before anything was sent, so nothing was spent — today this means a telegram number that is not reachable on Telegram. Offer the user another channel.
500ACTIVATION_FAILEDThe send failed for any other reason. Because you named a channel explicitly, no fallback was attempted. Retry, or send again without channel to use the pipeline's normal routing.

OTP Template Errors

Returned with HTTP 400 when the request or the pipeline default selects an OTP template that cannot be used. Nothing is sent or billed. Remedies are in the OTP templates guide.

StatusCodeCause
400TEMPLATE_UNKNOWNThe template id is malformed, not found, or not owned by the account.
400TEMPLATE_ARCHIVEDThe template was archived.
400TEMPLATE_WABA_REQUIREDThe account has no active own WABA, or its token cannot be read.
400TEMPLATE_WABA_CHANGEDThe template belongs to a previous WABA.
400TEMPLATE_NOT_APPROVEDThe OTP language has no approved variant.
400TEMPLATE_REJECTEDMeta rejected the OTP language variant.
400TEMPLATE_VARIABLE_MISSINGA required variable has no request value or stored default.
400TEMPLATE_VARIABLE_INVALIDA variable name or value is invalid, or the template object contains an unsupported key.

Challenge and Captcha Errors

StatusCodeCause and Solution
400POW_SOLUTION_MISSINGThe request omitted the PoW solution while PoW was required. Solve the current challenge and send its challengeToken and nonce.
400POW_INVALID_TOKEN, POW_INVALID_SIGNATURE, POW_PIPELINE_MISMATCH, POW_INVALID_SOLUTIONThe submitted PoW proof is invalid or bound to another pipeline. Fetch a new challenge and solve it for this pipeline.
409POW_CHALLENGE_REPLAYED, POW_DIFFICULTY_STALEThe proof was already consumed or was minted below the current difficulty. Fetch a new challenge and retry.
410POW_CHALLENGE_EXPIREDThe PoW challenge has expired. The TTL scales with difficulty (90s at the default difficulty 3, up to 300s at difficulty 6) — do not assume 5 minutes. Request a new challenge from Step 1.
500POW_VERIFICATION_FAILED, POW_DIFFICULTY_CALCULATION_FAILEDThe server could not complete a PoW operation. Retry the request.
400TURNSTILE_TOKEN_MISSINGTurnstile is enabled but no token was provided. Obtain a token before sending.
403TURNSTILE_VERIFICATION_FAILEDCloudflare rejected the Turnstile token. Obtain a fresh token and retry.
500TURNSTILE_SECRET_KEY_MISSINGThe pipeline's Turnstile secret is not configured. Contact the pipeline owner.
502TURNSTILE_API_ERRORTurnstile's API returned an error. Retry the request.
504TURNSTILE_VALIDATION_TIMEOUTTurnstile validation timed out. Retry the request.

Rate Limiting Errors

Each 429 response includes retryAfter (ISO timestamp) and cooldownSeconds (number) so you can back off precisely. V1.2 emits these explicit codes: RATE_LIMIT_PHONENUMBER_PERMINUTE, RATE_LIMIT_PHONENUMBER_PERHOUR, RATE_LIMIT_PHONENUMBER_PERDAY, RATE_LIMIT_ENDUSERIP_PERMINUTE, RATE_LIMIT_ENDUSERIP_PERHOUR, RATE_LIMIT_ENDUSERIP_PERDAY, RATE_LIMIT_PIPELINE_PERMINUTE, RATE_LIMIT_PIPELINE_PERHOUR, RATE_LIMIT_PIPELINE_PERDAY, and, on /send, IDENTITY_TEMPORARILY_BLOCKED.

StatusCodeCause and Solution
429RATE_LIMIT_PHONENUMBER_PERMINUTE, RATE_LIMIT_PHONENUMBER_PERHOUR, RATE_LIMIT_PHONENUMBER_PERDAYThe same phone number has requested too many OTPs in this window. Wait for retryAfter before retrying.
429RATE_LIMIT_ENDUSERIP_PERMINUTE, RATE_LIMIT_ENDUSERIP_PERHOUR, RATE_LIMIT_ENDUSERIP_PERDAYToo many requests from the same end-user IP. Only fires when x-end-user-ip is provided or the connection originates from a public IP — private and loopback IPs are excluded from this check.
429RATE_LIMIT_PIPELINE_PERMINUTE, RATE_LIMIT_PIPELINE_PERHOUR, RATE_LIMIT_PIPELINE_PERDAYPipeline-wide cap reached across all end users. Consider raising the pipeline rate limits in the dashboard.
429IDENTITY_TEMPORARILY_BLOCKEDReturned by /send. The identity is under a zero-verify ban. retryable is false even though a schedule is supplied — the ban is terminal until it expires, so honour retryAfter (the ban expiry) and cooldownSeconds (the remaining wait) rather than branching on retryable.

Circuit Breaker Errors

The circuit breaker is a pipeline-level flood guard: when a pipeline's traffic looks like an attack it trips, and every send is refused for a cooldown rather than burning your OTP budget. Its thresholds and cooldown are configured on the pipeline.

StatusCodeCause and Solution
503CIRCUIT_BREAKER_OPENPipeline circuit breaker is open due to flood detection. Wait for cooldownSeconds.
503CIRCUIT_BREAKER_TRIGGEREDPipeline suspended due to sustained high traffic. Automatic recovery after cooldown.

Transaction and Verification Errors

StatusCodeCause and Solution
400MISSING_REQUIRED_FIELDSRequired fields are missing from the request. For send, provide APIKey and pipelineID; for verify, provide transactionReqID and otp.
400MISSING_VERIFICATION_ADDRESSThe send request did not include a verificationAddress with a phoneNumber or email.
500TRANSACTION_NOT_FOUNDThe transaction created for the send request could not be retrieved. Retry the request.
410TRANSACTION_EXPIREDTransaction expired. Use the expiresAt value returned by send and create a new transaction when it has passed.
403INVALID_OTPOTP entered by user does not match. Prompt them to re-enter.
409ALREADY_VERIFIEDThe transaction request was already verified. Do not submit the same request again.
429MAX_ATTEMPTS_EXCEEDED10th wrong OTP on this transaction. The transaction is force-expired — create a new one; further attempts return TRANSACTION_EXPIRED.
500SEND_OTP_FAILEDThe V1.2 send operation failed outside the handled transaction paths. Retry the request.
Propagated status (default 500)ACTIVATION_FAILEDThe transaction was created but could not be activated. Retry according to the returned status.
402BILLING_FAILEDBilling failed while verifying the OTP. Resolve the billing issue before retrying.
500VERIFY_OTP_FAILEDThe verify operation failed outside the handled verification outcomes. Retry the request.
Propagated from transaction creation (default 400)TRANSACTION_CREATION_FAILEDThe underlying transaction could not be created. The response preserves its status and, when the creator supplies one, its own code, so read code before this one. For example DESTINATION_COUNTRY_BLOCKED (403) when the destination is not allowed or SYSTEM_MANAGED_PIPELINE_FORBIDDEN (404) for a pipeline reserved for platform operations.

Challenge-generation errors

The challenge endpoint returns 500 for an unhandled challenge-generation failure. The PoW service may identify the failure as POW_CHALLENGE_GENERATION_FAILED; the controller fallback is CHALLENGE_GENERATION_FAILED.

StatusCodeCause and Solution
500CHALLENGE_GENERATION_FAILED, POW_CHALLENGE_GENERATION_FAILEDThe server could not create a PoW challenge. Retry the challenge request.

Validation Errors

StatusCodeCause and Solution
400INVALID_OTP_LANGUAGEInvalid otpLanguage; see accepted values. Before retrying, fetch and solve a new challenge when proof-of-work is enabled and obtain a fresh Turnstile token when required.
400VALIDATION_ERRORRequest body failed validation. Check the details field for specific issues.
413PAYLOAD_TOO_LARGERequest body exceeds size limit.

Server Errors

StatusCodeCause and Solution
500INTERNAL_SERVER_ERRORUnexpected server error. Retry the request. If persistent, contact support at support@akedly.io.