Versioning policy
The major version is in the URL. Today there is one, /v1. A new major version would run beside the old one for at least 12 months.
What can change with no notice
A new endpoint, a new optional request field or parameter, a new response field, a new webhook event, a new field on an event, a new value in a response enum, and a new error code for a new condition. Your code must ignore fields and enum values it does not know.
What needs notice
Removing or renaming an endpoint, a parameter, a response field, an event or an event field. Changing a type. Making an optional field required. Tightening validation so a request that worked now fails. Changing what an existing status code or error code means. Changing how webhooks are signed.
How much notice
At least 180 days between the day a deprecation is announced and the day it is removed. The one exception is a security fix, which can be shorter and is announced the same day with the reason. A surface marked beta gets 30 days.
How you hear about it
An entry on this changelog with the sunset date. deprecated, x-sunset and x-replacement in the OpenAPI spec. Deprecation, Sunset and Link headers on every response from a deprecated endpoint. A deprecated mark in the webhook event catalogue. A note beside the item in the API reference.
November 2026
Added 2026-11-02 API 1.4.0 #
POST /v1/voice/call can answer 202 with status unknown, and its 500 voice_enqueue_failed answer is now in the contract.
A 202 means the call could not be confirmed as queued. It may still be placed, so it is not tried again and its charge stays until it settles. The body has the same fields as a queued call plus message, which says whether this was recorded and, if not, asks you to contact support with the callSid. Look the call up with GET /v1/voice/call/{callSid}. A replay with the same Idempotency-Key returns the same 202 and places nothing. This case used to answer 500 and say you were not charged. A 500 voice_enqueue_failed now means the call was not placed, and message says what happened to the charge. A 500 is not stored against the Idempotency-Key, so a retry with the same key runs the request again: read message before you retry. Nothing about a successful call changed.
Changed 2026-11-02 API 1.3.0 #
A WhatsApp failure reported after the send now returns its charge.
Applies to the same refusals as a refusal at the moment we send: a bad or unapproved template, an invalid number, a blocked recipient, on the first attempt. A message already marked delivered or read keeps its charge. The message stays failed.
Changed 2026-11-02 API 1.3.0 #
A voice call or queued WhatsApp message with no answer from the provider now ends as unknown.
It used to be retried, which could send it twice. It now ends with the status unknown, its charge stays, and it is not sent again. A voice call can still move on if the provider's status callback arrives. A provider error that is an answer, such as a 5xx or a 429, is retried as before.
Added 2026-11-02 API 1.3.0 #
Two refusals are now in the contract.
POST /v1/voice/call can answer 503 charge_unavailable when the charge could not be taken right now. Retry after the seconds in Retry-After. POST /v1/campaigns answers 400 template_not_found when the template is not approved on the account. Both are in the OpenAPI document. Nothing about a successful call changed.
Changed 2026-11-02 API 1.3.0 #
A WhatsApp message refused at the moment we send it now returns its charge.
Applies to queued template messages when WhatsApp refuses the template or the number on the first attempt. The message ends as failed and is not retried. A timeout or a provider error is not a refusal: the message is retried and the charge stays. A failure WhatsApp reports later, after it accepted the message, is not returned automatically. The response of the send is unchanged.
Changed 2026-11-02 API 1.3.0 #
POST /v1/campaigns on WhatsApp now returns one campaign id for the whole request.
The response keeps the same fields. campaignId is now camp_ followed by a full GUID, as on the sms channel, and it names the campaign on your Campaigns page, where it can be cancelled until its messages are dispatched. A cancel also stops recipients the request has not reached yet. The name in the request is shown there. Each recipient used to get a separate one-message campaign that the page could not list or cancel, and the returned id matched none of them. Campaigns sent before this change stay as they are. A campaign with one recipient counts as a single send, so the page hides it unless single sends are shown. If nothing was queued no campaign is written, so sentCount 0 means the id names nothing.
Changed 2026-11-02 API 1.2.0 #
POST /v1/campaigns on WhatsApp now queues each message.
sentCount counts messages queued, so read delivery from message status or webhooks. failedCount covers refusals before queuing only. A template that is not approved on the account is refused with 400 template_not_found and nothing is charged. The messages now follow the account's send rate limit, frequency cap and quiet hours.
Added 2026-11-02 API 1.2.0 #
New webhook event: segment.alert.
Sent when an audience alert rule fires or recovers. The payload names the segment, the rule, its threshold, the size now and a state of firing or recovered. Subscribe to it on the webhook endpoint like any other event.
Added 2026-11-02 API 1.2.0 #
The conversion postback answers with payout, currency and payout_source.
payout_source says where the amount came from: postback when the request sent it, offer_default when the offer's fixed amount applied. The three fields are left out when no money was recorded. Existing fields are unchanged.
Security 2026-11-02 API 1.1.0 #
The conversion pixel no longer sets a payout, and its events are stored as pixel.<name>.
The pixel is a public, unsigned request, so anyone holding a click id could write an amount to the revenue ledger, or take the event slot of a real postback and block its payout. payout on the pixel URL is now ignored. Send anything that pays through the signed postback. A click records at most five pixel events, a pixel event sends no conversion.recorded webhook, and pixel and cta_click events no longer use up an offer's daily cap. This removal has no notice period because it is a security fix.
Added 2026-11-02 API 1.1.0 #
GET /v1/messages and GET /v1/messages/{id} now carry a failure object, and SMS message.failed events carry reason and code.
failure has reason, reason_text, code and attempts, and is null when there is nothing to report. These two reads and GET /v1/contacts/{phone}/events can answer 403 team_scoping while an account's team views are on.
Deprecated 2026-11-02 API 1.1.0 #
rate_limits.requests_per_second on GET /v1/account is deprecated. Use rate_limits.requests_per_hour.
The limit Cast enforces is hourly. The old field holds the key's raw setting, which is 0 when the key has no setting of its own. It stays, with the same value, until the sunset date.
Removed on or after 2027-05-01.
Deprecated 2026-11-02 API 1.1.0 #
message_id and campaign_id on SMS message events are deprecated. Use messageId and campaignId.
SMS delivery events now also carry messageId and campaignId, with the same values. The old keys stay until the sunset date.
Removed on or after 2027-05-01.
Added 2026-11-02 API 1.1.0 #
New webhook events for email and conversions, and every conversation event can now be turned on from the console.
Added email.opened, email.clicked, email.bounced, email.complained, email.unsubscribed, conversion.recorded and conversion.reversed, all off until you tick them on an endpoint. conversation.status_changed, conversation.assigned and note.added can now be ticked at /developers/webhooks. WhatsApp message events gain sentAt. Every delivery's envelope gains apiVersion. Send test can now send the sample of a chosen event.
Added 2026-11-02 API 1.1.0 #
Added GET /v1/webhook-events and GET /v1/changelog, rate-limit headers in the contract, and rate_limits.requests_per_hour on GET /v1/account.
The rate-limit headers were already sent; they are now documented in the OpenAPI spec and readable by browser callers. /v1/webhook-events is the event catalogue as JSON.
October 2026
Added 2026-10-16 API 1.0.0 #
Added GET /v1/audit-log for keys with the audit scope.
September 2026
Added 2026-09-07 API 1.0.0 #
Added next_cursor and starting_after to GET /v1/messages and GET /v1/contacts/{phone}/events.
A keyset cursor keeps pages stable when new rows arrive between calls. offset still works.
August 2026
Added 2026-08-22 API 1.0.0 #
POST /v1/push/devices accepts a device_id with no push token.
An app that uses in-app messages and no push can now register a device.
Added 2026-08-21 API 1.0.0 #
Added sandbox keys. A sk_test_ key reads your real data and simulates every send.
Added 2026-08-19 API 1.0.0 #
Added the OpenAPI contract at GET /v1/openapi.
Added 2026-08-19 API 1.0.0 #
Added the Idempotency-Key header on sends.
A retried request with the same key returns the first answer and does not send twice.
Added 2026-08-11 API 1.0.0 #
Added POST /v1/events for sending up to 100 events in one call.
May 2026
Added 2026-05-01 API 1.0.0 #
Added the contact properties and contact events endpoints.
Store per-contact properties for segments, and send custom events that can start a journey.