Skip to main content
Every error of the API answers in JSON with three fields at least:
422 Unprocessable Content
Some errors add fields of their own: errors for a validation error, problems for a campaign that is not ready, data for a transactional e-mail that was logged but not sent.

The HTTP statuses

Validation errors

422 validation_error, with the detail field by field:
Fields inside arrays are named by their position: subscribers.14.email is the 15th line of a batch.

An address nothing would arrive at

Adding someone new checks the address first: POST /v1/lists/{list}/subscribers, and POST /v1/automations/{automation}/trigger for a person not on the list yet. A throwaway mailbox, or a domain with no mail server, answers 422 undeliverable_address with two more fields:
Show suggestion to the person and let them choose: never swap it in on your own. In a batch, the same address is a line with "outcome": "failed" and its message; in an import, a line in error.

Retry or not

  • Retry on 429 rate_limited, on 5xx and on network errors, with a growing delay and the same Idempotency-Key.
  • Read first a 502 from a transactional e-mail: data.failure_reason says whether sending again can work.
  • Do not retry any other 4xx: the same call gives the same answer. Fix it first. One exception: 409 idempotency_key_in_use, the same idempotent call still running; try again a moment later.

Every code

Grouped by where they come from. Each one has its anchor: /errors#rate_limited.

Any route

unauthenticated

401. No Authorization header, a malformed token, or a revoked one. Check that the whole token follows Bearer . See Authentication.

missing_ability

403. A Read token called a route that writes. Create a Read and write token for this application.

role_not_allowed

403. The token’s owner may not do this in the team: a viewer writing, a writer sending a campaign. A token acts with its owner’s role, checked on every call. See The roles.

team_suspended

403. The team is suspended: every call is refused until whoever runs the service lifts it. Contact support.

team_access_lost

403. The token’s owner is no longer a member of the team the token was made in. Create a token from an account that is.

two_factor_required

403. The team requires two-factor authentication, and the token’s owner has neither a second factor nor a passkey. Once they set one up, the token works again. See Rules of the team.

no_team

403. The account is in no team at all. It happens to someone removed from every team.

forbidden

403. Refused for a reason that has no code of its own. message says which.

not_found

404. No route at this address, or no resource of this id in the token’s team. A resource of another team is not found either, by design.

method_not_allowed

405. The route exists, with another method: GET instead of POST, say.

conflict

409. The state of the resource does not allow it. message says why.

bad_request

400. The request could not be read.

payload_too_large

413. The body is larger than the server accepts. Send fewer lines per batch, or a smaller file.

validation_error

422. A field is missing or invalid. errors lists them, field by field. See Validation errors.

invalid_request

422. Refused for a reason that has no code of its own. message says which.

rate_limited

429. The token made more than its calls of the minute (120 by default). Wait the Retry-After seconds; X-RateLimit-Remaining says, on every answer, how many calls are left.

server_error

500. Lekalao’s fault. Try again later with the same Idempotency-Key; if it lasts, tell support the time of the call.

service_unavailable

503. The installation is in maintenance. Try again in a few minutes.

Idempotency

idempotency_key_too_long

400. The Idempotency-Key is longer than 255 characters.

idempotency_key_in_use

409. A call with the same key is still running. Try again a moment later: you will get its answer.

idempotency_key_reused

422. The key was already used for another route or another body. Give each operation its own key.

idempotency_key_expired

422. The key is more than 24 hours old. Send a new one. See Idempotency.

Test keys

sandbox_cannot_send

403. A test key called a route that exists to write to real people: sending a campaign, putting someone into an automation, sending a confirmation e-mail again. Use a live key.

Contacts

undeliverable_address

422. The address cannot receive e-mail: a throwaway mailbox, or a domain without a mail server. See An address nothing would arrive at.

address_suppressed

422. The address is on the team’s suppression list: it bounced for good, complained, or was blocked by hand. It cannot be subscribed again by the API.

subscriber_limit_reached

422. The plan holds no more subscribers. Move up a plan, or clean the lists. See Plans.

confirmation_not_needed

422. resend-confirmation for someone who has nothing to confirm: already subscribed, or on a list without double opt-in.

batch_rejected

422. Not one line of the batch could be saved. data gives the reason of each line, meta the counts.

contact_not_found

404. A conversion for an address that is on none of the team’s lists.

event_count_out_of_range

422. POST /v1/events takes one event, or between 1 and 1,000 under events.

Sending

sender_not_allowed

422. The sender address is not on a verified sending domain of the team, where the installation requires one. The message names the domain. See Sending domains.

template_error

422. The template does not render: a tag left open, an unknown filter. The message says where.

content_missing

422. A transactional e-mail with neither template nor html.

recipient_missing

422. A transactional e-mail with no to, from a template that has no default recipients either.

too_many_recipients

422. More than 50 addresses in one transactional e-mail, to, cc and bcc together. A transactional e-mail is written to someone: send one each.

recipients_suppressed

422. Every address in to is on the suppression list. The e-mail is logged as failed, under data. Sending it again fails the same way.

monthly_quota_exceeded

429. The plan’s e-mails of the month are used up; each recipient of an e-mail counts, copies included. The e-mail is logged as failed, under data. Wait for the next month, or move up a plan. A campaign test refused for this reason answers test_refused.

sending_paused

422. The team may not send: its paid period ended without a payment. The e-mail is logged as failed, under data. See Billing.

provider_error

502. The provider refused the transactional e-mail on every try, for six hours, or a test key wrote to failed@sink.lekalao.dev. data.failure_reason holds the provider’s last word.

queue_unavailable

502. The e-mail was logged, but the queue could not take it. Try again in a moment with the same Idempotency-Key: a 502 is not kept, so the e-mail is not counted twice.

mail_not_kept

409. A resend of a transactional e-mail whose template keeps neither the content nor the variables (one-time codes, sign-in links). Send a new e-mail.

campaign_not_ready

422. The campaign cannot leave yet. problems lists what is missing, as the interface does. See Ready or not.

campaign_is_sending

409. A campaign being sent cannot be deleted. Pause it in the interface first.

test_refused

422. A campaign test that may not leave: the sender’s domain is not verified (where the installation requires it), every address given is on the suppression list, the team has sent 100 test e-mails this hour, or the month’s allowance is used up. message says which.

automation_not_running

409. The automation is not active, or has no list. Switch it on in the interface.

already_in_automation

409. The person is already travelling through this automation. The answer also carries "started": false.

Licences

licence_invalid

422. POST /v1/licences/check: the key cannot be read, or is not signed by Lekalao. The answer also carries "valid": false, "reason": "invalid".

licence_revoked

403. The licence has been revoked. The answer also carries "valid": false, "reason": "revoked".

A transactional e-mail that failed

A transactional e-mail keeps why it failed in failure_code, with the same words as the codes above: recipients_suppressed, monthly_quota_exceeded, sending_paused, provider_error, queue_unavailable. One more is never an answer to a call, since it happens later: lost, an e-mail still pending seven hours after the call because its job was lost. Send it again. See Transactional e-mails.