Skip to main content
On this page

Before you start

The WhatsApp Business API is governed by Meta. Your business, phone number and message templates must be approved by Meta before you can send messages. Make sure you have completed these steps:

  1. Create a SpringEdge WhatsApp account. Sign up or talk to us to get onboarded on the WhatsApp Business API.
  2. Verify your business on Meta. Your Meta Business Portfolio (Business Manager) should be verified to unlock higher messaging limits. Follow the Meta business verification guide.
  3. Register a phone number and display name. Use a number that is not active on the WhatsApp or WhatsApp Business app, and a display name that follows Meta's guidelines. See the phone number & display name requirements.
  4. Get your message templates approved. Business-initiated messages must use a template approved by Meta. See the template approval guidelines, or create templates with the template API.
  5. Collect customer opt-in. Only message customers who have agreed to receive WhatsApp messages from you. See the opt-in rules.
  6. Get your API credentials. After onboarding, SpringEdge shares your <WHATSAPP_SERVICE_URL> and API key. Use the account details API to look up your phone number ID and WhatsApp Business Account (WABA) ID.

New to WhatsApp Business API? Read the WhatsApp Business API onboarding & Meta verification guide first. It covers business verification, policies, templates, quality rating and messaging limits.

Base URL & authentication

Every request in this documentation starts with <WHATSAPP_SERVICE_URL>. This is your account's WhatsApp service URL, shared with you after onboarding. Replace the placeholder with that URL, including https://.

Authenticate every request with your API key in the apikey header. Requests with a JSON body also need a Content-Type header:

HeaderValue
apikey Your WhatsApp Business API key.
Content-Type application/json for requests with a JSON body.

Identifiers used in URLs

PlaceholderDescription
{{phone_number_id}} ID of your WhatsApp business phone number. Used to send messages and manage media.
{{waba_id}} ID of your WhatsApp Business Account. Used to create and manage templates.
{{template_id}} ID of a message template, returned when the template is created.
{{media_id}} ID of an uploaded media file, returned by the upload media API.

Recipient numbers (to) must include the country code without + or leading zeros, e.g. 91XXXXXXXXXX for India.

Keep your API key secret. Call the API only from your server. Never call it from front-end code such as JavaScript, jQuery or HTML, where the key would be visible to anyone. Your API key can also be restricted to specific IP addresses. Ask support to enable this.

Session vs template messages

WhatsApp lets businesses send two kinds of messages:

  • Session messages (text, media, location, contacts, interactive and commerce messages) can be sent only within 24 hours of the customer's last message to you. Each new message from the customer reopens this 24-hour customer service window.
  • Template messages are pre-approved by Meta and can be sent at any time, including to start a conversation. Use them for notifications, OTPs, reminders and marketing.

So a conversation always starts in one of two ways: the customer messages you, or you send an approved template message. A session message sent to a customer who hasn't messaged you in the last 24 hours is not delivered. That's why this documentation covers template messages first, followed by session messages for replying once the customer responds.

HTTP status codes

StatusMeaning
200 OK The request was successful.
201 Created The request was successful and a resource was created.
204 No Content The request was successful but there is nothing to return.
400 Bad Request The request could not be understood or is missing required parameters.
401 Unauthorized Authentication failed, or the API key doesn't have permission for this operation.
403 Forbidden Access denied.
404 Not Found The resource was not found.
405 Method Not Allowed The HTTP method is not supported for this resource.

Send text template

Start here. Per Meta's rules, a conversation must be started either by the customer messaging you, or by you sending an approved template message. Free-form session messages (text, media, location and so on) sent to a customer who hasn't messaged you in the last 24 hours are not delivered. Send a template first, and switch to session messages once the customer replies.

Sends an approved template. name and language.code must exactly match the approved template, e.g. en or en_US. Pass one parameters entry for each variable ({{1}}, {{2}}, …) in the template body, in order.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages

Sample request

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "order_confirmation",
    "language": { "code": "en" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Rahul" },
          { "type": "text", "text": "ORD-78542" }
        ]
      }
    ]
  }
}
curl -X POST "<WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages" \
  -H "Content-Type: application/json" \
  -H "apikey: YOUR_API_KEY" \
  -d '{
    "messaging_product": "whatsapp",
    "recipient_type": "individual",
    "to": "91XXXXXXXXXX",
    "type": "template",
    "template": {
      "name": "order_confirmation",
      "language": { "code": "en" },
      "components": [
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "Rahul" },
            { "type": "text", "text": "ORD-78542" }
          ]
        }
      ]
    }
  }'
