SendKuy API

Errors

Every error this API can answer with, and what to do about each one.

Every failure answers with the same shape.

{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "The field channel is required.",
    "param": "channel",
    "doc_url": "https://docs.sendkuy.com/errors#validation_failed"
  }
}

type groups the failure into one of five families. code is specific and stable — branch your code on code, never on message, which is written for a person and may be reworded. param names the field when exactly one field caused it. doc_url links back to the section on this page.

Every response also carries X-Request-Id. Quote it when you report a problem and we find the exact call.

missing_api_key

HTTP 401 — No Authorization header, or one that is not Bearer.

Send the key as Authorization: Bearer sk_live_…. Keys in the query string or the request body are refused on purpose: a URL is logged by every proxy it passes through, and that is how customer keys leak.

invalid_api_key

HTTP 401 — The token does not match any key we issued.

Usually a copy-paste that lost a character, or a key from a different account. Check the prefix against the one shown in your dashboard.

api_key_revoked

HTTP 401 — The key existed and was revoked from the dashboard.

Revocation is immediate and permanent. Issue a new key; there is no un-revoke.

api_key_expired

HTTP 401 — The key carried an expiry and it has passed.

Issue a new one. If you did not mean to set an expiry, leave the field empty when creating the key.

subscription_expired

HTTP 403 — The account behind the key has no running plan.

The key is fine; the account is not. Renew the plan and the same key works again — you do not need to reissue it.

account_suspended

HTTP 403 — The account behind the key is suspended, in the trash, or being deleted.

The key is fine; the account cannot send anything right now, through the API or anywhere else. Reissuing the key does not help. Contact support.

insufficient_scope

HTTP 403 — The key is valid but was not issued the scope this route needs.

The message names the scope it wanted. Scopes are fixed at creation, so this means issuing a new key with the scope added, not editing the old one.

channel_not_in_plan

HTTP 403 — Your plan does not include the channel you asked to send on.

Change the channel, or change the plan. Reading works on every channel; only sending is gated.

insufficient_credits

HTTP 402 — Not enough credit for this send.

402 rather than 403 because this is the one refusal you fix by paying, not by changing the request. Retry the exact same call after topping up.

validation_failed

HTTP 422 — A field is missing, malformed, or not allowed on this endpoint.

param names the field. Fields that do not belong to the channel you picked are refused by name rather than ignored — sending subject on WhatsApp fails here instead of going out silently without it.

no_sender_available

HTTP 422 — Nothing on this channel can send for you right now.

The message says which half is missing. On a plan that sends through your own gateways, connect one on this channel in the dashboard and retry. On a plan that lends SendKuy's senders, the shared ones are all offline, and the same call works once one is back. Nothing was sent and no credit was spent.

request_refused

HTTP 400 — Well formed, and still refused for a reason the message states.

Almost always a state problem rather than a shape problem: pausing a campaign that never started, cancelling a message that already went out. Read the object first and check the state the endpoint requires.

resource_not_found

HTTP 404 — No object of that type carries that id in your account.

Ids are scoped to the account behind the key, so an id that works elsewhere answers 404 here rather than admitting it exists. Check the prefix too: msg_ is a delivery row, cms_ is a message inside a conversation, and they are different objects.

method_not_allowed

HTTP 405 — The path exists, the method does not.

Check the reference page for the endpoint. Updates are PATCH, never PUT.

idempotency_key_reused

HTTP 409 — That Idempotency-Key was used for a request with a different body.

A key stands for one logical request. Generate a fresh one per logical request, and reuse it only when retrying that same request unchanged.

idempotency_request_in_progress

HTTP 409 — The first request carrying that key has not finished yet.

Wait and retry with the same key; you will get the original answer. Do not generate a new key, or the work happens twice.

rate_limit_exceeded

HTTP 429 — Too many requests this minute for this key.

Retry-After says how many seconds to wait, and X-RateLimit-Limit says what your ceiling is. The ceiling comes from your plan, and GET /account reports it as rate_limit.

internal_error

HTTP 500 — Our fault.

Retry once; if it persists, send us the X-Request-Id from the response and we can find the exact call in our logs.

On this page