POST
When sending an audio attachment, set
Key params:
•
•
•
Note: the audio must be
View documentation
/v1/inbox/conversations/{conversationId}/messages now supports WhatsApp voice messages (PTT) via voiceNote in the JSON body.When sending an audio attachment, set
voiceNote to true to send it as a WhatsApp voice note (waveform/voice-note UI) instead of a regular audio file.Key params:
•
attachmentType: audio•
attachmentUrl: public URL to the audio file•
voiceNote: true (WhatsApp only)Note: the audio must be
.ogg encoded with OPUS (mono); other formats will be rejected by WhatsApp.View documentation
❤3
New webhook event conversation.started is available via
It fires once when a new DM conversation begins (first message exchange) and is platform-agnostic across
Key fields:
•
•
•
•
•
•
View documentation
WebhookPayloadConversationStarted.It fires once when a new DM conversation begins (first message exchange) and is platform-agnostic across
instagram, facebook, telegram, whatsapp, twitter, reddit, bluesky.Key fields:
•
event=conversation.started•
conversation.id, conversation.platform, conversation.platformConversationId•
conversation.status: active | archived•
account•
startedAt, timestamp•
id (stable webhook event ID)View documentation
❤1
CTWA ad creation now supports more precise geo targeting in
You can target by city/region/ZIP/metro or point-radius locations (useful for local WhatsApp campaigns) instead of relying only on country targeting.
New optional geo fields:
•
•
•
•
•
Note:
View documentation
POST /v1/ads/ctwa.You can target by city/region/ZIP/metro or point-radius locations (useful for local WhatsApp campaigns) instead of relying only on country targeting.
New optional geo fields:
•
cities[] (with optional radius + distance_unit: mile | kilometer)•
regions[]•
zips[]•
metros[]•
customLocations[] (requires latitude, longitude, radius, distanceUnit: mile | kilometer)Note:
countries now defaults to ["US"] only when no other geo targeting (cities/regions/zips/metros/customLocations) is provided.View documentation
🔥1
Inbox webhooks now include
This lets you join any inbox webhook event back to the Zernio CRM Contact (best-effort), without relying on the sender identity — useful for outgoing and delivery-status style events.
New field:
•
Applies to:
•
•
•
•
View documentation
contactId on conversation (via InboxWebhookConversation).This lets you join any inbox webhook event back to the Zernio CRM Contact (best-effort), without relying on the sender identity — useful for outgoing and delivery-status style events.
New field:
•
conversation.contactId - Zernio CRM Contact ID for the participant (omitted when no match or participantId is absent)Applies to:
•
message.received•
message.sent•
reaction.received•
conversation.startedView documentation
❤2
WhatsApp conversion events no longer require a Facebook Page ID on the account when calling
The endpoint now only requires
If you were setting account metadata with
View documentation
POST /v1/whatsapp/conversions.The endpoint now only requires
metaCapiDatasetId (provision via POST /v1/whatsapp/dataset) and forwards the WABA ID as user_data.whatsapp_business_account_id for Meta attribution.If you were setting account metadata with
connectedFacebookPageId, you can stop—missing it will no longer cause 422. Missing metaCapiDatasetId can still return 422.View documentation
🔥3
WhatsApp now supports Sandbox session management via new endpoints:
This lets you activate a test phone against the shared sandbox number (reply-to-activate), list non-expired sessions, and revoke access to block future sends.
Key fields:
• Create/refresh with
• Session object
• Responses include
Also,
View documentation
GET /v1/whatsapp/sandbox/sessions, POST /v1/whatsapp/sandbox/sessions, DELETE /v1/whatsapp/sandbox/sessions/{sessionId}.This lets you activate a test phone against the shared sandbox number (reply-to-activate), list non-expired sessions, and revoke access to block future sends.
Key fields:
• Create/refresh with
phone (server normalizes to E.164)• Session object
WhatsAppSandboxSession: id, phoneE164, status (pending | active), expiresAt, activatedAt• Responses include
sandboxNumberAlso,
GET /v1/whatsapp/phone-numbers now includes an optional sandbox object (or null) with phoneNumber, accountId, and allowed template (name, language), plus isSandbox = true.View documentation
❤3
GET
You can use these to show engagement stats and recent activity without querying message history.
New fields:
• Contact:
• Channel:
View documentation
/v1/contacts/{contactId} now returns additional messaging activity fields on the contact and channels.You can use these to show engagement stats and recent activity without querying message history.
New fields:
• Contact:
messagesSentCount, messagesReceivedCount, lastMessageSentAt (nullable), lastMessageReceivedAt (nullable)• Channel:
lastActiveAt (nullable)View documentation
👍1🔥1
WhatsApp call billing now includes
This makes it explicit what Zernio bills you (Telnyx + recording) vs what Meta bills directly to your WABA (display-only).
New/updated billing fields:
•
•
•
Applies to:
•
•
• Webhook schema
View documentation
billableCostUSD in call history, cost estimates, and call.ended webhooks.This makes it explicit what Zernio bills you (Telnyx + recording) vs what Meta bills directly to your WABA (display-only).
New/updated billing fields:
•
billing.billableCostUSD - amount Zernio bills (excludes Meta)•
billing.metaCostUSD - Meta per-minute charge (billed by Meta directly; display only)•
billing.totalCostUSD - full cost including Meta (display only)Applies to:
•
GET /v1/whatsapp/calls•
GET /v1/whatsapp/calls/estimate (in breakdown)• Webhook schema
WebhookPayloadCallEnded (in call.billing)View documentation
🔥1
X (Twitter) posts now support quote reposting via
Set
Key property:
•
View documentation
quoteTweetId in TwitterPlatformData.Set
quoteTweetId to a tweet ID (or full status URL) to publish a quote tweet. For threads, it applies to the first tweet only.Key property:
•
quoteTweetId - mutually exclusive with media and poll; X only allows quoting your own posts or posts you’re mentioned in / part of the conversation thread of; billed at the standard create rate ($0.015).View documentation
❤1
Comment-to-DM automations now support link tracking for DM button URLs, and the list endpoint includes click metrics.
When enabled, link buttons are wrapped in a tracked redirect so you can measure clicks and CTR.
New fields:
• Create/update:
• List:
• List stats:
• Details/create responses:
View documentation
When enabled, link buttons are wrapped in a tracked redirect so you can measure clicks and CTR.
New fields:
• Create/update:
linkTracking (POST default: true; set false to send links untouched)• List:
automations[].linkTracking• List stats:
automations[].stats.linkClicks, automations[].stats.uniqueClicks• Details/create responses:
automation.linkTrackingView documentation
🤯4❤2👏1
Comment-to-DM automations now support tagging contacts who click tracked links via
When
Use:
•
•
Returned in:
•
•
View documentation
clickTag.When
linkTracking is enabled, you can set clickTag so anyone who clicks a tracked link button in the DM gets tagged for segmentation (broadcasts/sequences).Use:
•
POST /v1/comment-automations: clickTag (optional; requires linkTracking)•
PATCH /v1/comment-automations/{automationId}: clickTag (empty string clears it)Returned in:
•
GET /v1/comment-automations: clickTag•
GET /v1/comment-automations/{automationId}: clickTagView documentation
👍2❤1
GET
This lets you report delivery/read performance for comment-to-DM automations (where supported) without extra calls.
New fields:
•
•
View documentation
/v1/comment-automations now returns additional automation stats: stats.delivered and stats.read.This lets you report delivery/read performance for comment-to-DM automations (where supported) without extra calls.
New fields:
•
stats.delivered - DMs confirmed delivered (Messenger; IG emits no delivery receipt)•
stats.read - DMs confirmed read (IG messaging_seen / Messenger message_reads)View documentation
❤1🔥1
Comment-to-DM automations now support Instagram story reply triggers via a new
You can create automations that fire on keyword replies to stories (in addition to post comments). For story replies,
Use
•
•
Applies to:
•
•
View documentation
trigger field.You can create automations that fire on keyword replies to stories (in addition to post comments). For story replies,
platformPostId is the story media id (omit it to target any story).Use
trigger:•
comment•
story_replyApplies to:
•
POST /v1/comment-automations (new request field trigger, default comment)•
GET /v1/comment-automations and GET /v1/comment-automations/{automationId} (responses now include trigger)View documentation
❤1🔥1
POST
This lets you pin a specific image to each placement group (e.g. 9:16 for Stories/Reels and 4:5 for Feed) within a single ad, using Meta’s
Use
•
•
Constraints: Meta-only; cannot be combined with
View documentation
/v1/ads/create now supports Meta placement asset customization via placementAssets.This lets you pin a specific image to each placement group (e.g. 9:16 for Stories/Reels and 4:5 for Feed) within a single ad, using Meta’s
asset_feed_spec + asset_customization_rules behavior.Use
placementAssets:•
defaultImageUrl (required)•
rules[] (1-10), each with imageUrl + placementsplacements supports: publisherPlatforms, facebookPositions, instagramPositions, messengerPositions, audienceNetworkPositions, threadsPositions, whatsappPositions, devicePlatforms.Constraints: Meta-only; cannot be combined with
dynamicCreative, creatives[], or adSetId.View documentation
🔥2❤1🫡1
Ads now support unified read/update of click-URL tracking tags via
This lets you audit and set platform-native tracking params across Meta/Google/LinkedIn (platforms without a click-URL tracking surface return
Read returns
• Meta:
• Google:
• LinkedIn:
Update expects only the platform fields:
• Meta:
• Google:
• LinkedIn:
Meta-only: you can now read Event Match Quality (EMQ) + pixel↔CAPI coverage via
Also added Meta advanced matching fields to
View documentation
GET /v1/ads/{adId}/tracking-tags and PATCH /v1/ads/{adId}/tracking-tags.This lets you audit and set platform-native tracking params across Meta/Google/LinkedIn (platforms without a click-URL tracking surface return
405).Read returns
platform, level (creative | campaign) plus platform fields:• Meta:
urlTags, templateUrlSpec• Google:
trackingUrlTemplate, finalUrlSuffix• LinkedIn:
dynamicValueParameters, customValueParametersUpdate expects only the platform fields:
• Meta:
urlTags (array of {key,value}) + full creative (headline, body, callToAction, linkUrl, imageUrl); may return 422 if the creative can’t be rebuilt• Google:
trackingUrlTemplate and/or finalUrlSuffix• LinkedIn:
dynamicValueParameters and/or customValueParametersMeta-only: you can now read Event Match Quality (EMQ) + pixel↔CAPI coverage via
GET /v1/ads/conversions/quality with accountId and destinationId (non-Meta returns 405).Also added Meta advanced matching fields to
ConversionEvent.user: city, state, zip, dob, gender (Meta-only; hashed server-side).View documentation
❤1
Meta placement asset customization in
You can now run a single ad with different assets by placement (e.g. 9:16 video on Stories/Reels, 4:5 on Feed). A
Use
• Image mode:
• Video mode:
View documentation
POST /v1/ads/create now supports pinning video per placement group (not just images).You can now run a single ad with different assets by placement (e.g. 9:16 video on Stories/Reels, 4:5 on Feed). A
placementAssets block must be all-image or all-video (no mixing).Use
placementAssets in one of these modes:• Image mode:
defaultImageUrl + rules[].imageUrl• Video mode:
defaultVideoUrl + rules[].videoUrl (+ optional defaultThumbnailUrl / rules[].thumbnailUrl)placementAssets still can’t be combined with dynamicCreative, creatives[], or adSetId.View documentation
❤1
Google Business Profile location listing now supports server-side narrowing for large accounts via
This helps users find a specific location without loading the full list, and responses can now indicate when the list is bounded.
Changes:
•
•
•
•
View documentation
search and advanced filter.This helps users find a specific location without loading the full list, and responses can now indicate when the list is bounded.
Changes:
•
GET /v1/connect/googlebusiness/locations: new search, filter; response adds hasMore and per-location storeCode•
GET /v1/accounts/{accountId}/gmb-locations: new search, filter; response adds hasMore and per-location storeCode•
POST /v1/connect/googlebusiness/select-location: request body adds optional (recommended) accountId to resolve the location directly for large accounts•
PUT /v1/accounts/{accountId}/gmb-locations: request body adds optional (recommended) accountId when switching locationsView documentation
❤2
POST
This endpoint isn’t idempotent at the ad-platform level (a blind retry can create duplicate campaigns/ad sets/ads). With
Use
• Same key + same body → replays the original response (response header
• Same key + different body →
• Key still processing →
Keys are scoped to your credential and expire after 24h.
View documentation
/v1/ads/create now supports safe retries via an optional Idempotency-Key header.This endpoint isn’t idempotent at the ad-platform level (a blind retry can create duplicate campaigns/ad sets/ads). With
Idempotency-Key, retries return the original stored response instead of creating duplicates.Use
Idempotency-Key (e.g. a UUID):• Same key + same body → replays the original response (response header
Idempotent-Replayed: true)• Same key + different body →
422• Key still processing →
409 (retry after backoff)Keys are scoped to your credential and expire after 24h.
View documentation
❤1
Meta ads created via
This lets you pass a Meta targeting spec through verbatim (snake_case) to clone an existing campaign’s targeting exactly, including advanced fields not covered by the camelCase targeting fields.
Use
• camelCase targeting fields (e.g.
•
•
Sending both will return
View documentation
POST /v1/ads/create now support raw Meta-native targeting via rawTargeting.This lets you pass a Meta targeting spec through verbatim (snake_case) to clone an existing campaign’s targeting exactly, including advanced fields not covered by the camelCase targeting fields.
Use
rawTargeting (Meta only) and do not combine it with:• camelCase targeting fields (e.g.
countries, regions, cities, interests, ageMin, ...)•
audienceId•
savedTargetingIdSending both will return
422. If targeting EU users, also provide dsaBeneficiary / dsaPayor separately (not inside rawTargeting).View documentation
❤1
You can now rename Meta ads objects via update endpoints.
This adds name updates without recreating entities (Meta only; other platforms return
•
•
•
Ad creation on Meta also adds more naming control:
•
• In Meta multi-creative mode,
View documentation
This adds name updates without recreating entities (Meta only; other platforms return
501).•
PUT /v1/ads/campaigns/{campaignId} now accepts name (max 255)•
PUT /v1/ads/ad-sets/{adSetId} now accepts name (max 255)•
PUT /v1/ads/{adId} now supports name (max 255) and propagates it to Meta; non-Meta returns 501Ad creation on Meta also adds more naming control:
•
POST /v1/ads/create now accepts campaignName and adSetName (max 255)• In Meta multi-creative mode,
creatives[].name sets the per-ad name (max 255)View documentation
❤1
New Inbox Analytics endpoints are available to query messaging volume, response times, and conversation-level stats (max date range:
New endpoints:
•
•
•
•
•
•
•
Webhook event enums were expanded in
•
•
•
View documentation
365 days).New endpoints:
•
GET /v1/analytics/inbox/volume — volume + KPIs + per-platform split (key params: fromDate, toDate, profileId, platform, accountId, source)•
GET /v1/analytics/inbox/heatmap — day-of-week × hour heatmap (key params: fromDate, toDate, action=message.received|message.sent|message.read|all)•
GET /v1/analytics/inbox/source-breakdown — breakdown by metadata.source•
GET /v1/analytics/inbox/response-time — time-to-first-response summary + histogram•
GET /v1/analytics/inbox/top-accounts — top accounts by inbox volume (key param: limit 1–50)•
GET /v1/analytics/inbox/conversations — paginated conversation analytics (key params: limit, page, sortBy=lastMessageAt|firstMessageAt|totalMessages|received|sent|read|failed, order=asc|desc)•
GET /v1/analytics/inbox/conversations/{conversationId} — single-conversation analytics ({conversationId} accepts Mongo _id or platformConversationId)Webhook event enums were expanded in
POST /v1/webhooks/settings, PUT /v1/webhooks/settings, and the Webhook schema to include:•
whatsapp.number.suspended•
whatsapp.number.reactivated•
whatsapp.number.releasedView documentation
❤5