<?php
$payload = [
    'messaging_product' => 'whatsapp',
    'recipient_type'    => 'individual',
    'to'                => '91XXXXXXXXXX',
    'type'              => 'template',
    'template'          => [
        'name'       => 'order_confirmation',
        'language'   => ['code' => 'en'],
        'components' => [
            [
                'type'       => 'body',
                'parameters' => [
                    ['type' => 'text', 'text' => 'Rahul'],
                    ['type' => 'text', 'text' => 'ORD-78542'],
                ],
            ],
        ],
    ],
];

$ch = curl_init('<WHATSAPP_SERVICE_URL>/v3/PHONE_NUMBER_ID/messages');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'apikey: YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => json_encode($payload),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

echo $response['messages'][0]['id'];
import requests

response = requests.post(
    "<WHATSAPP_SERVICE_URL>/v3/PHONE_NUMBER_ID/messages",
    headers={"apikey": "YOUR_API_KEY"},
    json={
        "messaging_product": "whatsapp",
        "recipient_type": "individual",
        "to": "91XXXXXXXXXX",
        "type": "template",
        "template": {
            "name": "order_confirmation",
            "language": {"code": "en"},
            "components": [
                {
                    "type": "body",
                    "parameters": [
                        {"type": "text", "text": "Rahul"},
                        {"type": "text", "text": "ORD-78542"},
                    ],
                }
            ],
        },
    },
    timeout=30,
)
print(response.json())
// Node.js 18+ (built-in fetch)
const response = await fetch('<WHATSAPP_SERVICE_URL>/v3/PHONE_NUMBER_ID/messages', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', apikey: 'YOUR_API_KEY' },
  body: JSON.stringify({
    messaging_product: 'whatsapp',
    recipient_type: 'individual',
    to: '91XXXXXXXXXX',
    type: 'template',
    template: {
      name: 'order_confirmation',
      language: { code: 'en' },
      components: [
        {
          type: 'body',
          parameters: [
            { type: 'text', text: 'Rahul' },
            { type: 'text', text: 'ORD-78542' },
          ],
        },
      ],
    },
  }),
});
console.log(await response.json());

Sample response

Every send-message endpoint on this page, template or session, returns this response. Store messages[0].id (the WhatsApp message ID, wamid) to match it with status webhooks.

JSON
{
  "messaging_product": "whatsapp",
  "contacts": [
    {
      "input": "91XXXXXXXXXX",
      "wa_id": "91XXXXXXXXXX"
    }
  ],
  "messages": [
    {
      "id": "wamid.HBgMOTE3OTcyODkyNzEyFQIAERgSQUM3MzRCRjdFREYzOENDNTgw"
    }
  ]
}

Send media template

For templates with an image, video or document header, pass the media in a header component, using link or an uploaded media id. Body parameters can also be localized currency and date_time values.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "template-name",
    "language": { "code": "language-and-locale-code" },
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "image",
            "image": { "link": "https://example.com/images/header.jpg" }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "text-string" },
          {
            "type": "currency",
            "currency": {
              "fallback_value": "$100.99",
              "code": "USD",
              "amount_1000": 100990
            }
          },
          {
            "type": "date_time",
            "date_time": {
              "fallback_value": "February 25, 1977",
              "day_of_week": 5,
              "year": 1977,
              "month": 2,
              "day_of_month": 25,
              "hour": 15,
              "minute": 33,
              "calendar": "GREGORIAN"
            }
          }
        ]
      }
    ]
  }
}

For a video or document header, replace image with video or document in both type and the object name. Returns the standard send response.

Send call-to-action template (dynamic URL)

If a template's Visit website button has a dynamic URL such as https://www.website.com/{{1}}, pass the variable part in a button component. index is the button's position in the template, starting at 0.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "{{template_name}}",
    "language": { "code": "en" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "{{text_string}}" },
          { "type": "text", "text": "{{text_string}}" },
          { "type": "text", "text": "{{text_string}}" }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": "1",
        "parameters": [
          { "type": "text", "text": "<Developer defined dynamic URL suffix>" }
        ]
      }
    ]
  }
}

Returns the standard send response.

Send quick reply template

