ioZen Docs

Start a WhatsApp conversation

Send an approved template from your CRM and let an Intake Bot take the reply.

Use this when a form in your CRM creates a lead and you want ioZen to write to that person on WhatsApp. The call finds or creates the contact, opens the conversation, sends one approved template, and returns the ids. Replies follow the Intake Bot you name, or the workspace routing rules when you omit it.

The same Idempotency-Key returns the original result and does not send a second WhatsApp message.

Before you call

  • The workspace is on a plan with the inbox.
  • A WhatsApp connection is active. If the workspace has more than one, send connection_id.
  • The template is approved, and its category is UTILITY or AUTHENTICATION. MARKETING templates return 422 template_category_not_allowed.
  • The workspace has credits for the send.
  • The API key includes the send:whatsapp scope. Existing keys do not receive it.

Send the template

curl -X POST https://app.iozen.ai/api/v1/whatsapp/conversations \
  -H "Authorization: Bearer $IOZEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: crm-1234-consulta" \
  -d '{
    "phone": "+593991234567",
    "contact": {
      "first_name": "Ana",
      "last_name": "Torres",
      "email": "ana@example.com",
      "external_id": "crm-1234"
    },
    "template": { "name": "consulta_inicio", "language": "es", "params": {} },
    "intake_bot_id": "your-published-intake-bot-id"
  }'

phone is normalized to E.164. Contact fields fill only when the matched contact has them empty. external_id is stored on the contact as customFields.external_id and is not replaced once set. If the WhatsApp identity is already linked to a contact, that contact is the one returned.

Template params you send win. Blank names that match a contact field (first_name, full_name, email, and the other contact variables) are filled from the contact. Anything still blank returns 422 template_params_missing.

A 201 body looks like this:

{
  "success": true,
  "data": {
    "contact": { "id": "contact_id", "created": true },
    "conversation": { "id": "conversation_id", "created": true },
    "message": {
      "id": "message_id",
      "status": "sent",
      "template": { "name": "consulta_inicio", "language": "es" }
    },
    "idempotent": false
  }
}

Read the status later with GET /api/v1/whatsapp/messages/{id}. Status moves through sending, sent, delivered, read, or failed.

CRM recipe

  1. On a new lead, POST with a stable Idempotency-Key (the CRM lead id plus the template name is enough).
  2. Store contact.id, conversation.id, and message.id.
  3. Keep your existing pull for answers. This call does not add a per-message webhook.
  4. Repeat the same key after a timeout. You get idempotent: true and no second message.
  5. If the person is already chatting, you get 409 conversation_active. Do not retry until that chat is idle.

An API send never switches the conversation to human and never notifies agents.

Limits

LimitWindow
60 sends per API key1 hour
3 sends per workspace and phone24 hours

These sit on top of the plan's per-minute API limit, the outbound risk check, and the credit check.

Errors

CodeHTTPWhen
validation_failed400Bad body, invalid phone, or missing Idempotency-Key
feature_not_available403Plan lacks the inbox
opted_out409The person opted out
connection_inactive409No active WhatsApp connection
conversation_active409Inbound inside 24 hours, or the conversation is in human mode
risk_blocked409Outbound risk check blocked the send
connection_required422More than one connection and connection_id was omitted
template_not_available422Template is missing, not approved, or the language does not match
template_category_not_allowed422Template category is not UTILITY or AUTHENTICATION
template_params_missing422A template variable is still empty
plan_limit_exceeded402Contact limit, or no credits (details.detail is insufficient_credits)
rate_limited429Key cap or phone cap
send_failed502WhatsApp rejected the send. details.message_id is the stored message

On this page