📡 WhatsApp Messaging API

Send template and non-template messages through your registered WhatsApp Business Account (WABA).


🔗 Endpoint

POST /api/v1/whatsapp/:id/messages
  • :id = WABA channel ID (required)

🔐 Authentication

All requests must include the API key via the Authorization header:

You can get your API key from the /companies page.

Authorization: Bearer YOUR_API_KEY

📥 Request Parameters

🔸 Path Parameter

ParameterTypeRequiredDescription
idstring✅ YesWABA channel ID you want to use

📦 Request Body (General Structure)

{
  "phone_number": "+254712345678" | ["+254712345678", "+254798765432"],
  "contact_tag_id": "42" | ["42", "57"],
  "type": "text" | "image" | "video" | "audio" | "document" | "template",
  "message": "Hello world",
  "link": "https://example.com/file.mp4",
  "caption": "Your caption here",
  "template_id": 123,
  "components": [ ... ]
}

📋 Body Parameters

ParameterTypeRequiredDescription
phone_numberstring | number | array✳️ One ofRecipient phone number(s). Can be a single value or an array. Non-digits are stripped automatically.
contact_tag_idstring | array✳️ One ofContact tag ID(s). All contacts assigned to the tag(s) in your company will receive the message. Can be combined with phone_number.
typestring✅ YesMessage type: text, image, video, audio, document, template, or interactive.
messagestring⚠️ ConditionalRequired when type is text.
linkstring (URL)⚠️ ConditionalRequired when type is image, video, audio, or document. Must be a publicly accessible URL.
captionstring❌ NoOptional caption for image, video, and document messages.
template_idnumber⚠️ ConditionalRequired when type is template. Must be the numeric ID of an approved template.
componentsarray⚠️ ConditionalRequired when type is template. Defines header, body, and button variable values.
interactiveobject⚠️ ConditionalRequired when type is interactive. Contains the interactive message payload.

> ✳️ At least one of phone_number or contact_tag_id must be provided. They can be used together — resolved phone numbers from both sources are merged and deduplicated before sending.


🎯 Message Types and Payloads

1. 📨 Text Message

Single recipient:

{
  "phone_number": "+254712345678",
  "type": "text",
  "message": "Hello! This is a test message"
}

Multiple recipients (array):

{
  "phone_number": ["+254712345678", "+254798765432"],
  "type": "text",
  "message": "Hello! This is a test message"
}

Send to all contacts in a tag:

{
  "contact_tag_id": "42",
  "type": "text",
  "message": "Hello! This is a test message"
}

Send to multiple tags + explicit numbers:

{
  "contact_tag_id": ["42", "57"],
  "phone_number": "+254798765432",
  "type": "text",
  "message": "Hello! This is a test message"
}

2. 🖼️ Image Message

{
  "phone_number": "+254712345678",
  "type": "image",
  "link": "https://example.com/image.jpg",
  "caption": "Check out this photo"
}

3. 🎥 Video Message

{
  "phone_number": "+254712345678",
  "type": "video",
  "link": "https://example.com/video.mp4",
  "caption": "Watch this!"
}

4. 🔈 Audio Message

{
  "phone_number": "+254712345678",
  "type": "audio",
  "link": "https://example.com/audio.mp3"
}

5. 📄 Document Message

{
  "phone_number": "+254712345678",
  "type": "document",
  "link": "https://example.com/file.pdf",
  "caption": "Please review the file"
}

6. 🧩 Template Message

{
  "phone_number": "+254712345678",
  "type": "template",
  "template_id": "promo_template",
  "language": "en_US",
  "components": [
    {
      "type": "header",
      "parameters": [
        {
          "type": "image",
          "link": "https://example.com/header.jpg"
        }
      ]
    },
    {
      "type": "body",
      "parameters": [
        { "type": "text", "text": "Dennis" },
        { "type": "text", "text": "20% OFF" }
      ]
    },
    {
      "type": "button",
      "sub_type": "url",
      "index": "0",
      "parameters": [{ "type": "text", "text": "promo123" }]
    }
  ]
}

7. 🧩 Interactive Buttons Message

{
  "phone_number": "+254712345678",
  "type": "interactive",
  "interactive": {
    "type": "button",
    "body": {
      "text": "Escolha qual carnê você deseja resgatar no meu abaixo!"
    },
    "action": {
      "buttons": [
        {
          "type": "reply",
          "reply": {
            "id": "ID1",
            "title": "Botão 1"
          }
        },
        {
          "type": "reply",
          "reply": {
            "id": "ID2",
            "title": "Botão 2"
          }
        }
      ]
    }
  }
}

