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
Ad analytics now include additional Meta click + cost breakdown fields in
This adds per-action cost metrics and separates different click definitions (attributed vs in-session vs outbound), making it easier to build accurate dashboards and optimize campaigns.
New fields:
•
•
•
•
Note: these click fields are Meta-only; other platforms return
View documentation
AdMetrics.This adds per-action cost metrics and separates different click definitions (attributed vs in-session vs outbound), making it easier to build accurate dashboards and optimize campaigns.
New fields:
•
costPerAction (object) — derived spend / actions[type] per action type•
outboundClicks, outboundClicksCtr•
inlineLinkClicks, inlineLinkClickCtr•
uniqueClicks, uniqueCtrNote: these click fields are Meta-only; other platforms return
0 (and costPerAction may be {} when not applicable).View documentation
LinkedIn posts now support polls via
Use this to publish a LinkedIn poll with your post. Polls cannot be combined with media or
Set
•
•
•
View documentation
poll in LinkedInPlatformData.Use this to publish a LinkedIn poll with your post. Polls cannot be combined with media or
reshareUrl, cannot be edited after publishing, and API-created polls are non-sponsored only.Set
poll with:•
question (1-140 chars)•
options (2-4 items, 1-30 chars each)•
duration (optional): ONE_DAY | THREE_DAYS | SEVEN_DAYS | FOURTEEN_DAYS (default SEVEN_DAYS)View documentation
POST
When
Key fields:
• Enable:
• Supported
• Web Smart+ requires
• App Smart+ requires
• Budget is campaign-level;
• Cannot be combined with
View documentation
/v1/ads/create now supports TikTok Smart+ campaigns via smartPlus.When
smartPlus: true, Zernio creates an Upgraded Smart+ campaign where TikTok automates targeting/bidding/delivery (within your provided geo targeting).Key fields:
• Enable:
smartPlus (boolean)• Supported
goal: conversions, lead_generation, app_promotion• Web Smart+ requires
promotedObject.pixelId + promotedObject.customEventType• App Smart+ requires
promotedObject.applicationId• Budget is campaign-level;
budgetType=lifetime requires endDate• Cannot be combined with
adSetIdView documentation
❤1
TikTok ads now populate engagement breakdown in
You can now read paid engagement interactions for TikTok directly from
Key fields:
•
•
•
•
Other platforms are unchanged (still 0 where not supported).
View documentation
AdEngagementCounts (previously Meta-only).You can now read paid engagement interactions for TikTok directly from
engagementBreakdown (while TikTok follows remain in actions).Key fields:
•
AdMetrics.engagementBreakdown.reactions (TikTok paid likes)•
AdMetrics.engagementBreakdown.comments•
AdMetrics.engagementBreakdown.shares•
AdMetrics.actions.follow (TikTok followers objective result)Other platforms are unchanged (still 0 where not supported).
View documentation
❤1
Google Local Services Ads lead insights are now available via two new endpoints.
You can fetch LSA leads live from Google (newest first) and then pull the conversation history (calls/messages) for a specific lead. Note: data is not persisted (Google is the source of truth), and requests draw from the shared Google Ads operations budget.
Get leads with
Required:
Optional filters:
Key fields:
Get lead conversations with
Params:
Conversation fields include
View documentation
You can fetch LSA leads live from Google (newest first) and then pull the conversation history (calls/messages) for a specific lead. Note: data is not persisted (Google is the source of truth), and requests draw from the shared Google Ads operations budget.
Get leads with
GET /v1/ads/local-services/leadsRequired:
accountIdOptional filters:
customerId, fromDate, toDate, leadType (PHONE_CALL/MESSAGE/BOOKING), leadStatus (e.g. NEW, BOOKED, WIPED_OUT), chargedOnly, pageTokenKey fields:
id, contact (null when WIPED_OUT), charged, creditState, createdTimeGet lead conversations with
GET /v1/ads/local-services/leads/{leadId}/conversationsParams:
leadId, accountId (+ optional customerId, pageToken)Conversation fields include
channel (PHONE_CALL/MESSAGE/SMS/EMAIL/WHATSAPP/ADS_API), participantType (ADVERTISER/CONSUMER), plus phoneCall.callRecordingUrl / message.attachmentUrls when applicable.View documentation
❤1