Skip to content

Send your first message in 5 minutes

Create an API key with the Send WhatsApp messages preset, put it in your environment, and send a WhatsApp message with one request, in curl, Node.js, Python or PHP.

This guide takes you from no API key to a WhatsApp message on your own phone. You need about five minutes and a terminal.

Before you start

  • A connected WhatsApp number. The API sends from your organisation's own numbers. See Numbers and accounts.
  • An approved message template. A customer who has never written to your number can only receive a template. Your own phone counts as a new customer. See Message templates.
  • An Owner or Admin account. A key can never do more than the person who creates it. The Developer role can't send messages, so it can't create a key that sends.
  • A plan that includes the public API. See Plans and trial.

1. Create a key

  1. Go to Settings › Developers › API keys and click New API key.
  2. In Name, enter the name of the system that will use the key, for example "Order sync".
  3. Under What will this key do?, keep Send WhatsApp messages selected. It is marked Recommended and lists what the key will be able to do: send messages, check whether they were delivered, add a contact when you message a new number, and see your numbers and templates.
  4. Click Create key. If IconEngage asks you to confirm your identity, enter your two-factor code or your password.
  5. Copy the key and store it somewhere safe. This is the only time it is shown.

Tip: The screen that shows your key also has Send your first message: the same examples as below, already filled in with your number and one of your approved templates. You can copy from there instead.

2. Put the key in your environment

The examples read the key from the ICONENGAGE_API_KEY environment variable, so it never ends up in your code. In the terminal you will use:

bash
export ICONENGAGE_API_KEY="paste-your-key-here"

On Windows PowerShell, use $env:ICONENGAGE_API_KEY = "paste-your-key-here" instead.

3. Send a template message

Replace the example values with yours:

  • to: your own phone number in international format, starting with + and the country code, in place of +91XXXXXXXXXX. Spaces and dashes are fine. A number without the + is refused. The placeholder is refused as it stands, so an example you forget to edit sends nothing.
  • template: the name and language of one of your approved templates, and one value in variables for each variable in its body, in order. Leave variables out if the template has none. To skip the guesswork, GET /templates/{template_id} returns example, a ready-to-send body: copy it and change to. See Start from the template's example.

If your organisation has one WhatsApp number, the message is sent from it. If it has several, add "from". See Choose the sending number.

Every request also sends an Idempotency-Key header. If a request times out, sending it again with the same key can never deliver the message twice. The examples make a new key each time they run, so each run sends a new message.

The curl examples make the key with uuidgen. If your system doesn't have it (Windows, and some minimal Linux images), use $(python3 -c 'import uuid; print(uuid.uuid4())') in its place. In PowerShell, [guid]::NewGuid() makes one.

curl

bash
curl -X POST https://iconengage.com/api/public/v1/messages \
  -H "Authorization: Bearer $ICONENGAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "to": "+91XXXXXXXXXX",
    "type": "template",
    "template": {
      "name": "order_update",
      "language": "en",
      "variables": ["Asha", "#1042"]
    }
  }'

Node.js

Node.js 18 or later. Save this as send.mjs and run node send.mjs:

js
const response = await fetch("https://iconengage.com/api/public/v1/messages", {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ICONENGAGE_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    to: '+91XXXXXXXXXX',
    type: 'template',
    template: { name: 'order_update', language: 'en', variables: ['Asha', '#1042'] },
  }),
})
console.log(response.status, await response.json())

Python

Python 3 with the requests package (pip install requests):

python
import os
import uuid

import requests

response = requests.post(
    "https://iconengage.com/api/public/v1/messages",
    headers={
        "Authorization": f"Bearer {os.environ['ICONENGAGE_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "to": "+91XXXXXXXXXX",
        "type": "template",
        "template": {"name": "order_update", "language": "en", "variables": ["Asha", "#1042"]},
    },
)
print(response.status_code, response.json())

PHP

PHP 7.4 or later with the curl extension. Run php send.php:

php
<?php
$body = [
    'to' => '+91XXXXXXXXXX',
    'type' => 'template',
    'template' => ['name' => 'order_update', 'language' => 'en', 'variables' => ['Asha', '#1042']],
];

$ch = curl_init('https://iconengage.com/api/public/v1/messages');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ICONENGAGE_API_KEY'),
        'Content-Type: application/json',
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => json_encode($body),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), ' ', $response, PHP_EOL;

4. Check the answer

A message IconEngage has accepted gets 202 and the stored message:

json
{
  "id": "6f1c2e8a-…",
  "type": "template",
  "status": "accepted",
  "template_name": "order_update",
  "wamid": null
}

accepted means IconEngage will send it. It has not reached WhatsApp yet. To follow it, ask for the message by its id. Its status moves from accepted to sent, delivered and read, or to failed with a reason:

bash
curl https://iconengage.com/api/public/v1/messages/6f1c2e8a-… \
  -H "Authorization: Bearer $ICONENGAGE_API_KEY"

If it doesn't work

Every refusal has a code, and for the common ones a fix that says what to change and a docs_url that links to the explanation. The ones you are most likely to meet on a first send:

StatuscodeWhat to do
401unauthenticatedThe key is missing, mistyped or revoked. Check that ICONENGAGE_API_KEY is set in the terminal you ran from. See unauthenticated.
403permission_deniedThe key lacks a permission. Create one with the Send WhatsApp messages preset. See permission_denied.
400validation_failed with details.reason: to_needs_country_codeto has no + and country code. Write it as +91 XXXXX XXXXX, not XXXXX XXXXX. See to_needs_country_code.
400validation_failed with details.reason: from_requiredYour organisation has more than one number. Add "from" with one of details.numbers. See from_required.
409template_requiredYou sent text to someone who has never written to this number. Send a template. See template_required.
409template_not_approvedThe template name, language or number of variables doesn't match an approved template. See template_not_approved.
409conflict with details.reason: no_connected_phone_numberNo number can send yet. See no_connected_phone_number.

If the answer was 202 but the message never arrives, see Messages not delivered.

Send text instead

WhatsApp only delivers text and other free-form messages within 24 hours of the customer's last message to you. To try one, first send any message from your phone to your WhatsApp Business number. Then, within 24 hours:

bash
curl -X POST https://iconengage.com/api/public/v1/messages \
  -H "Authorization: Bearer $ICONENGAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "to": "+91XXXXXXXXXX", "type": "text", "text": { "body": "Hello from the API!" } }'

See The 24-hour window and templates.

Next steps

Still need help?

Write to us at [email protected] and tell us what you were trying to do. Already a customer? Sign in to IconEngage — the same articles are under Help in the app.