8. 🧩 Interactive List Message

{
  "phone_number": "+254712345678",
  "type": "interactive",
  "interactive": {
    "type": "list",
    "body": {
      "text": "ExemplodeMensagemLista"
    },
    "action": {
      "button": "menutext",
      "sections": [
        {
          "title": "SectionTitle",
          "rows": [
            {
              "id": "1",
              "title": "Bruno",
              "description": "19984440001"
            },
            {
              "id": "2",
              "title": "Bruno2",
              "description": "19984440002"
            },
            {
              "id": "3",
              "title": "Bruno2",
              "description": "19984440003"
            }
          ]
        }
      ]
    }
  }
}

9. 🧩 Interactive Product List Message

{
  "phone_number": "+254712345678",
  "type": "interactive",
  "interactive": {
    "type": "product_list",
    "header": {
      "type": "text",
      "text": "Texto Header"
    },
    "body": {
      "text": "Texto Body"
    },
    "footer": {
      "text": "Texto Footer"
    },
    "action": {
      "catalog_id": "829935987679103",
      "sections": [
        {
          "title": "Pizzas",
          "product_items": [
            {
              "product_retailer_id": "pizza-queijo"
            }
          ]
        },
        {
          "title": "Refrigerantes",
          "product_items": [
            {
              "product_retailer_id": "coca-2l"
            },
            {
              "product_retailer_id": "coca-fardo"
            }
          ]
        }
      ]
    }
  }
}

10. 🧩 Interactive One product Message

{
  "phone_number": "+254712345678",
  "type": "interactive",
  "interactive": {
    "type": "product",
    "body": {
      "text": "Texto Body"
    },
    "footer": {
      "text": "Texto Footer"
    },
    "action": {
      "catalog_id": "829935987679103",
      "product_retailer_id": "P01002"
    }
  }
}

🧪 Example cURL

Single number:

curl -X POST https://app.autokonnect.co.ke/api/v1/whatsapp/123/messages \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+254712345678",
    "type": "text",
    "message": "Hello from the API!"
  }'

Multiple numbers:

curl -X POST https://app.autokonnect.co.ke/api/v1/whatsapp/123/messages \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": ["+254712345678", "+254798765432"],
    "type": "text",
    "message": "Hello from the API!"
  }'

By contact tag:

curl -X POST https://app.autokonnect.co.ke/api/v1/whatsapp/123/messages \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_tag_id": "42",
    "type": "text",
    "message": "Hello from the API!"
  }'

✅ Response

{
  "message": "Message queued for sending",
  "recipients_count": 3
}

recipients_count reflects the total number of unique phone numbers the message was queued for, after merging phone_number and contact_tag_id recipients and deduplicating.


❌ Error Responses

StatusCodeMessage
400missing_typetype field is required
400missing_recipientNeither phone_number nor contact_tag_id was provided
400no_valid_recipientsTag(s) resolved to zero contacts with valid phone numbers
400invalid_typeMessage type is not supported
400missing_messagemessage is required for text type
400missing_linklink is required for media types
400missing_template_idtemplate_id is required for template type
400invalid_template_id_formattemplate_id must be a number
400missing_componentscomponents is required for template type
400template_not_approvedThe specified template is not approved
400reconnect_wabaWABA channel is disconnected
401invalid_auth_headerMissing or malformed Authorization header
401invalid_api_keyInvalid API key
403credential_resource_mismatchWABA does not belong to the authenticated company
404template_not_foundTemplate ID not found for this company
404WABA channel ID not found
500Internal server error

📌 Notes

  • Recipient resolution: phone_number and contact_tag_id can be used together. All resolved numbers are merged and deduplicated before queuing.
  • phone_number accepts a single string/number or an array. Non-digit characters (spaces, dashes, +) are stripped automatically.
  • contact_tag_id accepts a single tag ID or an array of tag IDs. Only contacts belonging to your company and having a valid phone number are included.
  • Bulk sending: When more than one recipient is resolved, messages are queued in a single bulk operation for efficiency.
  • Media links must be publicly accessible URLs.
  • template_id must be the numeric ID of an approved template (use the GET templates API to retrieve it).
  • Rate limits and template usage quotas depend on your WABA tier settings.