For templates with quick reply buttons, you can attach a payload to each button. It is returned to you in the incoming-message webhook when the customer taps that button.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "{{template_name}}",
    "language": { "code": "en" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "{{text_string}}" },
          { "type": "text", "text": "{{text_string}}" }
        ]
      },
      {
        "type": "button",
        "sub_type": "quick_reply",
        "index": "0",
        "parameters": [
          { "type": "payload", "payload": "CONFIRM_BOOKING_1024" }
        ]
      },
      {
        "type": "button",
        "sub_type": "quick_reply",
        "index": "1",
        "parameters": [
          { "type": "payload", "payload": "CANCEL_BOOKING_1024" }
        ]
      }
    ]
  }
}

Returns the standard send response.

Send media template with multiple buttons

Templates can mix quick reply, URL and phone buttons. Only pass parameters for the parts that are variable: the media header, body variables and any dynamic URL buttons. Static buttons need no parameters.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
{
  "messaging_product": "whatsapp",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "multiple_button_template_image01",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "image",
            "image": { "link": "https://example.com/images/header.jpg" }
          }
        ]
      }
    ]
  }
}
{
  "messaging_product": "whatsapp",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "multiple_button_template_image_dya_ph1",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "image",
            "image": { "link": "https://example.com/images/header.jpg" }
          }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": 8,
        "parameters": [
          { "type": "text", "text": "get-started" }
        ]
      }
    ]
  }
}

In the dynamic URL example, the URL button is the ninth button in the template, so its index is 8. Returns the standard send response.

Send coupon code template

For templates with a Copy code button, pass the coupon in a copy_code button component. The customer can copy it with one tap.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "copycode_07",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "25OFF" },
          { "type": "text", "text": "25%" }
        ]
      },
      {
        "type": "button",
        "sub_type": "copy_code",
        "index": 0,
        "parameters": [
          { "type": "coupon_code", "coupon_code": "25OFF" }
        ]
      }
    ]
  }
}

Returns the standard send response.

Send multi-product (MPM) template

Sends an approved multi-product template that opens a selection of products from your catalogue. thumbnail_product_retailer_id sets the product image shown on the message.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "mpm_25nov1",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "text", "text": "Pablo" }
        ]
      },
      {
        "type": "body",
        "parameters": []
      },
      {
        "type": "button",
        "sub_type": "mpm",
        "index": 0,
        "parameters": [
          {
            "type": "action",
            "action": {
              "thumbnail_product_retailer_id": "61",
              "sections": [
                {
                  "title": "Popular Bundles",
                  "product_items": [
                    { "product_retailer_id": "61" },
                    { "product_retailer_id": "63" }
                  ]
                },
                {
                  "title": "Premium Packages",
                  "product_items": [
                    { "product_retailer_id": "64" }
                  ]
                }
              ]
            }
          }
        ]
      }
    ]
  }
}

Returns the standard send response.

Send limited-time offer template

Limited-time offer templates show a countdown. Set the expiry in expiration_time_ms as a Unix timestamp in milliseconds. This example also passes a coupon code and a dynamic URL suffix.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "limited_time_offer_dec12",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "image", "image": { "id": "{{media_id}}" } }
        ]
      },
      {
        "type": "body",
        "parameters": []
      },
      {
        "type": "limited_time_offer",
        "parameters": [
          {
            "type": "limited_time_offer",
            "limited_time_offer": { "expiration_time_ms": 1699400090000 }
          }
        ]
      },
      {
        "type": "button",
        "sub_type": "copy_code",
        "index": 0,
        "parameters": [
          { "type": "coupon_code", "coupon_code": "CARIBE25" }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": 1,
        "parameters": [
          { "type": "text", "text": "n3mtql" }
        ]
      }
    ]
  }
}

Returns the standard send response.

Custom tracking data

Add biz_opaque_callback_data to any send request to attach your own reference, such as an order ID, campaign name or template ID. It isn't shown to the customer. It is returned unchanged in the sent, delivered and read status webhooks, so you can track each customer journey or compare the performance of different templates. Maximum 512 characters.

JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "template",
  "template": {
    "name": "order_confirmation",
    "language": { "code": "en" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Rahul" },
          { "type": "text", "text": "ORD-78542" }
        ]
      }
    ]
  },
  "biz_opaque_callback_data": "{\"source\":\"api\",\"date\":\"2024-03-01\",\"uuid\":\"fuif-0deu-dgyu-5674\"}"
}

