Threadwire by TriTech

← API reference

Waiting, errors and retries

A send is answered at once with 202 and status: "queued". The message then goes out the way a person would send it, so it may wait. A rule either holds it (it stays queued and goes by itself) or fails it (status: "failed", with the reason in error). This page says which is which, how long a wait can last, and what your code should try again.

Where to see why

  • A failed message says why in its error, in plain words: in GET /v1/messages/{id}, in the message.status webhook, and in your panel under the message in its chat and in the Message log (under Developers). Its error_code says the same as a fixed value for your code: see Error codes.
  • A waiting message stays queued until it goes, with no error. Its error_code names what it is waiting for, and is null again once it has gone. GET /v1/instances/{id} shows where the instance stands today under protection: the day's limits and how much of them is used, its timezone, and under new_chats whether new chats are paused, why and until when.

What holds a message

A held message needs nothing from you. It goes when its turn comes.

Why it waits For how long
Its turn. One instance sends one message at a time, with a gap that depends on who it is for (see the pace) seconds; for someone new, up to a minute, and 5 to 10 minutes after every tenth new person
Night. Nobody who never wrote is messaged from 22:00 to 08:00 in the instance's time zone (or the quiet hours you set) until the morning
One person, many messages. At most 4 an hour go to someone who has not answered, 10 while they are chatting with you until the hour has passed, or they write
An earlier message to the same chat is still waiting. Messages to one person go in the order you sent them until that one has gone
One group, many messages: at most 20 an hour to one group until the hour has passed
The instance is reconnecting to WhatsApp a minute at a time; one that stays disconnected fails the message
WhatsApp is limiting the instance, or has just refused one of its messages. Only replies go meanwhile: everything else waits until it ends (at least an hour after a refusal), when that is within 6 hours; a longer one fails the message with the reason
A file given by url whose server did not answer, or answered with a server error tried 3 times, 2 minutes apart, then it fails

What fails a message

A failed message will not go by itself. Read error: it says what to do.

  • The instance cannot send: it is not connected, it is stopped, the account is suspended, or a different phone was linked after the message was queued.
  • The person: they wrote "STOP", or their number is not on WhatsApp.
  • The day's limits: the instance's new people for the day are used up, or its warm-up's daily messages that are not replies, or its group messages (200 a day) or channel posts (30 a day). The reason says "Try again tomorrow".
  • Someone new who has not answered: more than 2 follow-ups in a day, or a new first message before 7 days have passed. The reason gives the date it may go.
  • What a first message holds: a location, a contact card, a sticker or a poll; an http:// link, or only a link; more than 600 characters; or a text or file that already opened 5 chats that day.
  • New chats are paused: by WhatsApp for longer than 6 hours, by us, or because almost nobody answers the instance's first messages. Replies still go.
  • The file: it could not be fetched, is too large, or a sticker is not a WebP image.
  • WhatsApp refused it, or did not confirm it in time. In the second case it may have been delivered: look at the chat before sending it again.
  • An OTP code that cannot go within 2 minutes fails at once: a late code is useless.
  • You cancelled it before it went.

The rules themselves are in How sending protects your number.

A message's error codes

error is written for people, and its words may change. error_code is for your code: one fixed value per reason, on the message in the API and in the message.status event. On a failed message it is why it failed. On a queued one it is what the message is waiting for, and no event is sent for a wait. A message that failed before codes were added has none. New values may be added, so treat one you do not know like error alone.

Code What it means The message
instance_not_connected The instance is not connected to WhatsApp fails
instance_stopped The instance is stopped. Start it to send fails
instance_reconnecting The instance is reconnecting to WhatsApp waits
number_on_another_instance The WhatsApp number scanned belongs to another instance, so it was not linked here fails
account_suspended The account is suspended fails
phone_changed A different phone was linked after the message was queued or scheduled fails
opted_out The person wrote "STOP" or similar fails
opt_out_unconfirmed WhatsApp could not say whether this person is one who opted out waits
not_on_whatsapp The phone number is not on WhatsApp fails
no_number The message was addressed by a private chat id, the person's number is no longer known, and they have not written lately fails
quiet_hours It is night where the instance is, and nobody new is messaged at night waits
pacing The gap before the instance's next message waits
earlier_message_waiting An earlier message to the same chat goes first waits
per_minute_limit The instance's ceiling of messages a minute waits
per_person_limit Several messages to this person in the last hour went unanswered waits
per_group_limit Many messages went to this group in the last hour waits
daily_new_people_limit The instance's new people for the day are used up fails
daily_lookup_limit The instance checked as many new numbers on WhatsApp as it may today fails
daily_volume_limit The day's messages that are not replies are used up: warm-up, or your own cap fails
daily_group_limit The day's group messages are used up fails
daily_channel_limit The day's channel posts are used up fails
unanswered_follow_ups The person has not answered, and the day's follow-ups to them are used up fails
not_answered_yet The person has not answered the last message; error gives the date they may be written to again fails
first_message_type A first message cannot be a location, a contact card, a sticker or a poll fails
first_message_too_long A first message is longer than allowed fails
insecure_link A message to someone new carries an http:// link fails
link_only A first message is only a link fails
same_first_message The same text, or file and caption, already opened the day's allowed chats fails
new_chats_paused We paused new chats from the instance. Replies still go fails
few_replies Almost nobody answers the instance's first messages, so new chats are paused fails
whatsapp_restricted WhatsApp is limiting the instance, or has just refused one of its messages waits
whatsapp_quota The instance is near or at WhatsApp's quota of new chats waits
whatsapp_refused WhatsApp refused the message. Sending it again will not help fails
whatsapp_unreachable WhatsApp did not answer waits
may_have_been_delivered WhatsApp did not confirm it in time. Check the chat before sending it again fails
file_unavailable The file could not be fetched from its url, or is too large waits
file_missing The message's file is no longer stored with us fails
invalid_sticker A sticker must be a WebP image of at most 1 MB fails
file_too_large On a message you received: its file was over 100 MB, so we did not keep it stays received, with no media
otp_too_late An OTP's message could not go within its short window fails
otp_ended The OTP ended before its code went fails
broadcast_stopped Its broadcast held it back: paused, cancelled, stopped for safety, or the message could not be queued. The person's turn comes again fails
warmup_stopped Automatic warm-up stopped before the line went fails
cancelled You cancelled it before it went fails
not_queued We could not queue it. Send it again fails

