Ads analytics now includes funnel step counts, an engagement breakdown, and cost per ThruPlay.
This makes it easier to report on Meta ads without parsing/deduping raw
New fields in
•
•
•
Also new in
•
View documentation
This makes it easier to report on Meta ads without parsing/deduping raw
actions keys (and avoids double-counting), and adds a direct cost metric for ThruPlays.New fields in
AdMetrics:•
costPerThruplay•
funnel (ref AdFunnelCounts): landingPageViews, contentViews, searches, wishlistAdds, cartAdds, checkoutsInitiated, paymentInfoAdds, purchases, leads, registrationsCompleted, appInstalls, messagingConversationsStarted, messagingFirstReplies•
engagementBreakdown (ref AdEngagementCounts): postEngagement, pageEngagement, reactions, comments, shares, saves, pageLikes, videoViews, linkClicksAlso new in
Ad:•
creativeType: carousel | video | document | image | nullView documentation
❤1
PATCH
You can switch an automation between comment-based and story-reply-based triggers; changing it will detach the automation from its currently bound post/story unless the same request sets a new binding.
Set
View documentation
/v1/comment-automations/{automationId} now accepts trigger to control what fires an automation.You can switch an automation between comment-based and story-reply-based triggers; changing it will detach the automation from its currently bound post/story unless the same request sets a new binding.
Set
trigger to: • comment • story_reply (Instagram only)View documentation
❤2
GET /v1/comment-automations/{automationId}/logs now returns non-matching comment diagnostics via a new misses object.Use
misses to see how many comments reached the automation but matched none of its keywords (and a few recent samples) to troubleshoot keyword/exclusion setups.New response fields:
•
misses.total•
misses.retentionDays•
misses.samples[]: commentText, commenterName, excludedBy, atRequest validation tightened:
•
limit now 1..200•
skip now >= 0• Invalid values may return
400 BadRequestView documentation
❤1
Instagram follow checks are now available via
This resolves the follow relationship (when Meta allows it) and returns
Key fields:
•
•
Comment-to-DM automations now support follower-based targeting + optional follow verification (Instagram only), and delayed sends.
New request fields on
•
•
•
•
Automation logs (
Webhook comment payloads now may include Instagram-only
View documentation
GET /v1/accounts/{accountId}/follow-status/{userId}.This resolves the follow relationship (when Meta allows it) and returns
isFollower (can be null when unknown) plus basic public counters; use refresh=true to bypass the short cache.Key fields:
•
isFollower: true | null (null = unknown, never “no”)•
unavailableReason: consent_required | dm_access_disabled | not_messageable | error | nullComment-to-DM automations now support follower-based targeting + optional follow verification (Instagram only), and delayed sends.
New request fields on
POST /v1/comment-automations and PATCH /v1/comment-automations/{automationId}:•
dmDelaySeconds (0–86400)•
commentReplyDelaySeconds (0–86400)•
audience (followerStatus: any | follower | non_follower; whenUnknown: send | skip | verify; optional minFollowerCount)•
followGate (message, buttonLabel, optional notFollowingMessage)Automation logs (
GET /v1/comment-automations/{automationId} and .../logs) add new status values pending and gated, plus fields like audienceOutcome (passed | blocked | gate_sent | gate_passed | gate_failed) and nextDueAt while queued.Webhook comment payloads now may include Instagram-only
comment.author.instagramProfile (best-effort) with isFollower/followerCount when available; absence means “unknown”.View documentation
Message reactions are now supported on Instagram, Facebook Messenger, and Slack via the existing reactions endpoints.
You can add/remove reactions across more inbox channels, and reaction webhooks now cover these platforms too.
Use:
•
•
Notes:
• Slack reactions require a Slack emoji name like
• Instagram/Messenger reactions are subject to Meta’s 24h messaging window
•
Comment-to-DM automations now support sending a Meta generic template (product card) as the first DM.
Set
•
•
Constraints:
•
• For
Also: for
View documentation
You can add/remove reactions across more inbox channels, and reaction webhooks now cover these platforms too.
Use:
•
POST /v1/inbox/conversations/{conversationId}/messages/{messageId}/reactions with emoji•
DELETE /v1/inbox/conversations/{conversationId}/messages/{messageId}/reactions with accountId (query)Notes:
• Slack reactions require a Slack emoji name like
:thumbsup: (unnamed Unicode emoji returns 400)• Instagram/Messenger reactions are subject to Meta’s 24h messaging window
•
reaction.received webhook now includes Slack/Instagram/Messenger (sender can be the business platform id; compare reaction.sender.id with conversation.participantId)Comment-to-DM automations now support sending a Meta generic template (product card) as the first DM.
Set
template on POST /v1/comment-automations / PATCH /v1/comment-automations/{automationId}:•
template.type: generic•
template.elements: 1–10 cards (each supports title, subtitle, imageUrl, buttons)Constraints:
•
template is mutually exclusive with buttons (sending both is a 400)• For
PATCH, pass template: null to clear the cardAlso: for
POST /v1/inbox/conversations/{conversationId}/messages on Instagram/Facebook, top-level buttons are now explicitly mutually exclusive with template (sending both returns 400).View documentation
PUT /v1/ads/campaigns/{campaignId} now supports Google campaigns (in addition to Meta) and enforces platform-level field support (unsupported fields return 400, not silently ignored).For Google, you can set campaign bidding via:
•
platform: google•
bidStrategy (Meta + Google)•
bidAmount (Google only; required for LOWEST_COST_WITH_BID_CAP and COST_CAP)•
roasAverageFloor (Google only; required for LOWEST_COST_WITH_MIN_ROAS)The
200 response now echoes back only the fields you sent, plus updated (and may include bidAmount/roasAverageFloor when provided).View documentation
New endpoint:
This re-homes the number and any associated accounts together (so you don’t split the number across profiles by moving only the social account).
Send
Response may include
View documentation
PATCH /v1/whatsapp/phone-numbers/{id}/profile to move a provisioned number to another profile.This re-homes the number and any associated accounts together (so you don’t split the number across profiles by moving only the social account).
Send
{ "profileId": "..." } where id is the phone number record id from GET /v1/phone-numbers (not an account id).Response may include
movedPlatforms with values phone, sms, whatsapp. Conflicts return 409 if the destination profile already has an account on any of those platforms.View documentation
POST
This lets you refresh/boost an existing post while keeping the ad set’s learning phase (attach to an existing ad set instead of provisioning a new campaign/ad set).
Key changes:
• Meta-only attach: send
• When
•
• Meta-only additions:
•
POST
• Send
Schema note (breaking for generated clients):
View documentation
/v1/ads/boost now supports attaching a boost to an existing Meta ad set via adSetId, and adds Meta support for CTA destinations via linkUrl + callToAction.This lets you refresh/boost an existing post while keeping the ad set’s learning phase (attach to an existing ad set instead of provisioning a new campaign/ad set).
Key changes:
• Meta-only attach: send
adSetId to attach under an existing ad set• When
adSetId is set, budget/schedule/targeting are owned by the ad set and sending any of them is a 400•
budget is now required only when adSetId is NOT set• Meta-only additions:
instagramAccountId, destinationType (INSTAGRAM_PROFILE, WEBSITE, ON_AD, MESSENGER, WHATSAPP)•
linkUrl is now supported on Meta boosts (still supported on TikTok); callToAction must be sent together with linkUrl (sending either alone is a 400)POST
/v1/ads/ctwa (deprecated) also adds an attach flow:• Send
adSetId to add creatives to an existing messaging ad set; then budgetAmount/budgetType/endDate/objective/countries/interests/audienceId are rejected with 400Schema note (breaking for generated clients):
CtwaAdRequestBody no longer lists budgetAmount/budgetType as always-required (they’re required unless adSetId is set).View documentation
Google Business location selection/updates now validate the provided Google account resource name and will reject mismatches.
If you pass an account identifier to speed up location resolution for large GBP accounts, the API will now return
Applies to:
•
•
•
View documentation
If you pass an account identifier to speed up location resolution for large GBP accounts, the API will now return
400 when the provided account is not one of the accounts the connection manages.Applies to:
•
POST /v1/connect/googlebusiness/select-location with accountId•
PUT /v1/accounts/{accountId}/gmb-locations with googleAccountId (legacy body field accountId still accepted)•
POST /v1/accounts/{accountId}/gmb-locations/assign with googleAccountIdView documentation
WhatsApp connect now rejects Zernio-provisioned numbers that are pinned to a different profile with a
This prevents accidentally connecting a provisioned WhatsApp number from the wrong
New
•
•
•
Remediation:
• Move the number with
View documentation
409 conflict.This prevents accidentally connecting a provisioned WhatsApp number from the wrong
profileId. If you need to connect it on another profile, move the number first, then retry the connect.New
409 responses:•
GET /v1/connect/whatsapp (when profileId doesn’t match the provisioned number’s profile)•
POST /v1/connect/whatsapp/credentials•
POST /v1/connect/whatsapp/select-phone-numberRemediation:
• Move the number with
PATCH /v1/whatsapp/phone-numbers/{id}/profile, then connect again.View documentation
Instagram connect now supports headless mode for
This lets you run the Facebook Login-based Instagram flow with your own UI: after OAuth, the callback redirects to your
Use:
•
Callback includes:
View documentation
loginMethod=facebook_login on GET /v1/connect/instagram.This lets you run the Facebook Login-based Instagram flow with your own UI: after OAuth, the callback redirects to your
redirect_url with selection-step params, and you finish by calling GET /v1/connect/instagram/select-account.Use:
•
GET /v1/connect/instagram?loginMethod=facebook_login&headless=trueCallback includes:
platform=instagram, step=select_account, profileId, tempToken, connect_tokenView documentation
Comment-to-DM automations can now also trigger from inbound DMs via
Set
Key details:
•
• Requires at least one
• Not allowed for
Responses now include:
•
•
View documentation
alsoMatchInDms.Set
alsoMatchInDms: true on a trigger=comment automation to answer users who DM the keyword instead of commenting it. Deduplication is per source (comment vs DM).Key details:
•
alsoMatchInDms (boolean, default false) on POST /v1/comment-automations and PATCH /v1/comment-automations/{automationId}• Requires at least one
keywords entry (empty keyword lists are rejected when enabling)• Not allowed for
trigger=story_replyResponses now include:
•
alsoMatchInDms on automation objects (list/get/create/update)•
source on log entries: comment | story_reply | dmView documentation
Inbox messages now support refreshable attachment URLs for Instagram/Facebook DMs.
Meta DM media URLs expire; attachments now include a stable
New endpoint:
Key params:
Response behavior:
• Default
•
Also added on
•
•
View documentation
Meta DM media URLs expire; attachments now include a stable
refreshUrl you can store and call later to get a working media URL.New endpoint:
GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}Key params:
accountId (required), format (redirect | json, default redirect)Response behavior:
• Default
format=redirect returns 302 to the live media URL•
format=json returns { url, refreshed }Also added on
GET /v1/inbox/conversations/{conversationId}/messages attachments:•
attachments[].refreshUrl (Instagram/Facebook only)•
attachments[].url is now documented as expiring on Instagram/Facebook (use immediately; don’t store).View documentation
Workflow AI nodes now support
This lets you route AI steps through OpenRouter using your BYOK setup (set
Set
View documentation
openrouter as an ai.provider value.This lets you route AI steps through OpenRouter using your BYOK setup (set
provider + model).Set
ai.provider to one of: anthropic, openai, google, mistral, groq, openrouter.View documentation
🔥2
You can now like/unlike posts via the Inbox API.
This enables executive engagement (like/react as any connected
New endpoints:
•
•
Also updated: comment like/unlike now supports LinkedIn on
View documentation
This enables executive engagement (like/react as any connected
accountId on a brand post). postId accepts a Zernio post ID or the platform native post ID.New endpoints:
•
POST /v1/inbox/posts/{postId}/like with accountId (+ optional reactionType for LinkedIn: LIKE, PRAISE, EMPATHY, INTEREST, APPRECIATION, ENTERTAINMENT; optional cid for Bluesky)•
DELETE /v1/inbox/posts/{postId}/like with accountId (+ likeUri required for Bluesky)Also updated: comment like/unlike now supports LinkedIn on
POST /v1/inbox/comments/{postId}/{commentId}/like and DELETE /v1/inbox/comments/{postId}/{commentId}/like. For LinkedIn likes, pass the composite comment URN as commentId and you can set reactionType (same enum as above).View documentation
👍1
Meta ads now support scheduled budget increases via
This lets you pre-schedule temporary budget bumps (e.g. Black Friday) instead of editing budgets manually on the day.
Send:
•
• exactly one of
•
•
•
• optional
Meta custom conversions are now manageable via the API:
• List:
• Create or reuse:
Creating supports reuse (to avoid duplicates) by matching
Meta creatives now accept
•
•
Use
View documentation
POST /v1/ads/high-demand-periods.This lets you pre-schedule temporary budget bumps (e.g. Black Friday) instead of editing budgets manually on the day.
Send:
•
accountId• exactly one of
campaignId / adSetId•
budgetValueType: ABSOLUTE | MULTIPLIER•
budgetValue•
timeStart, timeEnd (Unix seconds, 15-min boundaries)• optional
recurrenceType: ONE_TIME | WEEKLY | MONTHLYMeta custom conversions are now manageable via the API:
• List:
GET /v1/accounts/{accountId}/custom-conversions (requires adAccountId)• Create or reuse:
POST /v1/accounts/{accountId}/custom-conversionsCreating supports reuse (to avoid duplicates) by matching
name + pixelId; reused conversions return 200 with reused: true, otherwise 201. The response includes customConversionId for promotedObject.customConversionId on POST /v1/ads/create.Meta creatives now accept
multiAdvertiser: OPT_IN | OPT_OUT on:•
POST /v1/ads/creatives•
POST /v1/ads/createUse
OPT_OUT to disable Meta’s multi-advertiser ads behavior (Meta auto-enrolls by default).View documentation
GET /v1/accounts/{accountId}/instagram/stories/{storyId}/insights can now return 502 when Instagram rejects the upstream request.This makes upstream failures explicit so clients can distinguish Instagram-side rejection from successful-but-empty expired story results.
Handle these responses:
•
200 with data.source = live | cached | unavailable•
502 - Instagram rejected the requestView documentation
GET /v1/broadcasts/{broadcastId}/recipients now returns errorTraceId for failed recipients.Use
errorTraceId (Meta fbtrace_id) to correlate a failed send and quote it when escalating to Meta Direct Support. It’s only populated when status is failed (Meta platforms).New field:
errorTraceId (string | null)View documentation
Instagram now supports attaching catalog audio to Reels via
You can search/trend audio with
Search params:
•
•
To publish with audio, set:
•
•
•
Requires an Instagram account connected via Facebook Login. Classic Instagram Login accounts will get a 400
View documentation
platformSpecificData.audioConfiguration.You can search/trend audio with
GET /v1/accounts/{accountId}/instagram/audio (omit q for trending) and fetch metadata with GET /v1/accounts/{accountId}/instagram/audio/{audioId}. Use the returned audioId when creating a Reel.Search params:
•
audioType: music | original_sound•
q: optional keywords (omit for trending)To publish with audio, set:
•
platformSpecificData.audioConfiguration.audioId (required)•
platformSpecificData.audioConfiguration.audioVolume (0-100)•
platformSpecificData.audioConfiguration.videoVolume (0-100)Requires an Instagram account connected via Facebook Login. Classic Instagram Login accounts will get a 400
instagram_audio_requires_facebook_login and must be reconnected using the Facebook option.View documentation
TikTok ad reporting now populates additional video metrics in
This lets you use the same video KPI fields across Meta and TikTok when reading ad/campaign metrics.
TikTok sources now apply to:
•
•
•
•
•
•
Meta-only remains:
•
•
•
•
View documentation
AdMetrics (previously documented as Meta-only).This lets you use the same video KPI fields across Meta and TikTok when reading ad/campaign metrics.
TikTok sources now apply to:
•
videoPlayActions•
videoP25WatchedActions•
videoP50WatchedActions•
videoP75WatchedActions•
videoP100WatchedActions•
videoAvgTimeWatchedActionsMeta-only remains:
•
video30SecWatchedActions•
videoThruplayWatchedActions•
videoP95WatchedActions•
costPerThruplayView documentation
Google Ads now supports keyword edits on existing ads via
You can update Google Search ad group keywords by sending
Use:
•
•
Also added for Google Search creation via
•
View documentation
PUT /v1/ads/{adId}.You can update Google Search ad group keywords by sending
targeting.keywords and/or targeting.negativeKeywords. Each list you send becomes the FULL new set of that kind (items not included are removed); omit a kind to leave it unchanged.Use:
•
targeting.keywords (Google only) — items are "string" (defaults to broad) or { text, matchType } where matchType is exact | phrase | broad•
targeting.negativeKeywords (Google only) — same shape as aboveAlso added for Google Search creation via
POST /v1/ads/create:•
negativeKeywords — broad-match negative keywords on the new ad group (editable later via PUT /v1/ads/{adId} targeting.negativeKeywords).View documentation