Skip to main content
POST
cURL (Windows)
Best effort. Many WhatsApp clients no longer render interactive messages and will show a plain-text fallback instead. A 200 means the message was accepted for delivery — not that the buttons will appear. The response carries "best_effort": true to say so explicitly. Read Buttons and lists are best-effort before you build anything on this.
The playground on this page is live. There is no test mode and no sandbox: pressing Send authenticates with the key you paste and really calls https://api.bulkneo.com — a send delivers a real WhatsApp message to the number you type, and an instance call really changes your account. Use your own number while you are exploring, and paste a key only from a machine you trust.Your browser remembers what you type into the playground, so a key you paste here is still in the Authorization box on your next visit. Nobody else sees it — it never leaves your machine and it is not part of this site — but on a shared or borrowed computer, clear the site data when you are done.

Notes

  • 1 to 3 buttons. WhatsApp will not render more than three.
  • title is required, up to 1,024 characters. description (up to 1,024) and footer (up to 60) are optional.
  • text is the button label, 1–24 characters, required on every button.
Each type needs one extra field: Only reply, url and call are accepted. Sending anything else returns 400 invalid_request listing the allowed values.

Example

The response

You cannot receive the tap. When someone presses a reply button, the response goes into the WhatsApp conversation — there is no webhook and no endpoint that delivers it to your system. If you need the answer in software, ask for a typed reply instead.

Authorizations

apikey
string
header
required

Your API key, sent in an apikey request header. Never in the URL, never as a Bearer token.

Headers

Idempotency-Key
string

OPTIONAL. A unique string you choose, 8-255 characters of letters, digits or . _ : ~ -

Send the same key with the same body again within 24 hours and the ORIGINAL result is returned without sending a second message — which is what makes a network retry safe. A different body on the same key is refused with 422 idempotency_key_reused rather than silently overwriting either result.

Responses carry Idempotency-Replayed: true|false while this is active. If that header is ABSENT, idempotency is not enabled on this deployment and retries will send again.

Required string length: 8 - 255
Pattern: ^[A-Za-z0-9._:~-]{8,255}$

Body

application/json
instance_id
string<uuid>
required

Which of your connected numbers to send FROM. Copy it from your numbers screen in the portal, or from GET /v1/instances. It must belong to your account.

Example:

"3f9c1a2b-7d4e-4c81-9f0a-2b6d5e8c1a34"

to
string
required

The recipient, with country code and no leading zero — for example 919000000000. Spaces, dashes, brackets and a leading + are accepted and stripped; 6 to 15 digits must remain.

Example:

"919000000000"

title
string
required

Heading of the message.

Required string length: 1 - 1024
Example:

"Confirm your order"

buttons
object[]
required

1 to 3 buttons. WhatsApp will not render more than three.

Required array length: 1 - 3 elements
description
string

Body text under the title.

Maximum string length: 1024
Example:

"Order #2043 — ₹1,299"

Small print under the buttons. Up to 60 characters.

Maximum string length: 60
quoted_message_id
string

Send this message as a reply, quoting an earlier one. Use the data.message_id returned by a previous send.

Maximum string length: 128
Example:

"3EB0C1D2F4A5B6C7D8E9"

quoted_from_me
boolean
default:false

Set true when the quoted message is one you sent from this number. Only valid together with quoted_message_id.

Response

Accepted for delivery — best effort. data.type is always buttons on this endpoint. best_effort and note are on every interactive response, because whether the recipient's WhatsApp renders it is outside anyone's control.

success
boolean
data
object
request_id
string<uuid>