A message that "waits" fails with the same code when the wait cannot end in time: see The longest wait. A request the API refuses outright (409, 422, 429) makes no message, so it has no error_code: read its message.

The longest wait

A message waits at most 24 hours, counted from when you sent it, or from its send_at if you scheduled it. A hold that would last to within 10 minutes of that is not started: the message fails then, and its error names what held it, usually ending "It waited as long as it could, so it was not sent. Send it again if it is still wanted." One still queued when the 24 hours end fails with "Could not reach WhatsApp. Please try again.", or with a note that it may have been delivered.

The pace

Each instance sends one message at a time. After any message, the next one waits a gap, picked at random, by who it is for:

The next message is for Gap before it
Someone who wrote in the last 24 hours (a reply) 2 to 8 seconds
Someone who wrote before that, a group or a channel 8 to 20 seconds
Someone who never wrote 30 to 60 seconds after the last first message, and a break of 5 to 10 minutes after every 10

A message to a person or a group also shows "typing…" for 1 to 4 seconds first. Above all of this there is a ceiling of 20 messages a minute per instance. So 100 replies take ten to fifteen minutes. 100 first messages take days: a newly linked instance may message 10 new people a day, rising to 50 over its first two weeks.

Different instances send at the same time; one does not slow another.

Do not send faster than an instance sends. The API takes 600 requests a minute, and an instance sends about 20 messages a minute, so a burst only makes a queue. Once an instance has more than 500 messages waiting or scheduled, POST /v1/messages to it answers 429 with the code backlog_full and a Retry-After: send the rest as these go out. Messages scheduled with send_at count like the waiting ones. Replies to people who wrote in the last 24 hours are always taken. For one message to many people, use a broadcast, which paces itself.

What your code should retry

A request that was refused (no message was made):

Status Retry?
409 Only when there is a Retry-After header: wait that long, then send the same request. Without one, read message: for example, the instance is not connected, or is stopped.
429 Yes, after Retry-After. It is the request limit (600 a minute per account), an instance's full backlog, or a plan or safety limit that message names.
502, 503 Yes. WhatsApp did not answer, or we could not take the request just now. Wait for Retry-After when present; otherwise a few seconds, then longer each time.
401, 403, 404, 422 No. Fix the key, the id or the request first.

Send the same Idempotency-Key on every retry of one message, so two answers to one request can never become two messages. POST /v1/otps and POST /v1/broadcasts take the header too.

A message that was accepted (202) needs no retry while it is queued: waiting is normal.

A message that failed: never send it again in a loop. Repeating a refused message is the pattern WhatsApp bans, and the same reason will refuse it again. Read error and act on it: wait for tomorrow, let the person write first, fix the file. When you do send it again, use a new Idempotency-Key: the old key returns the failed message.

The API's error codes

A refused request carries a code beside its message. We may improve a message's words; a code never changes. So let your program act on the code, and show or log the message.

Code Meaning
unauthenticated No API key was sent, or it was revoked.
key_not_allowed The key was made for less: it is read-only or send-only, or for one instance.
ip_not_allowed The key is locked to IP addresses, and the request came from another.
account_suspended The account is paused or suspended; message says why.
plan_limit The plan's instances, messages, conversations or API requests are used up.
feature_not_included Your plan, or its free trial, does not include this feature; message names it.
instance_not_found No instance with this id on your account.
message_not_found No message with this id on your account.
chat_not_found The instance has no chat with this person, or does not know them.
group_not_found No group with this id.
channel_not_found No channel with this id.
broadcast_not_found No broadcast with this id on your account.
otp_not_found No OTP with this id on your account.
status_not_found No status with this id on the instance.
not_found No such address, or nothing else with this id.
not_connected The instance is not connected to WhatsApp: stopped, disconnected or not linked yet.
link_refused The phone scanned belongs to another instance. Unlink to start again.
whatsapp_restricted WhatsApp is restricting the number, and this would make it worse. Wait until it lifts.
new_chats_paused New chats are paused on the instance, so it cannot reach new people now.
whatsapp_refused WhatsApp refused the request itself; message says what it needs.
in_progress Something else is under way on the instance or the account. Try again in a few seconds.
conflict Not possible in the state this is in, such as cancelling a message that has gone.
validation_failed Something in the request is wrong; errors names each field.
wrong_code The OTP code is not right; attempts_left says how many tries remain.
no_attempts_left The OTP has no attempts left. Start a new one.
rate_limited Too many requests from the account in a minute.
limit_reached One endpoint's own limit for the instance, key or phone, by the minute, hour or day; message says which.
backlog_full The instance already has too many messages waiting or scheduled. Send more as they go out.
file_budget_used The account's inline files for the day are used. Send files by url, or wait for Retry-After.
busy The instance is answering other requests that read from WhatsApp. Try again in a few seconds.
whatsapp_unavailable WhatsApp did not answer. Try again.
unavailable We could not take the request just now. Try again.
person_unknown WhatsApp could not tell us the number behind a private chat_id just now, so nothing was sent. Try again.
server_error Something failed on our side. Try again, and tell us if it stays.
bad_request The request could not be read, such as a method the address does not take.