Messaging
Conversations / WhatsApp
WhatsApp is the second channel of Conversations (channel_type 2). It is sent through the same thread endpoints as SMS, with three WhatsApp rules on top: the sender is a phone number connected to a Meta business account, a conversation that has had no inbound message for 24 hours accepts approved templates only, and media is moderated before it leaves. This group holds the template and media endpoints; the sender itself is connected in the portal.
Before your first message
- Add-on and sender: the account needs the WhatsApp for Business add-on and at least one connected number. Both are set up in the portal under Integrations → WhatsApp for Business: payment, a Twilio sub-account and Meta's Embedded Signup run in the browser, so those endpoints are not part of the public reference. Accounts that bring their own Twilio carrier (BYOC) cannot use WhatsApp.
- Find your senders:
GET /v2/sms/sender_names?filter[channel]=whatsapplists the connected numbers;sender_nameis the value to send assender_id. Up to 10 numbers per account. - Token: the template and media endpoints need an account admin token. Without an active sender every endpoint of this group answers
403"No active WhatsApp sender found for your account".
Templates (what the portal does)
- List:
GET /v2/integrations/whatsapp/templates(status,category,language,search,page,per_pageup to 100) or the sharedGET /v2/sms-templates?filter[channel]=2, which is what the portal's template picker uses (filter[status]=1for sendable ones,filter[exclude_dynamic_variables]=truefor automations that cannot fill placeholders). - Create:
POST /v2/integrations/whatsapp/templateswithname,category(1 Authentication, 2 Marketing, 3 Utility: Meta prices and reviews them differently),language,sender_id,body(textwith{{1}}…{{N}}and one sample per placeholder invariables), optionalheader(typetext, image, video or document; media as amedia_idfrom the upload endpoint, a publicmedia_urlor an inlinemediafile),footerand up to 10buttons. The template is created locally with status 6 (Not Submitted);submit_after_approval: truesubmits it as soon as its header media passes moderation. - Edit or delete:
PUTis allowed whilepermissions.can_editis true (Not Submitted, Rejected, Disabled or Media Rejected); an approved template is immutable, create a new one.DELETEworks in every status and also removes the template from Twilio. - Submit:
POST /v2/integrations/whatsapp/templates/{smsTemplate}/submitsends it to Meta.200withstatus: "submitted"and thetemplate_sid;202withstatus: "pending_submit"when the header media is still being moderated (it is submitted automatically afterwards);403when the template is already approved or pending;422when a placeholder has no sample. - Wait for approval: Meta decides asynchronously, usually within minutes, sometimes a day. Poll
GET …/templates/{smsTemplate}:statusis an integer andstatus_labelits text: 0 Pending (submitted, awaiting Meta's review), 1 Approved, 2 Error (the submission failed;status_labelreads "Unknown"), 3 Rejected, 4 Disabled, 5 Paused, 6 Not Submitted, 7 Pending Moderation (header media still being checked), 8 Pending Submit (queued for submission), 9 Media Rejected, 10 Deleted from Twilio (removed on the provider side; create a new one). Only 1 can be sent. An approved template can later become Paused or Disabled by Meta for quality reasons.
Template lifecycle
stateDiagram-v2
[*] --> NotSubmitted: created locally (status 6 Not Submitted)
NotSubmitted --> PendingModeration: submit_after_approval, header media uploaded (status 7)
PendingModeration --> PendingSubmit: media approved (status 8)
PendingModeration --> MediaRejected: media rejected (status 9)
PendingSubmit --> Pending: auto-submitted to Meta (status 0)
NotSubmitted --> Pending: POST …/submit, 200 submitted (status 0)
NotSubmitted --> PendingSubmit: POST …/submit, 202 pending_submit (status 8)
Pending --> Approved: Meta approves (status 1)
Pending --> Rejected: Meta rejects (status 3)
Pending --> Error: submission failed (status 2)
Approved --> Paused: Meta pauses for quality (status 5)
Approved --> Disabled: Meta disables (status 4)
Rejected --> [*]: DELETE, create a new one
MediaRejected --> [*]: DELETE, create a new one
Approved --> [*]: Deleted from Twilio (status 10)
Media
- Upload:
POST /v2/integrations/whatsapp/media(multipartfile; JPEG, PNG, MP4, AAC, MP3, AMR, 3GP, PDF, DOC, DOCX, PPTX, XLSX, VCF; 16 MB, images 5 MB) answersmedia_id, a signed previewurl,type,message_typeandmoderation_status. Images and videos are moderated asynchronously (pending→approvedorrejected); audio and documents are approved on upload. Rejected media cannot be sent or used in a template header. Template headers accept JPEG, PNG, MP4 and PDF only; an inlineheader.mediafile is checked on its real MIME type, not its extension, and the same 16 MB / 5 MB limits apply. - Read: an inbound or outbound file is the message's single
attachments[]entry (id,content_url,thumbnail_url,media_type,mime_type,file_size,filename), andcontent_urlandthumbnail_urlare repeated on the message itself.content_urlis a signed URL that expires.GET /v2/whatsapp/media/{media}/download-urlwith the attachment'sidissues a fresh one:200withurl(valid for 15 minutes, usable directly in<img>,<video>and<audio>, no token needed),expires_at,media_typeandmime_type;202withstatus: "pending"while the file is still being moderated, so poll until200;403when it was rejected or belongs to another account;404when the id does not exist. - Previews: for an image or video NUACOM also builds a JPEG thumbnail of at most 320 × 320 px in the background.
thumbnail_urlis a signed link that needs no token and stays the same until the end of the calendar year, so it can be cached; it answers404until the thumbnail exists and403once the media is rejected. It isnullfor audio, documents and messages without media.
Sending
- Start or reply with
POST /v2/conversations(channel_type: 2,sender_id, oneparticipants[]entry of typephone_number) orPOST /v2/conversations/{conversation}/messages. A message is exactly one of: text incontent; media ascontent_url(a public URL NUACOM downloads and re-hosts),content_file(multipart) or amedia_id-backed upload, withcontentas the caption; a template asmetadata.template_idplusmetadata.template_variables(one value per{{N}}, in order); a location asmetadata.location(latitude,longitude,label). The answer is201with the message. - The 24-hour window: a contact's inbound message opens a window that ends 24 hours after their last message;
expires_aton the conversation shows when. Inside it any message type is allowed; outside it the API answers422(metadata.template_id"The Customer Service Window is closed…", orerror: WHATSAPP_CSW_CLOSEDon a new conversation) unless the message is an approved template. Templates can always be sent and reopen the conversation. - Campaigns:
POST /v2/sms/overviewwithchannel_type: 2,wa_template_idandwa_parameters(JSON keyed by placeholder number) quotes a WhatsApp campaign and flags numbers that cannot receive WhatsApp as invalid; the portal's New Message page then sends the staged draft. Through the API, send to each recipient withPOST /v2/conversations. - Scheduling uses
scheduled_forlike SMS; a scheduled message is cancellable until delivery.
Reading and delivery
- Threads and messages come from
GET /v2/conversations(channel=2) andGET /v2/conversations/{conversation};statuses[]move through sent, delivered and read as Meta reports them; afailedstatus refunds the message. An inbound file that could not be fetched arrives withmetadata.media_error.code(MEDIA_TOO_LARGEabove about 16 MB,MEDIA_TOO_LARGE_PROVIDERwhen Twilio rejected it,UNSUPPORTED_MEDIA_TYPE,MEDIA_DOWNLOAD_FAILED,MEDIA_PROCESSING_FAILED). message_receivedandmessage_sentwebhooks fire for WhatsApp as for SMS.
Pricing
Each message is charged at request time (scheduled messages at delivery, Marketing and Authentication templates up front) from the SMS balance at the WhatsApp rate of the recipient's country, by category: a Marketing or Authentication template at its own rate; a Utility template and a free-form message at the cheaper "service" rate while the 24-hour window is open, the Utility rate outside it. GET /v2/account/messaging-rates?country_code= lists them per wa_message_type. A message Meta reports as failed or undelivered is refunded once. 402 means the balance is empty.
Roles and access
- Template and media endpoints: account admin with the WhatsApp for Business add-on and an active sender. Reading and sending through Conversations: any authenticated user on an account with the add-on.
- Without the add-on WhatsApp messages are also hidden from the conversation and inbox endpoints.
Pitfalls
- Recipients are phone numbers today (
participant_type: phone_number, international format). Meta is rolling out WhatsApp usernames: a contact who hides their number will arrive with a business-scoped id instead, so do not parseparticipant_idas a phone number. statusandcategoryare integers on the WhatsApp endpoints;template_idinmetadatais the integeridof the template, not itstemplate_sid.- A template's placeholders are positional: send
template_variablesin{{1}},{{2}}order with every value present, or the send is rejected. content_urlmust be fetchable by NUACOM without authentication; it is downloaded, moderated and re-hosted, so a private or expiring link fails with422.- Inbound files larger than about 95 MB never reach NUACOM: Meta drops them with no error on either side, so tell contacts the limit.
- A sender number must not be in use on another WhatsApp Business account; connecting it moves it. Removing a number in the portal ends its threads' sending ability but keeps the history.