Send text message

Session messages only work within the 24-hour window. This and the following message types are delivered only if the customer has messaged you in the last 24 hours. To contact a customer first, send a template message.

Sends a plain text message. Set preview_url to true to show a preview of the first link in the message.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages

Sample request

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "text",
  "text": {
    "preview_url": false,
    "body": "Hello! Your order has been shipped."
  }
}
curl -X POST "<WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages" \
  -H "Content-Type: application/json" \
  -H "apikey: YOUR_API_KEY" \
  -d '{
    "messaging_product": "whatsapp",
    "recipient_type": "individual",
    "to": "91XXXXXXXXXX",
    "type": "text",
    "text": { "preview_url": false, "body": "Hello! Your order has been shipped." }
  }'

Returns the standard send response. For PHP, Python and Node.js, use the template samples with this JSON body.

Send image, document & video

Send media from a public HTTPS URL with link, or from a file you've uploaded with id. Set type to image, document or video and use the matching object.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages

Sample request

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "image",
  "image": {
    "link": "https://example.com/images/offer.jpg",
    "caption": "Our new collection is here!"
  }
}
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "document",
  "document": {
    "link": "https://example.com/invoices/INV-1024.pdf",
    "caption": "Your invoice for order #1024"
  }
}
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "video",
  "video": {
    "link": "https://example.com/videos/product-demo.mp4",
    "caption": "Watch how it works"
  }
}
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "image",
  "image": {
    "id": "{{media_id}}",
    "caption": "Our new collection is here!"
  }
}

Returns the standard send response.

Send location message

Sends a map pin with an optional name and address.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "location",
  "location": {
    "latitude": "12.9716",
    "longitude": "77.5946",
    "name": "Our Bengaluru Store",
    "address": "MG Road, Bengaluru, Karnataka 560001"
  }
}

Returns the standard send response.

Send contact message

Shares one or more contact cards. Only name.formatted_name is required. Include the other fields you need.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "to": "91XXXXXXXXXX",
  "type": "contacts",
  "contacts": [
    {
      "addresses": [
        {
          "street": "<ADDRESS_STREET>",
          "city": "<ADDRESS_CITY>",
          "state": "<ADDRESS_STATE>",
          "zip": "<ADDRESS_ZIP>",
          "country": "<ADDRESS_COUNTRY>",
          "country_code": "<ADDRESS_COUNTRY_CODE>",
          "type": "<HOME|WORK>"
        }
      ],
      "birthday": "<CONTACT_BIRTHDAY>",
      "emails": [
        { "email": "<CONTACT_EMAIL>", "type": "<WORK|HOME>" }
      ],
      "name": {
        "formatted_name": "<CONTACT_FORMATTED_NAME>",
        "first_name": "<CONTACT_FIRST_NAME>",
        "last_name": "<CONTACT_LAST_NAME>",
        "middle_name": "<CONTACT_MIDDLE_NAME>",
        "suffix": "<CONTACT_SUFFIX>",
        "prefix": "<CONTACT_PREFIX>"
      },
      "org": {
        "company": "<CONTACT_ORG_COMPANY>",
        "department": "<CONTACT_ORG_DEPARTMENT>",
        "title": "<CONTACT_ORG_TITLE>"
      },
      "phones": [
        { "phone": "<CONTACT_PHONE>", "wa_id": "<CONTACT_WA_ID>", "type": "<HOME|WORK>" }
      ],
      "urls": [
        { "url": "<CONTACT_URL>", "type": "<HOME|WORK>" }
      ]
    }
  ]
}

Returns the standard send response.

Send interactive list message

Shows a button that opens a menu of options grouped into sections. When the customer picks a row, you receive its id in the incoming-message webhook.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "list",
    "header": { "type": "text", "text": "Choose a plan" },
    "body": { "text": "Pick the plan that suits you best." },
    "footer": { "text": "FOOTER_TEXT" },
    "action": {
      "button": "View plans",
      "sections": [
        {
          "title": "SECTION_1_TITLE",
          "rows": [
            { "id": "SECTION_1_ROW_1_ID", "title": "SECTION_1_ROW_1_TITLE", "description": "SECTION_1_ROW_1_DESCRIPTION" },
            { "id": "SECTION_1_ROW_2_ID", "title": "SECTION_1_ROW_2_TITLE", "description": "SECTION_1_ROW_2_DESCRIPTION" }
          ]
        },
        {
          "title": "SECTION_2_TITLE",
          "rows": [
            { "id": "SECTION_2_ROW_1_ID", "title": "SECTION_2_ROW_1_TITLE", "description": "SECTION_2_ROW_1_DESCRIPTION" },
            { "id": "SECTION_2_ROW_2_ID", "title": "SECTION_2_ROW_2_TITLE", "description": "SECTION_2_ROW_2_DESCRIPTION" }
          ]
        }
      ]
    }
  }
}

