API documentation

API errors

Every IotaBot API error code, its HTTP status, and what to do about it.

Errors use HTTP status codes and one body shape, so your code can branch on error.code rather than on the message text:

{
  "error": {
    "code": "window_closed",
    "message": "More than 24 hours since the customer last wrote — WhatsApp only allows an approved template now",
    "request_id": "0f6047d9-bf3d-4ca7-adac-33011910b01d"
  }
}

request_id is also sent as the X-Request-Id header on every response. Quote it when you contact support — it finds the request in your logs and ours.

CodeStatusWhat it means
invalid_api_key401The key is missing, malformed or unknown. Send it as Authorization: Bearer ib_live_….
key_revoked401The key was revoked. Create a new one.
key_expired401The key passed its expiry date. Roll or replace it.
key_rolled401This is a rolled-away secret whose grace period ended. Use the new secret.
test_key_required403Simulated messages need a test key (ib_test_…).
step_up_required403Portal only: creating, rolling or showing a secret needs a fresh emailed code.
plan_upgrade_required403API keys and webhooks are on paid plans. Upgrade the workspace to use them.
account_inactive403The workspace is suspended or closed.
ip_not_allowed403The request came from an address outside the key's IP allowlist.
insufficient_scope403The key lacks the permission this endpoint needs (shown on each endpoint).
channel_not_allowed403The key is limited to other channels.
website_not_allowed403The key is limited to other websites.
contacts_need_all_websites403Contacts belong to the whole workspace; use a key that is not limited to some websites.
invalid_request400The body or parameters do not make sense together — the message says which.
invalid_version400The IotaBot-Version header names a version the API does not serve. Leave it out to use the key's own version.
invalid_limit400limit must be between 1 and 100.
invalid_cursor400starting_after is not a cursor this API returned.
invalid_phone400Give phone numbers with their country code, e.g. +919812345678.
text_required400The message has no content for its channel (text, html, a template or attachments).
from_required400A new email needs from, one of your verified addresses.
subject_required400A new email needs a subject.
invalid_email400to is not an email address.
whatsapp_account_required400The key reaches several WhatsApp numbers — say which with whatsapp_account_id.
invalid_attachment400Each attachment needs file_id, or filename with content_base64.
file_not_found400No uploaded file with that id.
invalid_idempotency_key400Idempotency-Key must be at most 255 characters.
file_rejected400The file type is not allowed, the file is empty, or it is over 10 MB.
unsupported_attachment400Instagram takes images, video and audio only.
file_already_used400An uploaded file can be attached to one message only.
attachments_too_large400Attachments may total 10 MB per message.
conversation_not_found404No conversation with that id that this key can see.
message_not_found404No message with that id that this key can see.
contact_not_found404No contact with that id.
integration_paused409An agent paused integration replies on this conversation. Stop retrying; a conversation.updated event tells you when it resumes.
contact_exists409Another contact already has this email or phone; the message includes its id.
idempotency_in_progress409A request with this Idempotency-Key is still being processed. Retry shortly.
window_closed422More than 24 hours since the customer last wrote. On WhatsApp send an approved template; on Instagram you must wait for them to write.
no_whatsapp_account422This key cannot reach any connected WhatsApp number.
endpoint_disabled400The webhook endpoint is off or deleted, so it cannot be replayed to.
event_expired400The event is past your log retention period.
template_not_approved422No approved template with that name and language on this number (GET /whatsapp/templates).
template_not_marketing422POST /whatsapp/marketing-messages sends MARKETING templates only. Send utility and authentication templates with POST /messages.
conversation_closed422Website chats accept messages only while open; reopen a conversation before changing its mode.
sender_not_verified422The email domain is not verified yet, so nothing can be sent from it.
sender_not_found422from is not one of your email addresses this key can use (GET /email/senders).
recipient_suppressed422An address bounced permanently or reported your email as spam, so nothing can be sent to it.
recipient_unsubscribed422The address unsubscribed: you can answer their emails, but not start a new thread.
private_reply_expired422Instagram allows a private reply (reply_as: "dm") only within 7 days of the comment. Reply publicly instead.
private_reply_used422The comment already has its private reply — Instagram allows one per comment. Once the customer answers, reply in their DM conversation.
recipient_opted_out422The customer opted out of this channel (they replied STOP, or the contact is marked opted out). Nothing can be sent to them there.
no_recipient422The email conversation has no customer address to send to.
agent_not_found422assigned_agent_id is not an active agent in this workspace.
idempotency_key_reused422The Idempotency-Key was already used with a different request.
rate_limited429Over the key's rate limit (20 a second and 300 a minute on paid plans). Wait for Retry-After seconds.
api_quota_exceeded429The workspace used its monthly API messages. It resets on the 1st; the plan sets the limit.