Returns the standard send response.

Send location request message

Shows a Send location button that asks the customer to share their current location.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "location_request_message",
    "body": {
      "text": "Let us start with your pickup. You can either manually *enter an address* or *share your current location*."
    },
    "action": {
      "name": "send_location"
    }
  }
}

Returns the standard send response.

Send address message

Opens a form in WhatsApp that lets the customer fill in a delivery address. Address messages are currently supported in India (IN) and Singapore (SG).

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "address_message",
    "body": {
      "text": "Thanks for your order! Tell us what address you'd like this order delivered to."
    },
    "action": {
      "name": "address_message",
      "parameters": {
        "country": "IN"
      }
    }
  }
}

Address form fields

FieldDisplay labelInput typeCountriesLimitations
name Name text India, Singapore —
phone_number Phone Number tel India, Singapore Valid phone numbers only
in_pin_code Pin Code text India Max length: 6
sg_post_code Post Code number Singapore Max length: 6
house_number Flat/House Number text India —
floor_number Floor Number text India —
tower_number Tower Number text India —
building_name Building/Apartment Name text India —
address Address text India, Singapore —
landmark_area Landmark/Area text India —
unit_number Unit number text Singapore —
city City text India, Singapore —
state State text India —

Returns the standard send response.

Send single product message

Shows one product from your Meta commerce catalogue. Requires a catalogue connected to your WhatsApp Business Account.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "product",
    "body": { "text": "text-body-content" },
    "footer": { "text": "text-footer-content" },
    "action": {
      "catalog_id": "{{catalog_id}}",
      "product_retailer_id": "{{retailer_id}}"
    }
  }
}

Returns the standard send response.

Send multi-product message

Shows several products from your catalogue, grouped into sections.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "product_list",
    "header": { "type": "text", "text": "Our bestsellers" },
    "body": { "text": "Browse this week's top picks." },
    "footer": { "text": "Prices include GST" },
    "action": {
      "catalog_id": "{{catalog_id}}",
      "sections": [
        {
          "title": "{{section_title}}",
          "product_items": [
            { "product_retailer_id": "{{retailer_id}}" },
            { "product_retailer_id": "{{retailer_id}}" }
          ]
        },
        {
          "title": "{{section_title}}",
          "product_items": [
            { "product_retailer_id": "{{retailer_id}}" },
            { "product_retailer_id": "{{retailer_id}}" }
          ]
        }
      ]
    }
  }
}

Returns the standard send response.

Send order details (payment)

Sends an order summary with a Review and pay button so the customer can pay inside WhatsApp through your connected payment gateway (razorpay or payu). Amounts are sent as value and offset, where the actual amount is value ÷ offset. For example, value: 100, offset: 100 is ₹1.00.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "order_details",
    "header": {
      "type": "image",
      "image": { "link": "https://example.com/images/product.jpg" }
    },
    "body": { "text": "Test payment" },
    "footer": { "text": "Thank you for shopping with us" },
    "action": {
      "name": "review_and_pay",
      "parameters": {
        "reference_id": "EZV2023032712042512044720",
        "type": "digital-goods",
        "currency": "INR",
        "total_amount": { "value": 100, "offset": 100 },
        "payment_settings": [
          {
            "type": "payment_gateway",
            "payment_gateway": {
              "type": "razorpay",
              "configuration_name": "payment-config-id"
            }
          }
        ],
        "order": {
          "status": "pending",
          "items": [
            {
              "retailer_id": "R1",
              "product_id": "product-id",
              "name": "Test Payment Rs. 1",
              "amount": { "value": 100, "offset": 100 },
              "quantity": 1
            }
          ],
          "subtotal": { "value": 100, "offset": 100 },
          "tax": { "value": 0, "offset": 100 }
        }
      }
    }
  }
}

Returns the standard send response.

Send order status

Updates the customer on an order you sent earlier. Use the same reference_id. Set order.status to completed or canceled.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/messages
JSON
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "91XXXXXXXXXX",
  "type": "interactive",
  "interactive": {
    "type": "order_status",
    "body": { "text": "Your payment could not be completed." },
    "action": {
      "name": "review_order",
      "parameters": {
        "reference_id": "EZV2023032712042512044720",
        "order": {
          "status": "canceled",
          "description": "Payment failed"
        }
      }
    }
  }
}

Returns the standard send response.

Upload media

Uploads a file and returns a media ID you can use in messages instead of a public link. Send the file as multipart/form-data in a field named sheet.

POST <WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/media
cURL
curl -X POST "<WHATSAPP_SERVICE_URL>/v3/{{phone_number_id}}/media" \
  -H "apikey: YOUR_API_KEY" \
  -F "sheet=@/path/to/file.jpg"

Sample response

JSON
{
  "response": {
    "id": "{{media_id}}"
  }
}

Get & download media

Use these endpoints to fetch media files, for example images or documents your customers send you.

Download media directly

Returns the media file itself.

POST <WHATSAPP_SERVICE_URL>/v3/downloadMedia/{{media_id}}?phone_number_id={{phone_number_id}}

Get media URL

Returns a temporary URL and details for a media file.

GET <WHATSAPP_SERVICE_URL>/v3/{{media_id}}?phone_number_id={{phone_number_id}}
JSON
{
  "url": "<WHATSAPP_SERVICE_URL>/v3/whatsapp_business/attachments/?mid=7609700182448254&ext=1716536800&hash=ATtFkAs7t1xlhx9wik43m7NBRARfMzfh6Vi_IvgzzxkQsQ",
  "mime_type": "image/png",
  "sha256": "ee490eac2a7b038413ab2fb0bfc6db02d9a68e015d92e917fbcee9e324a96810",
  "file_size": 436484,
  "id": "7609700182448254",
  "messaging_product": "whatsapp"
}

Download from media URL

Call the url returned above with your apikey header to download the file.

GET <WHATSAPP_SERVICE_URL>/v3/whatsapp_business/attachments/?mid=...&ext=...&hash=...

Delete media

DELETE <WHATSAPP_SERVICE_URL>/v3/{{media_id}}?phone_number_id={{phone_number_id}}
JSON
{ "success": true }

Media file handle (for templates)

When you create a template with an image, video or document header, Meta needs a sample file, passed as a file handle in header_handle. Get one in two steps.

Step 1: Create an upload session

Pass the file size in bytes and its MIME type.

POST <WHATSAPP_SERVICE_URL>/v3/app/uploads?file_length=164313&file_type=video/mp4
JSON
{
  "id": "upload:MTphdHRhY2htZW50OjNlYTE1ZTkzLTZkZDktNGIwOS1iOTM3...?sig=ARbUFIDlNcIbRnOalIY"
}

Step 2: Upload the file

Send the file as the raw binary request body to the session ID returned in step 1. The response contains the file handle h.

POST <WHATSAPP_SERVICE_URL>/v3/{{upload_session_id}}
cURL
curl -X POST "<WHATSAPP_SERVICE_URL>/v3/upload:MTphdHRhY2htZW50...?sig=ARbUFIDlNcIbRnOalIY" \
  -H "apikey: YOUR_API_KEY" \
  --data-binary "@/path/to/video.mp4"
JSON
{
  "h": "4::dmlkZW8vbXA0:ARa3wu4QWKmzupRJa-dmysHBZrmo4TxDVwJgvvtbhvqMqPb-UC..."
}

Create template

Submits a new message template to Meta for approval. The response status can be APPROVED, PENDING or REJECTED. Read the template guidelines to avoid rejections.

POST <WHATSAPP_SERVICE_URL>/v3/{{waba_id}}/message_templates

Request fields

ParameterRequiredDescription
name Yes Template name: lowercase letters, numbers and underscores only.
category Yes MARKETING, UTILITY or AUTHENTICATION.
language Yes Language code, e.g. en_US, en or hi.
components Yes Array of HEADER, BODY, FOOTER and BUTTONS components. Only BODY is required.
allow_category_change No true lets Meta assign the correct category instead of rejecting the template.

Components

ComponentDetails
HEADER format: TEXT, IMAGE, VIDEO or DOCUMENT. A text header can contain one variable, with a sample in example.header_text. Media headers need a sample file handle in example.header_handle. See media file handle.
BODY Main message text. Variables are written {{1}}, {{2}}, … with sample values in example.body_text.
FOOTER Short text shown below the body.
BUTTONS Up to 10 buttons: QUICK_REPLY, URL (static or with one {{1}} at the end, with an example), PHONE_NUMBER and COPY_CODE.

Sample requests

{
  "name": "welcome_message_v1",
  "category": "MARKETING",
  "language": "en_US",
  "allow_category_change": true,
  "components": [
    {
      "type": "HEADER",
      "format": "TEXT",
      "text": "Welcome {{1}}",
      "example": { "header_text": ["Rahul"] }
    },
    {
      "type": "BODY",
      "text": "Dear {{1}}, thank you for registering with {{2}} and providing consent to receive notifications on WhatsApp.\n\nPlease save this number. Reply HELP to get started or STOP to unsubscribe.",
      "example": { "body_text": [["Rahul", "Company"]] }
    },
    {
      "type": "FOOTER",
      "text": "Welcome to Company"
    },
    {
      "type": "BUTTONS",
      "buttons": [
        { "type": "QUICK_REPLY", "text": "button1" },
        { "type": "QUICK_REPLY", "text": "button2" },
        { "type": "QUICK_REPLY", "text": "button3" }
      ]
    }
  ]
}
{
  "name": "welcome_message_cta_v1",
  "category": "MARKETING",
  "language": "en_US",
  "allow_category_change": true,
  "components": [
    {
      "type": "HEADER",
      "format": "TEXT",
      "text": "Welcome {{1}}",
      "example": { "header_text": ["Rahul"] }
    },
    {
      "type": "BODY",
      "text": "Thank you for registering with Company and providing consent to receive notifications on WhatsApp."
    },
    {
      "type": "FOOTER",
      "text": "Welcome to Company"
    },
    {
      "type": "BUTTONS",
      "buttons": [
        { "type": "PHONE_NUMBER", "text": "Call us", "phone_number": "+9199XXXXXXXX" },
        {
          "type": "URL",
          "text": "Click",
          "url": "https://www.website.com/{{1}}",
          "example": ["dynamic-url-example"]
        }
      ]
    }
  ]
}
{
  "name": "sample_image_template_1",
  "category": "MARKETING",
  "language": "en_US",
  "allow_category_change": true,
  "components": [
    {
      "type": "HEADER",
      "format": "IMAGE",
      "example": {
        "header_handle": ["4::aW1hZ2UvanBlZw==:ARZsON6K-8ukPIq2h95wJ9UUCr439vX2odOWPJ0TjP..."]
      }
    },
    {
      "type": "BODY",
      "text": "Hey user,\nWelcome to the Company.\n\nRegards,\nCompany"
    },
    {
      "type": "FOOTER",
      "text": "Reply STOP to unsubscribe"
    },
    {
      "type": "BUTTONS",
      "buttons": [
        { "type": "QUICK_REPLY", "text": "Button1" },
        { "type": "QUICK_REPLY", "text": "Button2" },
        { "type": "QUICK_REPLY", "text": "Button3" },
        { "type": "URL", "text": "Visit", "url": "https://www.website.com/" },
        { "type": "PHONE_NUMBER", "text": "Call", "phone_number": "+9199XXXXXXXX" }
      ]
    }
  ]
}

For video or document headers, change format to VIDEO or DOCUMENT and upload a sample file of that type. For a dynamic URL button, use a URL ending in {{1}} with an example, as shown in the second sample.

Sample response

JSON
{
  "id": "123412341234123",
  "status": "APPROVED",
  "category": "MARKETING"
}

Get templates

Get all templates

Returns every template on your WhatsApp Business Account with its status and components.

GET <WHATSAPP_SERVICE_URL>/v3/{{waba_id}}/message_templates
JSON
{
  "data": [
    {
      "name": "ltotemp36013m103",
      "components": [
        { "type": "BODY", "text": "Hey User, check out our Caribbean packages!" },
        {
          "type": "LIMITED_TIME_OFFER",
          "limited_time_offer": { "text": "Expiring offer!", "has_expiration": true }
        },
        {
          "type": "BUTTONS",
          "buttons": [
            { "type": "COPY_CODE", "text": "Copy offer code", "example": ["CARIBE25"] },
            { "type": "URL", "text": "Click", "url": "https://www.website.com/{{1}}", "example": ["dynamic-url-example"] },
            { "type": "PHONE_NUMBER", "text": "call", "phone_number": "+9199XXXXXXXX" }
          ]
        }
      ],
      "language": "en_US",
      "status": "APPROVED",
      "category": "MARKETING",
      "id": "2883983598406625"
    }
  ]
}

Get template by ID

Returns a single template object, in the same format as one item of the list above.

GET <WHATSAPP_SERVICE_URL>/v3/{{template_id}}

Edit template

Updates a template's components or category. If a template was REJECTED, for example during category validation, you can edit its components, change its category, or create a new template.

POST <WHATSAPP_SERVICE_URL>/v3/{{template_id}}
{
  "name": "image_v3_2",
  "category": "MARKETING",
  "language": "en_US",
  "allow_category_change": true,
  "components": [
    {
      "type": "header",
      "format": "image",
      "example": { "header_handle": ["4::aW1hZ2UvanBlZw==:ARaL3BstEF5_AxgQlJNl2Th3WNWDgRR..."] }
    },
    { "type": "body", "text": "Hey user,\nWelcome to the Company.\n\nRegards,\nCompany" },
    { "type": "footer", "text": "Reply STOP to unsubscribe" },
    {
      "type": "buttons",
      "buttons": [
        { "type": "quick_reply", "text": "Button1" },
        { "type": "quick_reply", "text": "Button2" },
        { "type": "url", "text": "click", "url": "https://www.website.com/" },
        { "type": "phone_number", "text": "Call", "phone_number": "+9199XXXXXXXX" }
      ]
    }
  ]
}
{ "category": "MARKETING" }

Sample response

JSON
{ "success": true }

Delete template

Delete by name

Deletes every language version of the template with this name.

DELETE <WHATSAPP_SERVICE_URL>/v3/{{waba_id}}/message_templates?name={{template_name}}

Delete by name and ID

Deletes only the template with this ID.

DELETE <WHATSAPP_SERVICE_URL>/v3/{{waba_id}}/message_templates?hsm_id={{template_id}}&name={{template_name}}

Sample response

JSON
{ "success": true }

Get account details

Returns the WhatsApp numbers on your account with their WhatsApp Business Account ID ({{waba_id}}) and phone number ID ({{phone_number_id}}). Call this first to get the IDs used by the other endpoints.

GET <WHATSAPP_SERVICE_URL>/v3/getuserdetails
JSON
{
  "code": 200,
  "status": "SUCCESS",
  "data": [
    {
      "wanumber": "+9199XXXXXXXX",
      "whatsapp_business_account_id": "100249586351323",
      "phone_number_id": "111266881902966"
    },
    {
      "wanumber": "+9199XXXXXXXX",
      "whatsapp_business_account_id": "100249586351323",
      "phone_number_id": "112672835072002"
    }
  ]
}

Status webhooks

To receive message status updates (sent, delivered, read, failed) and incoming customer messages on your server, share a publicly reachable HTTPS callback URL with SpringEdge support. Events are POSTed to it as JSON in Meta's webhook format. Match status updates to your messages using statuses[].id (the wamid returned when sending) or your custom tracking data.

Sample status webhook

JSON
{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "112365665238904",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "91XXXXXXXXXX",
              "phone_number_id": "10XXXXXXXXXXXXXX"
            },
            "statuses": [
              {
                "id": "wamid.HBgMOTE3NTA3MDY2MzMxFQIAERgSQzZGNUVFOTgxMUUyMkI3MzVBAA==",
                "status": "delivered",
                "timestamp": "1709295133",
                "recipient_id": "91XXXXXXXXXX",
                "biz_opaque_callback_data": "{\"source\":\"api\",\"date\":\"2024-03-01\",\"uuid\":\"fuif-0deu-dgyu-5674\"}",
                "conversation": {
                  "id": "a34a10abd87c7badad4d1fc5bafadd71",
                  "origin": { "type": "marketing" }
                },
                "pricing": {
                  "billable": true,
                  "pricing_model": "CBP",
                  "category": "marketing"
                }
              }
            ]
          },
          "field": "messages"
        }
      ]
    }
  ]
}

Help & support

Need your <WHATSAPP_SERVICE_URL>, a webhook set up, help with template approval or an integration? Email contact@springedge.com or contact us.