Changelog
Stay up to date with the latest API changes and improvements
Track all updates to the Zernio API. We announce significant changes here and on our Telegram channel and X (Twitter).
Improvement
Facebook text background posts via
Previously, requests were rejected with
Use
textFormatPresetId no longer reject long captions.Previously, requests were rejected with
400 when content exceeded ~130 characters. Now, length is not rejected; Facebook may publish and return a warning instead.Use
textFormatPresetId (numeric string, ^\d+$) for Pages + text-only feed posts. Requests are still rejected with 400 if mediaItems or carouselCards are present, if contentType is story or reel, or if content is empty.New Feature
WhatsApp Calling config now supports a call duration cap and forwarded caller ID control on calling endpoints.
You can limit forwarded call length (to prevent dead-air billing) and, for SIP forwards, choose whether the destination sees the business number or the end-caller.
New fields:
•
•
Available on:
•
•
•
You can limit forwarded call length (to prevent dead-air billing) and, for SIP forwards, choose whether the destination sees the business number or the end-caller.
New fields:
•
maxCallDurationSeconds (request/response) — 30..14400 or null (no cap / clear cap)•
forwardCallerId (request/response) — business | callerAvailable on:
•
GET /v1/whatsapp/calling•
GET /v1/phone-numbers/{id}/whatsapp/calling•
POST/PATCH /v1/phone-numbers/{id}/whatsapp/calling (and the deprecated alias /v1/whatsapp/phone-numbers/{id}/calling)Breaking Change
Bulk contact import (
When
Check your handling of
POST /v1/contacts/bulk) now validates and normalizes phone identifiers for phone platforms.When
platform is whatsapp or sms, each contact’s platformIdentifier is normalized to digits; values that aren’t phone-shaped are rejected per contact and reported in errors[] (not imported).Check your handling of
errors[] in the 200 response (now returned as strings describing per-contact failures).New Feature
WhatsApp Calling now supports caller-ID verification for customer-brought (BYO) phone numbers, so
Start (or resend) a verification code via
Confirm the code via
•
•
tel: call forwards can present the business number as caller ID.Start (or resend) a verification code via
POST /v1/phone-numbers/{id}/whatsapp/caller-id-verification with optional method: sms | call.Confirm the code via
POST /v1/phone-numbers/{id}/whatsapp/caller-id-verification/verify with required code.GET /v1/whatsapp/calling now returns:•
callerIdMode: business | platform•
callerIdVerified: true | falseImprovement
WhatsApp Calling endpoints now return caller ID details for tel: forwards via
This helps you understand whether the PSTN forward-leg will present the business number or a Zernio platform number when caller ID isn’t verified.
New response fields:
•
•
Also clarified:
callerIdMode (and verification status on GET).This helps you understand whether the PSTN forward-leg will present the business number or a Zernio platform number when caller ID isn’t verified.
New response fields:
•
POST /v1/phone-numbers/{id}/whatsapp/calling and POST /v1/whatsapp/phone-numbers/{id}/calling: callerIdMode = business | platform•
GET /v1/phone-numbers/{id}/whatsapp/calling: callerIdMode = business | platform, callerIdVerified (boolean)Also clarified:
400 can be returned if forwardTo is set to the number itself.New Feature
Facebook posts now support large-text background presets via
This lets you render a text-only feed post as large text on a colored background using Meta’s
Use
• Text-only feed posts only: request is rejected if
• Not allowed with
•
• If a URL is present in
textFormatPresetId in FacebookPlatformData.This lets you render a text-only feed post as large text on a colored background using Meta’s
textformatpreset_id.Use
textFormatPresetId (numeric string, pattern ^\d+$). Constraints:• Text-only feed posts only: request is rejected if
mediaItems or carouselCards are present• Not allowed with
contentType story or reel•
content must be non-empty and ≤ 130 chars (otherwise rejected)• If a URL is present in
content, no link preview is attached while a preset is setImprovement
Rate limit guidance has been updated: the per-account velocity limit referenced in
•
•
If you throttle based on the error text for
429 responses is now 25 posts/hour per account (was 15) for:•
POST /v1/posts•
POST /v1/posts/{postId}/retryIf you throttle based on the error text for
429, update your assumptions to match the new 25 posts/hour limit.Improvement
Meta ad URL tags now preserve Meta dynamic macros in tracking parameters.
When setting Meta
Applies to:
•
•
•
When setting Meta
urlTags, macros like {{ad.id}}, {{campaign.id}}, {{placement}} are sent through unescaped so Meta can expand them; all other characters are percent-encoded.Applies to:
•
PATCH /v1/ads/{adId}/tracking-tags via urlTags•
POST /v1/ads/boost via tracking.urlTags•
POST /v1/ads/create via tracking.urlTagsImprovement
Meta ads reporting now supports filtering by Facebook Page via
This lets you scope results and rolled-up metrics to ads whose creative is backed by a specific Page (useful when one Meta ad account serves multiple Pages).
New query param:
•
Available on:
•
•
•
Matches against
pageId on ads, campaigns, and the campaign tree.This lets you scope results and rolled-up metrics to ads whose creative is backed by a specific Page (useful when one Meta ad account serves multiple Pages).
New query param:
•
pageId (Meta only)Available on:
•
GET /v1/ads•
GET /v1/ads/campaigns•
GET /v1/ads/treeMatches against
ad.creative.pageId (may be null for non-Meta ads and rare IG-only creatives).New Feature
Facebook analytics now supports per-post monetization earnings via
This returns lifetime cumulative earnings for a single post, read live from Meta on each request (no date range supported).
Required params:
•
•
Optional:
•
Notes:
•
• Money metrics include
• Metrics Meta can’t serve are omitted from
Also:
GET /v1/analytics/facebook/post-earnings.This returns lifetime cumulative earnings for a single post, read live from Meta on each request (no date range supported).
Required params:
•
accountId•
postId (e.g. {pageId}_{postId} or bare Reels video ID)Optional:
•
metrics = contentmonetizationearnings, monetizationapproximateearnings (defaults to both)Notes:
•
since/until/period/metricType/breakdown are rejected with 400 (lifetime only).• Money metrics include
unit (micro_amount | unspecified) and currency (string | null), and are never rescaled.• Metrics Meta can’t serve are omitted from
metrics and listed in unavailableMetrics (HTTP 200).Also:
GET /v1/analytics/facebook/page-insights now accepts monetization metrics (contentmonetizationearnings, monetizationapproximateearnings) and may return unavailableMetrics with the same omit-vs-zero behavior.New Feature
POST /v1/media/presign now supports generating presigned upload URLs for audio files.You can upload audio by setting
contentType to one of: audio/mpeg, audio/mp4, audio/aac, audio/ogg, audio/wav, audio/webm, audio/x-m4a.Improvement
Phone number purchases can now be auto-assigned to a different profile when the requested
Send
Check the assigned profile in:
•
•
profileId already has a number.Send
profileId as the preferred profile, but the API may assign the number to the next free profile (or create one) and will return the actual assignment.Check the assigned profile in:
•
phoneNumber.profileId (when a number is provisioned)•
profileId in the { status: "already_purchased" } response when using purchaseIntentIdBreaking Change
Instagram user tagging behavior has changed for
• Photos:
• Reels/videos: username-only tags; any
• Stories:
Carousel targeting still uses
platformSpecificData.instagram.userTags.userTags items now require only username (previously username + x + y were required). Tag handling now depends on media type:• Photos:
x/y are required; photo tags without valid coordinates are skipped• Reels/videos: username-only tags; any
x/y provided are ignored• Stories:
x/y are optionalCarousel targeting still uses
mediaIndex (defaults to 0); out-of-range indices are ignored.New Feature
GET /v1/inbox/conversations/search now supports filtering by Slack via platform=slack.This lets you search conversations and restrict results to Slack accounts the same way as other stored-message platforms.
Use
platform = facebook | instagram | telegram | whatsapp | sms | slackThe
conversation.started webhook payload also adds conversation.platform=slack in WebhookPayloadConversationStarted.New Feature
POST /v1/posts/sync-external now supports LinkedIn personal profiles.Because LinkedIn personal profiles don’t have a listing API, you must provide
url to import a single post authored by the connected member (works even for posts published before the account was connected).Use
accountId + url (required for LinkedIn personal), where url can be:•
linkedin.com/posts/…•
linkedin.com/feed/update/urn:li:activity:…•
urn:li:share:… / urn:li:ugcPost:…Imported LinkedIn personal posts return analytics (impressions, reach, reactions, comments, reshares, saves) but no content/media.
New Feature
Slack accounts now support reading and updating per-channel default message identity via new endpoints
This lets you set default author name/avatar for Slack messages on an account (per-post
Update with
The settings response includes channel details like
GET /v1/accounts/{accountId}/slack-settings and PATCH /v1/accounts/{accountId}/slack-settings.This lets you set default author name/avatar for Slack messages on an account (per-post
platformSpecificData.username/platformSpecificData.iconUrl can still override).Update with
defaultUsername (max 80) and defaultIconUrl. Send an empty string to clear either field.The settings response includes channel details like
channelId, channelName, channelType (public or private), plus teamId/teamName.Improvement
POST
You can distinguish missing-recipient cases and, for Instagram/Facebook, get Meta’s diagnostic fields to debug rejected sends.
New
•
•
/v1/inbox/conversations/{conversationId}/messages now returns more detailed send failures in 400 responses.You can distinguish missing-recipient cases and, for Instagram/Facebook, get Meta’s diagnostic fields to debug rejected sends.
New
400 fields:•
code: PLATFORMLIMITATION | MISSINGPARTICIPANT•
platformError (Instagram/Facebook only): code, subcode, fbtraceId, typeNew Feature
Slack is now supported as a posting platform via
You can schedule/publish Slack messages to the channel tied to the connected Slack
Use
•
•
•
•
•
Slack is also available for filtering in
POST /v1/posts and POST /v1/tools/validate/post, and can be connected via GET /v1/connect/{platform}.You can schedule/publish Slack messages to the channel tied to the connected Slack
accountId (one connected account per channel).Use
platform=slack and Slack options in platformSpecificData:•
threadTs•
unfurlLinks•
unfurlMedia•
username•
iconUrlSlack is also available for filtering in
GET /v1/accounts/health via platform=slack.New Feature
New Google Ads keyword research endpoints are available, and
You can now pull Keyword Planner data via:
•
•
Key request fields:
•
•
•
•
•
• Meta: use
• Google Ads: use
Note: Google responses return raw rows (camelCase) with int64 counters encoded as strings; bid/CPC values are in micros.
GET /v1/ads/insights now supports Google Ads queries.You can now pull Keyword Planner data via:
•
POST /v1/ads/keywords/ideas (generate ideas from seedKeywords and/or seedUrl)•
POST /v1/ads/keywords/historical-metrics (metrics for up to keywords = 1000)Key request fields:
•
accountId (required)•
customerId (optional; needed if the connection has several Google Ads accounts)•
countries (optional; omitted = worldwide)•
languageConstantId (default 1000)•
network: GOOGLESEARCH | GOOGLESEARCHANDPARTNERSGET /v1/ads/insights now routes by platform:• Meta: use
objectId (+ fields/breakdowns/filtering as before)• Google Ads: use
query (GAQL SELECT), with paging via pageToken and paging.nextPageToken (fixed 10,000 rows/page)Note: Google responses return raw rows (camelCase) with int64 counters encoded as strings; bid/CPC values are in micros.
Improvement
Instagram and Facebook Inbox now include pre-connect DM history replay in
When an IG/FB account is connected, Zernio replays existing Meta DM history in the background so older threads can appear in listings; if you sync into your own store, you should re-sweep rather than relying on a single pass at connect time.
Key behavior:
•
• Replayed history emits
•
GET /v1/inbox/conversations and GET /v1/inbox/conversations/{conversationId}/messages.When an IG/FB account is connected, Zernio replays existing Meta DM history in the background so older threads can appear in listings; if you sync into your own store, you should re-sweep rather than relying on a single pass at connect time.
Key behavior:
•
GET /v1/inbox/conversations: up to 500 conversations per account are replayed; replayed threads keep their original lastMessageAt/updatedTime so they sort into date order (not bumped to the top)• Replayed history emits
no webhooks and is stored as read (does not affect unreadCount)•
GET /v1/inbox/conversations/{conversationId}/messages: replay includes the 500 most recent messages per conversation; older messages beyond that are not retrievableBreaking Change
POST /v1/sms/registrations no longer requires phoneNumbers in the request body.For 10DLC registrations, if
phoneNumbers is omitted or an empty array, it now defaults to your active SMS-enabled US local numbers that aren’t already covered by another registration.Key request fields:
•
registrationType: standard10dlc | soleprop10dlc | tollfree•
phoneNumbers: optional (new defaulting behavior for 10DLC)New Feature
Webhooks now support
This event fires when Zernio’s background sync detects a platform post (published via Zernio) was later deleted on the platform (poll-driven ~hourly, not real-time).
Subscribe by including
In
•
•
• New field on delete events:
post.platform.deleted in events for POST /v1/webhooks/settings and PUT /v1/webhooks/settings.This event fires when Zernio’s background sync detects a platform post (published via Zernio) was later deleted on the platform (poll-driven ~hourly, not real-time).
Subscribe by including
post.platform.deleted in events.In
WebhookPayloadPostPlatform:•
event: post.platform.published | post.platform.failed | post.platform.deleted | post.tiktok.url_resolved•
platform.status: published | failed | deleted• New field on delete events:
platform.deletedAt (ISO 8601)New Feature
Instagram is now supported for typing indicators via
Calling this endpoint can now show
Request:
Response:
The endpoint may now also return
POST /v1/inbox/conversations/{conversationId}/typing.Calling this endpoint can now show
typing... to the Instagram recipient (works for both Instagram Login and Facebook Login accounts; recipient must be signed in to Instagram to see it).Request:
{ "accountId": "..." }Response:
{ "success": true|false } where success indicates whether the typing indicator was actually sent (false on unsupported platforms or if the platform call failed).The endpoint may now also return
400 (BadRequest) in addition to existing responses.New Feature
Meta conversion goals on
This lets you run
Use
•
•
POST /v1/ads/create now support optimizing against a Custom Conversion.This lets you run
goal conversions or lead_conversion without providing a standard event type, by pointing the ad set at an existing Custom Conversion.Use
promotedObject.customConversionId (instead of promotedObject.customEventType) for:•
goal=conversions•
goal=lead_conversionNew Feature
SMS carrier registrations now support a preflight dry-run and change-request replies.
Use
Request:
Response:
Use
Also added to
Use
POST /v1/sms/registrations/preflight to validate and preview the exact 10DLC brand/campaign payloads that would be stored, without creating a registration. It returns compliance findings (including AI review when available) so you can fix issues before submitting.Request:
registrationType (standard10dlc | soleprop_10dlc), brand, campaign, optional phoneNumbers, optional messagingBrandNameResponse:
composed, advisories (severity block | warn), verdict (pass | warn | fail | unreviewed), aiUnavailableUse
POST /v1/sms/registrations/{id}/respond to reply to a reviewer change request (when a registration is in changes_requested) with a note, files (hosted URLs), or both—without resubmitting the full registration. On success, status returns to requested.Also added to
POST /v1/sms/registrations: messagingBrandName (2–60 chars) to brand samples/auto-replies when it differs from the legal brand.displayName.Improvement
Webhook limits have increased: you can now configure up to 50 webhooks per user (was 10).
This lets you split event subscriptions across more endpoints/environments without hitting the previous cap.
Applies to:
•
•
This lets you split event subscriptions across more endpoints/environments without hitting the previous cap.
Applies to:
•
GET /v1/webhooks/settings (list up to 50)•
POST /v1/webhooks/settings (create up to 50; 400 if max reached)New Feature
New endpoint
Use it with:
•
•
•
•
•
•
•
To reply to a found tweet, set
Rate limit: 300 requests per 15 minutes per connected account.
GET /v1/twitter/search lets you search public tweets from the last 7 days using an X query (passed through unchanged) to discover tweets to reply to.Use it with:
•
accountId (required)•
query (required, 1–512 chars)•
limit (10–100, default 10)•
cursor (pagination)•
sinceId / untilId (numeric tweet IDs)•
startTime / endTime (ISO 8601 UTC, within last 7 days)•
sortOrder: recency | relevancy (default recency)To reply to a found tweet, set
platformSpecificData.replyToTweetId to the returned tweets[].id when creating a post.Rate limit: 300 requests per 15 minutes per connected account.
Improvement
KYC submission now enforces stricter validation when requesting multiple numbers with an
If you pass
Applies to:
•
•
Key params:
areaCode.If you pass
areaCode and request quantity above that area’s live inventory, the request is rejected with 400 (instead of best-effort skipping).Applies to:
•
POST /v1/phone-numbers/kyc•
POST /v1/whatsapp/phone-numbers/kycKey params:
areaCode, quantity (1–5).Breaking Change
GET /v1/accounts now enforces stricter pagination and query validation.If you use server-side pagination, you must send
page and limit together; sending only one now returns 400. Out-of-range page/limit values are also rejected with 400 (instead of being silently clamped).Key params:
•
page (1-based) + limit (1–100) must be supplied together•
profileId must be a valid ObjectIdImprovement
POST /v1/tools/validate/post now accepts accountId per platform to validate against account-specific limits.For
platform=twitter, providing platforms[].accountId lets validation apply the correct character limit (280 vs 25000 for X Premium). Missing/invalid/foreign IDs fall back to 280 and won’t error.Use:
•
platforms[].platform (enum: twitter, instagram, tiktok, youtube, facebook, linkedin, bluesky, threads, reddit, pinterest, telegram, snapchat, googlebusiness, discord)•
platforms[].accountIdNew Feature
New endpoint
Keywords are populated by the periodic ads discovery sweep (~every 3 hours per account). Campaign-level negative keywords aren’t included (ad-group-level only).
Filter with:
•
•
•
•
•
•
Response returns
GET /v1/ads/keywords is available to list Google Search keyword criteria (positive and negative) synced from connected Google Ads accounts (one row per ad-group keyword).Keywords are populated by the periodic ads discovery sweep (~every 3 hours per account). Campaign-level negative keywords aren’t included (ad-group-level only).
Filter with:
•
accountId, adAccountId (Google customer ID), profileId•
campaignId, adSetId (Google ad group)•
status: active | paused•
matchType: exact | phrase | broad | unknown•
negative: true (negative only) | false (positive only)•
search (substring match), plus pagination via page/limit (1–500)Response returns
keywords with fields like keyword, matchType, status, negative, and syncedAt, plus pagination.Improvement
WhatsApp template endpoints can now return
This makes Meta-side failures explicit so you can distinguish platform outages/rejections from Zernio validation/auth errors.
Applies to:
•
•
•
Also added ad review state support via
502 when Meta rejects the request or is unreachable.This makes Meta-side failures explicit so you can distinguish platform outages/rejections from Zernio validation/auth errors.
Applies to:
•
GET /v1/whatsapp/templates/{templateName}•
PATCH /v1/whatsapp/templates/{templateName}•
DELETE /v1/whatsapp/templates/{templateName}Also added ad review state support via
reviewStatus (schema AdReviewStatus: inreview, approved, rejected, withissues) and Meta-only configuredStatus on Ad to separate delivery status from the ad’s on/off toggle.Improvement
message.sent webhook payload now includes message.source for WhatsApp.This lets you tell whether a sent message came from the WhatsApp Business phone app on a Coexistence number vs being sent through Zernio (dashboard/API/broadcasts).
New field:
message.source = whatsappbusinessapp | cloud_apiOnly present for WhatsApp; absent on non-WhatsApp platforms.
New Feature
New endpoint:
You can send a reviewer message and/or submit corrected requirement data in a single call; submitting corrections re-submits the number back to review, while message-only posts to the reviewer thread.
Request body supports:
•
•
•
•
•
Response includes
POST /v1/phone-numbers/{id}/remediate/respond lets you respond to a regulatory reviewer for a phone number awaiting remediation.You can send a reviewer message and/or submit corrected requirement data in a single call; submitting corrections re-submits the number back to review, while message-only posts to the reviewer thread.
Request body supports:
•
message (max 2000)•
documents[] keyed by requirementId (use base64 or documentId)•
address (corrected address record)•
entityType: individual | business | null•
attachments[] (max 5; each filename + base64)Response includes
status: resubmitted | replied, plus posted, phoneNumber, and siblingsResubmitted.Improvement
GET /v1/profiles now supports exact-name filtering and pagination, and the default sort order is now default-first (then creation date).Use
name (exact match) to find a profile by name, and limit/skip to paginate. When limit or skip is provided, the response may include total, skip, and limit.New query params:
name, limit (1..1000), skip (>=0)POST /v1/profiles now supports idempotent retries via Idempotency-Key (header).With
Idempotency-Key: same key + same body replays the original 201; same key + different body returns 422; key still processing returns 409. Duplicate name conflicts (409) now include details.existingProfileId.New Feature
New endpoint:
Use it when the reviewer asks for info the structured remediation form can’t express; posting a reply can move the number back to
Request body:
•
•
Response
•
•
Errors:
POST /v1/phone-numbers/{id}/remediate/reply lets you reply to a regulatory reviewer on a phone number awaiting remediation, including optional file attachments.Use it when the reviewer asks for info the structured remediation form can’t express; posting a reply can move the number back to
in review (comment-style asks). Requires text or at least one attachments item.Request body:
•
text (string, max 2000)•
attachments (array, max 5) items: { filename, base64 } (PDF/JPG/PNG/WEBP, max 10MB each)Response
200:•
posted (boolean)•
attachments (integer uploaded)Errors:
400, 401, 404, 502 (retry).New Feature
You can now view KYC documents on file via
This streams the stored verification document inline as
KYC spec responses now include
•
•
Use that
GET /v1/phone-numbers/kyc/document/{documentId}.This streams the stored verification document inline as
application/pdf, so users can confirm what’s on file before reusing a verification. Access is auth-scoped (returns 404 if the documentId isn’t referenced by one of your numbers).KYC spec responses now include
documentId on document rows:•
GET /v1/phone-numbers/kyc → reusable.options[].details[].documentId•
GET /v1/whatsapp/phone-numbers/kyc → reusable.options[].details[].documentIdUse that
documentId as the {documentId} path parameter when fetching the PDF.Improvement
KYC reuse selection now supports a stable option identifier via
This makes selecting which prior verification to reuse unambiguous (a phone number may label multiple verifications) and lets you know whether reuse activates in minutes or still queues for carrier review.
Use on submit:
•
•
Returned on form spec:
•
reusable.options[].id, and KYC reuse options now include instant to indicate activation speed.This makes selecting which prior verification to reuse unambiguous (a phone number may label multiple verifications) and lets you know whether reuse activates in minutes or still queues for carrier review.
Use on submit:
•
POST /v1/phone-numbers/kyc: pass reuseOptionId (preferred)•
reuseFrom is now a legacy fallback and may be ambiguousReturned on form spec:
•
GET /v1/phone-numbers/kyc (and the deprecated WhatsApp alias): reusable.options[] now includes id and instantNew Feature
PUT /v1/ads/ad-sets/{adSetId} now supports updating bid strategy for platform=openai.You can set OpenAI ad group bidding via
bidStrategy + bidAmount; bidAmount is converted to micros (× 1,000,000).Use
bidStrategy:•
LOWESTCOSTWITHBIDCAP (requires bidAmount)•
COST_CAP (requires bidAmount)LOWESTCOSTWITHMINROAS is not supported on OpenAI and will return 422.New Feature
Zernio Ads now supports OpenAI Ads (ChatGPT Ads), including connect, create/manage, reporting, and conversions.
Connect an OpenAI Ads account via
Ads endpoints now accept
•
• Campaign/ad set status updates:
Creating ads:
•
• Required creative fields:
• Budget:
Conversions:
• Use
• If no pixel exists yet, create one via
Note:
Connect an OpenAI Ads account via
POST /v1/connect/openai-ads/credentials with apiKey and profileId (requires Ads add-on).Ads endpoints now accept
platform=openai:•
GET /v1/ads, GET /v1/ads/campaigns, GET /v1/ads/tree, GET /v1/ads/timeline• Campaign/ad set status updates:
PUT /v1/ads/campaigns/{campaignId}/status, POST /v1/ads/campaigns/bulk-status, PUT /v1/ads/ad-sets/{adSetId}, PUT /v1/ads/ad-sets/{adSetId}/statusCreating ads:
POST /v1/ads/create supports OpenAI Ads with:•
goal: traffic | awareness | conversions• Required creative fields:
headline, body, imageUrl, linkUrl• Budget:
budgetType must be lifetime (sending daily returns 422) and requires endDateConversions:
POST /v1/ads/conversions now supports accountId platform openaiads.• Use
GET /v1/accounts/{accountId}/conversion-destinations to get the OpenAI pixel destinationId (pixel wire id)• If no pixel exists yet, create one via
POST /v1/accounts/{accountId}/tracking-tags (OpenAI Ads may return 422 if pixel management isn’t enabled)Note:
PUT /v1/ads/{adId} supports OpenAI Ads for status + budget only (no targeting/creative updates). DELETE /v1/ads/{adId} archives OpenAI Ads (no platform delete API).Improvement
YouTube analytics endpoints now support returning provisional (not-yet-finalized) days when you set an explicit
By default,
Applies to:
•
•
•
New response field:
•
endDate up to today.By default,
endDate still resolves to the newest fully finalized day (~3-day delay). If you request into the delay window, the response indicates which days may still change.Applies to:
•
GET /v1/analytics/youtube/daily-views•
GET /v1/analytics/youtube/video-retention•
GET /v1/analytics/youtube/demographicsNew response field:
•
provisionalSince — first date in the returned range whose numbers are provisional and may be revised by YouTube.New Feature
WhatsApp template creation now supports carousel and limited time offer components in
This lets you build richer MARKETING templates (multi-card carousels and offer labels/countdowns) using the same template creation endpoint.
New component types:
•
•
Phone number purchase adds
components on POST /v1/whatsapp/templates.This lets you build richer MARKETING templates (multi-card carousels and offer labels/countdowns) using the same template creation endpoint.
New component types:
•
type=carousel with cards (2–10), each card components can include type=header, type=body, type=buttons•
type=limitedtimeoffer with limitedtimeoffer.text (<=16 chars) and optional limitedtimeoffer.has_expirationPhone number purchase adds
wantsWhatsapp on POST /v1/phone-numbers/purchase (used when connectWhatsapp=false) to ensure the assigned number is WhatsApp-eligible by swapping it during purchase if needed.Improvement
Profile create/update now return 409 Conflict when the profile name is already taken.
This lets clients distinguish name collisions from generic validation errors and handle retries/renames cleanly.
New response:
•
•
Several Ads read endpoints now also document 400 Bad Request for invalid query input:
•
•
•
•
This lets clients distinguish name collisions from generic validation errors and handle retries/renames cleanly.
New response:
•
POST /v1/profiles → 409 (code: profilenameconflict)•
PUT /v1/profiles/{profileId} → 409 (code: profilenameconflict)Several Ads read endpoints now also document 400 Bad Request for invalid query input:
•
GET /v1/ads → 400•
GET /v1/ads/catalogs → 400•
GET /v1/ads/catalogs/{catalogId}/product-sets → 400•
GET /v1/ads/conversions/quality → 400Improvement
Meta ads now support additional promoted-object fields, and some payloads are validated more strictly.
In
•
•
In
In
In
POST /v1/ads/create, promotedObject adds:•
offlineConversionDataSetId•
whatsappPhoneNumberIn
PUT /v1/ads/ad-sets/{adSetId}, platformSpecificData.promotedObject adds the same fields and now rejects unknown keys (additionalProperties: false), returning 400.In
POST /v1/ads/boost and POST /v1/ads/create, Meta adds specialAdCategoryCountry (array of 2-letter ISO codes). It requires specialAdCategories to be set (400 otherwise).GET /v1/ads/audiences and POST /v1/ads/audiences add a new audience type value: meta_engagement.Breaking Change
Discord: new member lookup + search endpoints, and guild member listing now fails fast when the Server Members Intent is missing.
You can now fetch a single member or prefix-search members without the privileged intent (useful when full listing is blocked).
New endpoints:
•
•
Breaking change:
•
SMS: alphanumeric Sender IDs are now supported.
Create and manage branded one-way SMS sender IDs (3–11 chars; letters/digits/spaces; at least one letter) and view the workspace-wide daily cap.
New endpoints:
•
•
•
•
Ads (Meta): new campaign/creative utilities + validate-only dry runs.
You can now create campaign shells, manage the creative library, duplicate ad sets/ads, and run a Meta validation pass without creating anything.
New endpoints:
•
•
•
•
New option on
•
You can now fetch a single member or prefix-search members without the privileged intent (useful when full listing is blocked).
New endpoints:
•
GET /v1/discord/guilds/{guildId}/members/{userId} (accountId)•
GET /v1/discord/guilds/{guildId}/members/search (accountId, query, optional limit) — query is prefix-onlyBreaking change:
•
GET /v1/discord/guilds/{guildId}/members now returns 403 if the Server Members Intent is not enabled (previously Discord could return an empty array).SMS: alphanumeric Sender IDs are now supported.
Create and manage branded one-way SMS sender IDs (3–11 chars; letters/digits/spaces; at least one letter) and view the workspace-wide daily cap.
New endpoints:
•
GET /v1/sms/sender-ids (returns senderIds + budget with cap/usedToday/level/pendingRequest)•
POST /v1/sms/sender-ids (senderId)•
DELETE /v1/sms/sender-ids/{id}•
POST /v1/sms/sender-ids/limit-request (requestedCap, reason)Ads (Meta): new campaign/creative utilities + validate-only dry runs.
You can now create campaign shells, manage the creative library, duplicate ad sets/ads, and run a Meta validation pass without creating anything.
New endpoints:
•
POST /v1/ads/campaigns (standalone campaign)•
POST /v1/ads/creatives, GET /v1/ads/creatives, GET /v1/ads/creatives/{creativeId}, PUT /v1/ads/creatives/{creativeId}, DELETE /v1/ads/creatives/{creativeId}•
GET /v1/ads/images, GET /v1/ads/labels, GET /v1/ads/businesses, GET /v1/ads/high-demand-periods•
POST /v1/ads/ad-sets/{adSetId}/duplicate, POST /v1/ads/{adId}/duplicateNew option on
POST /v1/ads/create:•
validateOnly: true (Meta only; single standalone shape only) — returns 200 with validation results instead of creating entities.Breaking Change
WhatsApp inbound attachments can now be downloaded via
This streams the binary for a WhatsApp attachment referenced by
Call it with:
•
•
•
Important behavior:
• Download on receipt: WhatsApp media expires on Meta’s side (typically ~7 days). After expiry this endpoint returns
Removed endpoints:
•
•
•
•
•
•
•
•
Breaking change (SMS):
GET /v1/whatsapp/media/{mediaId}.This streams the binary for a WhatsApp attachment referenced by
attachments[].url in message.received webhooks and List messages.Call it with:
•
mediaId (path) from attachments[].payload.id•
accountId (query) = the WhatsApp account that received the media•
Authorization: Bearer <your API key> (required; otherwise 401)Important behavior:
• Download on receipt: WhatsApp media expires on Meta’s side (typically ~7 days). After expiry this endpoint returns
400 permanently (do not retry).Removed endpoints:
•
GET /v1/sms/sender-ids, POST /v1/sms/sender-ids, POST /v1/sms/sender-ids/limit-request, DELETE /v1/sms/sender-ids/{id}•
POST /v1/ads/campaigns•
POST /v1/ads/ad-sets/{adSetId}/duplicate•
POST /v1/ads/{adId}/duplicate•
GET /v1/ads/labels•
GET /v1/ads/high-demand-periods•
GET/POST/GET/PUT/DELETE /v1/ads/creatives (and /v1/ads/creatives/{creativeId})•
GET /v1/ads/imagesBreaking change (SMS):
POST /v1/sms/messages no longer supports alphanumeric sender IDs in from (now requires an SMS-enabled number).New Feature
Meta Ads: new endpoints for campaign/creative management, duplication, and library access.
You can now create a standalone campaign shell, duplicate ad sets/ads via Meta native copy, manage creatives separately from ads, and query labels/images/creative library + budget schedules.
New endpoints:
• Create campaign (ODAX shell):
• Duplicate ad set:
• Duplicate ad:
• Creative library + CRUD:
• Libraries/metadata:
• Budget schedules:
Audience updates expanded:
You can now create a standalone campaign shell, duplicate ad sets/ads via Meta native copy, manage creatives separately from ads, and query labels/images/creative library + budget schedules.
New endpoints:
• Create campaign (ODAX shell):
POST /v1/ads/campaigns with goal (engagement, traffic, awareness, videoviews, leadgeneration, leadconversion, jobapplicants, conversions, apppromotion, catalogsales), optional CBO via budgetAmount + budgetType (daily|lifetime), status (ACTIVE|PAUSED)• Duplicate ad set:
POST /v1/ads/ad-sets/{adSetId}/duplicate with deepCopy, campaignId, statusOption (ACTIVE|PAUSED|INHERITEDFROMSOURCE), syncAfter• Duplicate ad:
POST /v1/ads/{adId}/duplicate with adSetId, statusOption (ACTIVE|PAUSED|INHERITEDFROMSOURCE), syncAfter• Creative library + CRUD:
GET /v1/ads/creatives, POST /v1/ads/creatives (use imageUrl or imageHash or carouselCards), GET /v1/ads/creatives/{creativeId}, PUT /v1/ads/creatives/{creativeId} (rename via name), DELETE /v1/ads/creatives/{creativeId}• Libraries/metadata:
GET /v1/ads/images, GET /v1/ads/labels• Budget schedules:
GET /v1/ads/high-demand-periods (exactly one of campaignId or adSetId)Audience updates expanded:
PUT /v1/ads/audiences/{audienceId} now supports updating platform audiences’ name/description (Meta only). spec is still allowed only for saved_targeting; sending spec for a platform audience returns 400. Non-Meta platform audience updates return 501.New Feature
SMS now supports alphanumeric sender IDs (e.g.
Create/manage sender IDs via:
•
•
•
•
Sending:
Notes for sender IDs: text-only (no MMS), recipients can’t reply, and sends to US/CA/PR are blocked.
New responses to handle on
•
•
•
ZERNIO) for one-way international texting.Create/manage sender IDs via:
•
GET /v1/sms/sender-ids (includes workspace daily budget: budget.cap, budget.usedToday, budget.level, budget.pendingRequest)•
POST /v1/sms/sender-ids with senderId (3–11 chars; letters/digits/spaces; at least one letter)•
DELETE /v1/sms/sender-ids/{id}•
POST /v1/sms/sender-ids/limit-request with requestedCap + reasonSending:
POST /v1/sms/messages now accepts from as either an SMS-enabled number or an approved sender ID.Notes for sender IDs: text-only (no MMS), recipients can’t reply, and sends to US/CA/PR are blocked.
New responses to handle on
POST /v1/sms/messages:•
403 (gate: registration/MMS not supported/alpha to US-CA-PR)•
429 (alphanumeric daily cap reached; code alphadailylimit_reached; resets midnight UTC)•
404 now covers “no SMS-enabled number or sender ID matches from”.New Feature
Meta ads now support Reach & Frequency (RESERVED) buying via new R&F prediction + reservation endpoints.
You can request a quote (no spend, no entities created), reserve it to lock price/inventory, then create an ad using the reserved prediction.
New endpoints:
•
•
•
•
•
•
Notes: RESERVED uses the single-ad shape only (no
You can request a quote (no spend, no entities created), reserve it to lock price/inventory, then create an ad using the reserved prediction.
New endpoints:
•
POST /v1/ads/rf-predictions (create quote; provide date range + exactly one of budgetAmount or reach)•
GET /v1/ads/rf-predictions/{predictionId}•
POST /v1/ads/rf-predictions/{predictionId}/reserve (returns a NEW RESERVED predictionId + expiresAt)•
DELETE /v1/ads/rf-predictions/{predictionId} (cancel reservation)POST /v1/ads/create adds:•
buyingType: AUCTION | RESERVED•
rfPredictionId (required when buyingType=RESERVED)Notes: RESERVED uses the single-ad shape only (no
creatives[], adSetId, existingCampaignId, or dynamicCreative). Budget/schedule/pricing come from the reservation; bid fields are ignored.New Feature
New Meta Ads endpoints are available for live reads, auditing, studies, finances, and asset upload.
You can now:
• Read a live Meta ad set (incl. learning phase) via
• Fetch account audit/activity log via
• List A/B tests & lift studies via
• Read ad account finances via
• Upload ad images from base64 via
Also updated:
•
•
•
You can now:
• Read a live Meta ad set (incl. learning phase) via
GET /v1/ads/ad-sets/{adSetId} with accountId and optional fields (default includes learningstageinfo).• Fetch account audit/activity log via
GET /v1/ads/activity using accountId, adAccountId, optional since/until, optional objectId (client-side filter), plus paging limit/after.• List A/B tests & lift studies via
GET /v1/ads/studies with accountId, adAccountId, optional fields, and paging limit/after.• Read ad account finances via
GET /v1/ads/accounts/finance (balance, amountSpent, spendCap, fundingSource).• Upload ad images from base64 via
POST /v1/ads/images with accountId, adAccountId, imageBase64 (optional filename); returns image.hash and image.url.Also updated:
•
specialAdCategories now includes FINANCIALPRODUCTSSERVICES and ONLINEGAMBLINGAND_GAMING on POST /v1/ads/boost and POST /v1/ads/create.•
callToAction enums expanded on POST /v1/ads/create (and Meta creatives[].callToAction) to include values like ADDTOCART, APPLYNOW, BOOKNOW, ORDERNOW, INSTALLMOBILEAPP, USEAPP (plus others).•
POST /v1/ads/conversions: consent now affects Meta too — if adUserData or adPersonalization is DENIED, events are sent with Meta Limited Data Use (LDU); GRANTED (or omitted) uses default processing.Deprecation
New Meta Ads capabilities are available: ad previews, click-to-message ads, and click-to-call ads.
You can now render embeddable preview iframes before creating an ad via
Click-to-message ads are now unified under
•
•
•
Click-to-call ads are supported via
You can now render embeddable preview iframes before creating an ad via
POST /v1/ads/preview (provide exactly one of existingCreativeId or creativeSpec) or for an existing ad via GET /v1/ads/{adId}/preview. Use formats (Meta ad_format values, max 10) to control placements.Click-to-message ads are now unified under
POST /v1/ads/messaging with destination:•
whatsapp•
messenger•
instagram_directClick-to-call ads are supported via
POST /v1/ads/call using phoneNumber (E.164) and linkUrl.POST /v1/ads/ctwa is now deprecated; use POST /v1/ads/messaging with destination: whatsapp (the old endpoint remains for back-compat).New Feature
Meta insights now supports action-level segmentation and attribution controls on both the sync and async insights APIs.
You can segment
New on
•
•
•
•
New on
•
•
•
•
Meta ad creation also adds hand-built carousels via
You can segment
actions[] and control attribution windows/reporting time without changing endpoints.New on
GET /v1/ads/insights:•
actionBreakdowns•
actionAttributionWindows•
actionReportTime•
useUnifiedAttributionSettingNew on
POST /v1/ads/insights/reports:•
actionBreakdowns•
actionAttributionWindows (array of strings)•
actionReportTime•
useUnifiedAttributionSettingMeta ad creation also adds hand-built carousels via
carouselCards on POST /v1/ads/create (2–10 cards, deterministic order).Improvement
Google Business batch reviews now supports server-side sorting via
This lets you fetch newest-updated reviews first (default) and stop paginating earlier when polling for recent changes.
Use
•
•
•
Also note:
Responses now clarify attribution: each
Inbox reviews (
orderBy on POST /v1/accounts/{accountId}/gmb-reviews/batch.This lets you fetch newest-updated reviews first (default) and stop paginating earlier when polling for recent changes.
Use
orderBy:•
updateTime desc (default)•
rating•
rating descAlso note:
locationNames is now capped at maxItems: 50 per request (chunk larger sets).Responses now clarify attribution: each
locationReviews[].name is the LOCATION resource name (not the review resource name), and review includes review.name (full review resource name) plus reviewMediaItems (photos/videos).Inbox reviews (
GET /v1/inbox/reviews) now includes Google Business location attribution fields: locationId (bare id) and locationName (display name).New Feature
POST
This lets you publish a photo comment alongside the text reply. The image URL must be publicly accessible so Meta can fetch it.
New request field:
•
If
/v1/inbox/comments/{postId} now supports attaching an image when replying on Facebook via attachmentUrl.This lets you publish a photo comment alongside the text reply. The image URL must be publicly accessible so Meta can fetch it.
New request field:
•
attachmentUrl (uri) — Facebook onlyIf
attachmentUrl is sent for non-Facebook platforms, the API now returns 400 (e.g. code PLATFORMNOTSUPPORTED).Improvement
POST
You can create TikTok ads/campaigns in a paused state and use additional geo targeting fields for TikTok.
Key changes:
•
• Geo targeting fields now support TikTok:
GET
/v1/ads/create now supports more TikTok controls and targeting.You can create TikTok ads/campaigns in a paused state and use additional geo targeting fields for TikTok.
Key changes:
•
status now applies to Meta and TikTok: ACTIVE | PAUSED (TikTok pauses campaign > ad group > ad)• Geo targeting fields now support TikTok:
cities, regions, metrosGET
/v1/ads/targeting/search: TikTok geo searches now return mixed levels in one list (type can be country | region | city | district | metro), and geoType is not applied for TikTok results.Improvement
TikTok conversion ads created via
This makes it easier to configure
Use
•
Applies to TikTok only;
POST /v1/ads/create now accept TikTok Events Manager event names in promotedObject.customEventType (auto-resolved to the underlying optimization_event code).This makes it easier to configure
goal=conversions without manually mapping to TikTok’s internal codes; note that ONWEBORDER is now deprecated.Use
promotedObject.customEventType with one of:•
SHOPPING, ONWEBCART, INITIATEORDER, FORM, ONWEBREGISTER, ONWEB_DETAILApplies to TikTok only;
promotedObject.pixelId is still required for goal=conversions.New Feature
New Meta Ads insights endpoints are available:
You can now run a flexible live insights query that forwards your chosen Meta Graph parameters (fields/breakdowns/filtering) and returns rows in Meta’s raw shape; use the async report flow for long ranges or large accounts.
Sync query:
Async flow:
• Submit:
• Poll:
Meta only (facebook/instagram). Invalid field/breakdown combos return
GET /v1/ads/insights, POST /v1/ads/insights/reports, GET /v1/ads/insights/reports/{reportRunId}.You can now run a flexible live insights query that forwards your chosen Meta Graph parameters (fields/breakdowns/filtering) and returns rows in Meta’s raw shape; use the async report flow for long ranges or large accounts.
Sync query:
GET /v1/ads/insights with accountId, objectId, optional level (ad/adset/campaign/account), fields, breakdowns, filtering, datePreset or fromDate+toDate, timeIncrement, limit, after.Async flow:
• Submit:
POST /v1/ads/insights/reports (body includes accountId, objectId, optional level, fields, breakdowns, filtering, datePreset or fromDate/toDate, timeIncrement (1-90 | monthly | all_days)) → returns reportRunId• Poll:
GET /v1/ads/insights/reports/{reportRunId} with accountId, limit, after → returns status and percentCompletion; when status is Job Completed, includes data + paging.Meta only (facebook/instagram). Invalid field/breakdown combos return
400 with Meta’s error message.New Feature
Google Business Profiles: you can now assign a GBP location to a different profile by reusing an existing OAuth grant (no browser re-auth).
Use
•
•
•
Returns
Phone number purchasing now supports selecting a number type.
On
Country/type discovery updates:
•
•
•
Facebook connect flow:
Use
POST /v1/accounts/{accountId}/gmb-locations/assign with:•
profileId (target profile)•
selectedLocationId (e.g. locations/123)•
googleAccountId (optional, recommended for accounts with many locations)Returns
409 if the target profile already has a Google Business connection.Phone number purchasing now supports selecting a number type.
On
POST /v1/phone-numbers/purchase you can pass numberType: local | mobile | national | toll_free. Availability/KYC can vary by (country, type).Country/type discovery updates:
•
GET /v1/phone-numbers/countries now includes inStock and types[] (per-type monthlyCents, needsKyc, whatsappAvailable, smsAvailable, callsAvailable, inStock)•
GET /v1/phone-numbers/availability adds optional numberType•
GET /v1/phone-numbers/kyc adds optional numberTypeFacebook connect flow:
POST /v1/connect/facebook/select-page can now return 409 with code RECONNECTACCOUNTMISMATCH when a force=true token-recovery re-auth lands on a different user/page than the existing connection.New Feature
Google Business reviews now include attached photos in review responses.
You can display/download reviewer-uploaded images and know how many photos are attached per review.
Added fields:
•
•
Notes:
You can display/download reviewer-uploaded images and know how many photos are attached per review.
Added fields:
•
GET /v1/accounts/{accountId}/gmb-reviews → reviews[].photoCount, reviews[].photos[] (each item: url)•
GET /v1/inbox/reviews → data[].photos[] (Google Business only; each item: url)Notes:
photoCount counts photos only (videos not counted). For non-Google platforms, photos is always an empty array.New Feature
Meta campaign updates now support a lifetime spend cap via
This lets you set or remove a campaign-level spend cap without recreating the campaign.
Use:
•
•
Meta ad set updates now accept post-launch delivery settings via
Set any of:
•
•
•
•
Also added:
platformSpecificData.spendCap on PUT /v1/ads/campaigns/{campaignId}.This lets you set or remove a campaign-level spend cap without recreating the campaign.
Use:
•
platformSpecificData.spendCap = number (sets cap)•
platformSpecificData.spendCap = null (removes cap; Meta rejects 0)Meta ad set updates now accept post-launch delivery settings via
platformSpecificData on PUT /v1/ads/ad-sets/{adSetId}.Set any of:
•
platformSpecificData.optimizationGoal•
platformSpecificData.billingEvent•
platformSpecificData.startDate, platformSpecificData.endDate•
platformSpecificData.promotedObject (e.g. pixelId, customEventType, pageId, applicationId, objectStoreUrl, customConversionId, productCatalogId, productSetId)Also added:
billingEvent (Meta only) on POST /v1/ads/create to explicitly set the ad set’s billing event (defaults to IMPRESSIONS).Breaking Change
Queue schedules:
This lets you clear a profile’s entire queue schedule in one call (previously
Use:
•
•
Sequences:
Response now includes
Also:
DELETE /v1/queue/slots now supports deleting all queues for a profile by omitting queueId.This lets you clear a profile’s entire queue schedule in one call (previously
queueId was required).Use:
•
profileId (required)•
queueId (optional) — omit to delete all queuesSequences:
POST /v1/sequences/{sequenceId}/enroll now returns per-contact outcomes.Response now includes
failed and results (array of { contactId, success, error }) in addition to enrolled.Also:
GET /v1/queue/slots expands all to true | false.Improvement
GET
You can raise the maximum number of Google Business Profile locations returned (default was effectively 100) up to 500 to enumerate accounts with more than 100 locations.
Use
•
Invalid values now return
/v1/accounts/{accountId}/gmb-locations now supports a limit query parameter.You can raise the maximum number of Google Business Profile locations returned (default was effectively 100) up to 500 to enumerate accounts with more than 100 locations.
Use
limit:•
limit (integer, default 100, min 1, max 500)Invalid values now return
400 (e.g. limit out of range).New Feature
YouTube demographics analytics now supports per-video audience breakdowns via
Pass
Use:
•
•
Response adds (video mode only):
Also: Meta city targeting docs were updated to reflect that
videoId on GET /v1/analytics/youtube/demographics.Pass
videoId to fetch demographics for a single video (instead of the whole channel). Note: YouTube may return empty breakdowns for low-traffic videos due to signed-in view thresholds.Use:
•
videoId - YouTube video ID (scoped to the connected channel; otherwise 404)•
startDate - defaults to the video publish date (lifetime) when videoId is providedResponse adds (video mode only):
videoId, title, publishedAt.Also: Meta city targeting docs were updated to reflect that
cities[].radius has a minimum (~17 km / 10 mi). Smaller values can produce a 0-size audience and fail at launch; use customLocations for tighter radius targeting.Improvement
GET
This lets you proactively refresh stored tokens (the endpoint normally returns
Use
New param:
/v1/connect/{platform}/ads now supports force to trigger a fresh OAuth flow even when an ads account is already connected.This lets you proactively refresh stored tokens (the endpoint normally returns
alreadyConnected: true based on account active state, not token liveness).Use
force=true to always receive authUrl; completing OAuth refreshes the stored token on the existing posting + ads accounts in place.New param:
force (true/false, default false)Breaking Change
SMS carrier registration
You may now see pre-submission review and deactivation states when listing, fetching, or reusing registrations, which can affect clients that assume only the previous 3 statuses.
Updated
•
Applies to:
•
•
•
Also added to
•
•
status now includes additional lifecycle states in registration APIs.You may now see pre-submission review and deactivation states when listing, fetching, or reusing registrations, which can affect clients that assume only the previous 3 statuses.
Updated
status enum:•
pending, approved, rejected, requested, changes_requested, deactivatedApplies to:
•
GET /v1/sms/registrations•
GET /v1/sms/registrations/{id}•
POST /v1/phone-numbers/{id}/sms/reuse-registrationAlso added to
POST /v1/sms/registrations request body:•
resubmitRequestId (resubmit an existing registration returned for changes)•
wizardValues (optional raw wizard answers; can be omitted by API integrators)Improvement
conversions in ads metrics now includes non-Meta platforms.You can now rely on
conversions for more platforms when charting or aggregating performance (instead of always getting 0 outside Meta).Applies to:
•
GET /v1/ads/timeline (rows[].conversions)•
AdMetrics.conversionsNew platform behavior:
• Meta: events matching the campaign optimization goal
• Google: tracked conversions
• X / LinkedIn: reported website/lead conversions (added 2026-07)
Improvement
GET
Deactivated (terminated) registrations are hidden by default; pass
New query param:
•
/v1/sms/registrations now supports includeDeactivated (boolean).Deactivated (terminated) registrations are hidden by default; pass
includeDeactivated=true to include them in the results.New query param:
•
includeDeactivated - true to include deactivated registrations (default: hidden)New Feature
New endpoint:
This terminates the carrier registry campaign so recurring monthly campaign fees stop; numbers under the registration can no longer send texts (receiving is unaffected). Deactivation is irreversible and the operation is idempotent.
Key parameter:
Response:
DELETE /v1/sms/registrations/{id} to deactivate an SMS brand/campaign registration.This terminates the carrier registry campaign so recurring monthly campaign fees stop; numbers under the registration can no longer send texts (receiving is unaffected). Deactivation is irreversible and the operation is idempotent.
Key parameter:
id (path, string)Response:
200 returns status = deactivated (enum: deactivated)New Feature
LinkedIn now supports Thought Leader ads on
This lets you create a LinkedIn ad that references an existing post (share/ugcPost) as the creative, while still using the normal
Set:
•
Notes:
• Mutually exclusive with other LinkedIn creative sources in
• When using
POST /v1/ads/create via platformSpecificData.thoughtLeader.This lets you create a LinkedIn ad that references an existing post (share/ugcPost) as the creative, while still using the normal
/v1/ads/create flow for targeting/bidding/schedule.Set:
•
platformSpecificData.thoughtLeader.postUrn (pattern: urn:li:share:\d+ or urn:li:ugcPost:\d+)Notes:
• Mutually exclusive with other LinkedIn creative sources in
platformSpecificData (e.g. carousel, document, conversation, etc.)• When using
thoughtLeader, you don’t need headline/body/imageUrl/organizationId for the creative (the referenced post provides them).New Feature
New LinkedIn-only Ads helpers are available:
• Suggested bid & budget bounds via
Returns suggested bid + allowed bid limits and daily budget bounds for a targeting spec (use before
Key request fields:
Response:
• Impressions/clicks/spend forecast via
Forecasts metrics for a targeting spec over a future time range.
Key request fields:
Response:
For non-LinkedIn accounts, both endpoints return
• Suggested bid & budget bounds via
POST /v1/ads/targeting/bid-pricingReturns suggested bid + allowed bid limits and daily budget bounds for a targeting spec (use before
POST /v1/ads/create).Key request fields:
accountId, adAccountId, spec, optional campaignType (TEXTAD/SPONSOREDUPDATES/SPONSOREDINMAILS), bidType (CPM/CPC/CPV), matchType (EXACT/AUDIENCEEXPANDED), dailyBudget.Response:
available and pricing (may be null).• Impressions/clicks/spend forecast via
POST /v1/ads/targeting/supply-forecastForecasts metrics for a targeting spec over a future time range.
Key request fields:
accountId, adAccountId, spec, timeRangeStart, timeRangeEnd, plus either dailyBudget or totalBudget. For manual bidding, set competingBid with bidType (CPM/CPC/CPV) and amount; for auto-bidding, set optimizationTarget.Response:
available and forecast series with metricType and granularity (DAILY/SEVENDAY/THIRTYDAY/CUSTOM).For non-LinkedIn accounts, both endpoints return
available: false (not an error).New Feature
New endpoint
Send
Response:
Errors:
POST /v1/sms/opt-in-proof uploads SMS opt-in proof (screenshot/PDF) and returns a public URL you can include in a campaign’s messageFlow for carrier review.Send
multipart/form-data with file (PNG/JPG/WebP/GIF/PDF, max 4MB).Response:
{ "url": "..." }Errors:
422 unsupported type/too large, 401 unauthorized. Alias: /v1/sms/registrations/{id}/opt-in-proof.New Feature
POST
Set
New field:
/v1/sms/messages now supports scheduling via sendAt.Set
sendAt (ISO 8601 date-time with offset) to queue an SMS/MMS for a future time; it must be in the future. The message is queued and the message.delivered webhook fires when it actually sends.New field:
sendAtImprovement
SMS carrier registration now accepts optional policy URLs on 10DLC campaigns via
You can include privacy/terms links in the
New
•
•
Also,
POST /v1/sms/registrations.You can include privacy/terms links in the
campaign object to help carrier reviewers validate compliance.New
campaign properties:•
privacyPolicyLink•
termsAndConditionsLinkAlso,
embeddedLink and embeddedPhone now document auto-derivation from your sample messages when omitted.New Feature
New endpoint:
Use it to host proof of consent when submitting
Request:
Response:
Errors:
POST /v1/sms/registrations/{id}/opt-in-proof uploads an SMS opt-in form screenshot/PDF and returns a public URL you can include in an appeal.Use it to host proof of consent when submitting
POST /v1/sms/registrations/{id}/appeal (add the returned URL to your messageFlow).Request:
multipart/form-data with file (PNG/JPG/WebP/GIF/PDF, max 4MB)Response:
{ "url": "..." }Errors:
404 registration not found, 422 unsupported type/too largeNew Feature
New endpoint:
The returned
Request body:
•
•
•
Response (201):
POST /v1/accounts/{accountId}/pinterest-boards to create Pinterest boards on a connected Pinterest account.The returned
board.id can be used immediately as platformSpecificData.boardId when creating a Pinterest post.Request body:
•
name (required)•
description•
privacy: PUBLIC | PROTECTED | SECRET (default PUBLIC)Response (201):
board with id, name, description, privacy, url.New Feature
Website retargeting audiences are now supported via a new audience type:
You can now create and list these audiences using
When creating, set:
•
•
website_retargeting (LinkedIn only).You can now create and list these audiences using
type=website_retargeting on POST /v1/ads/audiences and filter them via GET /v1/ads/audiences.When creating, set:
•
type: website_retargeting•
matchRules: array of URL patterns (matchType: EXACT | STARTSWITH | CONTAINS | ENDSWITH, plus matchValue)New Feature
Custom audiences now support new types:
You can list and filter these via
To create them via
•
•
company_list and engagement on /v1/ads/audiences.You can list and filter these via
GET /v1/ads/audiences using type = customerlist | companylist | engagement | website | lookalike | saved_targeting.To create them via
POST /v1/ads/audiences:•
type=engagement (LinkedIn): requires sourceType (VIDEOADS | LEADGENFORMS | ORGANIZATIONPAGES | EVENTPAGES | SINGLEIMAGE_ADS), plus trigger, lookbackDays (30 | 60 | 90 | 180 | 365), and engagementSources.•
type=company_list (LinkedIn): requires companies (array of company rows like name, domain, website, linkedinPageUrl).New Feature
LinkedIn firmographic breakdowns are now supported in analytics via the
This lets you request LinkedIn aggregated firmographic segments for the requested date range (note: LinkedIn data is aggregated over the whole range, delayed 12–24h, and segments with <3 events are omitted).
Use
•
•
•
LinkedIn breakdown rows include the raw pivot
breakdowns query param on GET /v1/ads/{adId}/analytics and GET /v1/ads/campaigns/{campaignId}/analytics.This lets you request LinkedIn aggregated firmographic segments for the requested date range (note: LinkedIn data is aggregated over the whole range, delayed 12–24h, and segments with <3 events are omitted).
Use
breakdowns with LinkedIn dimensions:•
jobtitle, jobfunction, seniority, industry•
company, company_size•
country, regionLinkedIn breakdown rows include the raw pivot
value plus a resolved name.New Feature
POST /v1/ads/create now supports LinkedIn Jobs ads via a new goal
This lets you create Dynamic Jobs Ads that promote open roles (requires a Company Page with active job postings).
Use:
•
•
Also added for LinkedIn-only creatives on
•
job_applicants.This lets you create Dynamic Jobs Ads that promote open roles (requires a Company Page with active job postings).
Use:
•
goal: job_applicants•
platformSpecificData.jobs with headline and buttonLabel (each takes exactly one of preApproved or custom)Also added for LinkedIn-only creatives on
platformSpecificData:•
conversation (Conversation Ads) with subject, firstMessageId, and messages (buttons use exactly one of nextMessageId or url).New Feature
POST
You can create LinkedIn-only creatives (beyond single image/video) by setting one of these mutually-exclusive options:
•
•
•
•
•
•
Notes:
• Carousel cards use
• Document ads use
• Spotlight ads use
• Follower ads use
Also clarified: on LinkedIn,
/v1/ads/create now supports more LinkedIn ad formats via platformSpecificData.You can create LinkedIn-only creatives (beyond single image/video) by setting one of these mutually-exclusive options:
•
platformSpecificData.carousel (2–10 cards)•
platformSpecificData.document (PDF/PPT/DOC)•
platformSpecificData.spotlight (dynamic spotlight)•
platformSpecificData.follower (dynamic follower)•
platformSpecificData.textAd (right-rail text ad)•
platformSpecificData.event (promote an existing event)Notes:
• Carousel cards use
cards[].imageUrl and optionally cards[].headline / cards[].landingUrl (falls back to ad-level linkUrl).• Document ads use
document.url + document.title.• Spotlight ads use
spotlight.headline + spotlight.callToAction + spotlight.landingUrl.• Follower ads use
follower.callToAction enum: VISITORGANIZATIONCOMPANYPAGE, VISITORGANIZATIONLIFEPAGE, VISITORGANIZATIONJOBSPAGE, VISITORGANIZATIONCAREERSPAGE.Also clarified: on LinkedIn,
imageUrl + linkUrl publishes an ARTICLE-content creative (with longHeadline as the description).New Feature
Sole-prop 10DLC registrations can now re-send the OTP via
Use this when the original code expired or never arrived. It only works while the registration is pending and awaiting OTP, and is rate-limited to 1 request/min.
Request:
Response:
Errors:
Port-in updates:
•
•
10DLC campaign submissions:
•
POST /v1/sms/registrations/{id}/resend-otp.Use this when the original code expired or never arrived. It only works while the registration is pending and awaiting OTP, and is rate-limited to 1 request/min.
Request:
id (path)Response:
{ sent: boolean }Errors:
400 not awaiting OTP, 404 not found, 429 wait 1 minutePort-in updates:
•
POST /v1/phone-numbers/port-in: endUser.accountNumber is now required (and endUser.countryCode is restricted to US/CA)•
POST /v1/phone-numbers/port-in/check: response adds lineType (when known) to indicate if a transfer PIN is required at submit10DLC campaign submissions:
•
POST /v1/sms/registrations: campaign.optinMessage, campaign.optoutMessage, and campaign.helpMessage are now optional; when omitted, compliant templates are generated.New Feature
LinkedIn ads now support campaign bidding & delivery controls via
This lets you set LinkedIn-specific options (manual bids, cost model, audience expansion, Audience Network, etc.) while keeping the platform inferred from
Use
•
•
•
•
•
platformSpecificData on POST /v1/ads/create and POST /v1/ads/boost.This lets you set LinkedIn-specific options (manual bids, cost model, audience expansion, Audience Network, etc.) while keeping the platform inferred from
accountId (sending options for a different platform returns 400).Use
platformSpecificData (LinkedIn only):•
costType: CPM | CPC | CPV•
unitCost (manual bid; requires costType)•
optimizationTargetType (pass-through)•
creativeSelection: OPTIMIZED | ROUND_ROBIN•
audienceExpansionEnabled, offsiteDeliveryEnabled, connectedTelevisionOnlyNew Feature
Comment-to-DM automations now support message variations for random rotation of DM text and public comment replies.
This lets you provide multiple alternate texts so repeat triggers don’t always send identical messages.
New optional fields:
• Create/Update:
• Returned on list/detail/update responses:
Rotation behavior:
• DM text is picked at random from
• Public reply is picked at random from
Applies to:
This lets you provide multiple alternate texts so repeat triggers don’t always send identical messages.
New optional fields:
• Create/Update:
dmMessageVariations (up to 5), commentReplyVariations (up to 5)• Returned on list/detail/update responses:
dmMessageVariations, commentReplyVariationsRotation behavior:
• DM text is picked at random from
[dmMessage, ...dmMessageVariations]• Public reply is picked at random from
[commentReply, ...commentReplyVariations]Applies to:
POST /v1/comment-automations, PATCH /v1/comment-automations/{automationId}, GET /v1/comment-automations, GET /v1/comment-automations/{automationId}.Improvement
Analytics responses now include media accessibility alt text via
Use this to display or audit the alt text set on each media item when available.
New field:
•
Included in:
•
•
mediaItems[].altText.Use this to display or audit the alt text set on each media item when available.
New field:
•
mediaItems[].altText (string)Included in:
•
AnalyticsSinglePostResponse•
AnalyticsListResponseImprovement
GET
This lets you detect and display reviews with attached photos (Google Business only; other platforms return
New fields:
•
•
GET
Use this to validate budget inputs against account-level minimums (field may be absent if the connected token can’t read it).
New field:
•
/v1/inbox/reviews now returns Google Business review photo info via hasPhotos and photoCount.This lets you detect and display reviews with attached photos (Google Business only; other platforms return
hasPhotos=false and photoCount=0).New fields:
•
hasPhotos•
photoCountGET
/v1/ads/accounts now includes Meta’s minimum daily budget via minimumDailyBudget.Use this to validate budget inputs against account-level minimums (field may be absent if the connected token can’t read it).
New field:
•
minimumDailyBudgetNew Feature
Meta ads now support setting EU DSA (Article 26) defaults at the ad-account level, so EU-targeted calls can omit per-ad
Set defaults once via
Read current defaults via
dsaBeneficiary/dsaPayor when defaults are configured.Set defaults once via
PATCH /v1/ads/accounts with accountId, adAccountId, defaultDsaBeneficiary, optional defaultDsaPayor (if omitted, payor defaults to beneficiary).Read current defaults via
GET /v1/ads/dsa-defaults (accountId, adAccountId), and fetch Meta-provided suggestions via GET /v1/ads/dsa-recommendations (accountId, adAccountId).POST /v1/ads/create, POST /v1/ads/boost, and POST /v1/ads/ctwa now treat dsaBeneficiary/dsaPayor as optional for EU targeting when the Meta ad account has defaults set (Meta accounts only; other platforms return 400).Improvement
POST
Use
New/updated request behavior:
•
•
•
/v1/phone-numbers/port-in now supports portType to specify whether you’re porting the entire losing account or only some numbers.Use
portType to avoid ambiguity on ports where the losing account keeps some numbers.New/updated request behavior:
•
portType: full | partial (default: full)•
endUser.billingPhoneNumber: now documented as the number on the losing carrier’s bill; defaults to the ported number itself on single-number orders•
focDatetimeRequested: when omitted, defaults to ~1 week out (shifted off weekends)New Feature
New endpoint:
This is ad-scoped only (does not affect the parent ad set/campaign), and is a thin wrapper around updating the ad
Set
Response includes
PUT /v1/ads/{adId}/status to pause/resume a single ad.This is ad-scoped only (does not affect the parent ad set/campaign), and is a thin wrapper around updating the ad
status.Set
status to active or paused. {adId} accepts Zernio _id, Meta platformAdId, or the creative’s effective story/media IDs.Response includes
updated (1/0) and skipped (1/0); message is returned when the change is skipped (terminal status or already in target state).New Feature
conversation.started webhooks now include SMS conversations via conversation.platform.This lets you receive “new conversation started” events for SMS in the same platform-agnostic subscription.
New enum value:
•
conversation.platform: sms (in addition to existing platforms)New Feature
WhatsApp template sends via
This lets you use a single approved template with an image/video/document header while sending a different asset for each recipient (e.g. a unique invoice PDF), instead of always sending the template’s approved sample asset.
Set
•
• Provide exactly one of
• Optional:
POST /v1/inbox/conversations now support overriding a media-header template asset per message using headerMedia.This lets you use a single approved template with an image/video/document header while sending a different asset for each recipient (e.g. a unique invoice PDF), instead of always sending the template’s approved sample asset.
Set
headerMedia (JSON body only):•
type: image | video | document (must match the template header type)• Provide exactly one of
link (public URL) or id (Meta media id)• Optional:
filename (document only)Improvement
GET
This lets you filter out ad accounts that can’t currently create/run ads and show a user-friendly reason in your UI.
New fields in
•
•
On non-Meta platforms these fields are absent (treat
/v1/ads/accounts now returns Meta ad account usability flags: selectable and unusableReason.This lets you filter out ad accounts that can’t currently create/run ads and show a user-friendly reason in your UI.
New fields in
accounts[] (Meta only):•
selectable (boolean) — whether the account can create/run ads now•
unusableReason (string|null) — reason when selectable is false; null when selectableOn non-Meta platforms these fields are absent (treat
selectable as true).Improvement
GET /v1/inbox/conversations/search now searches by contact identity (participant name/username/phone) in addition to message text, returning matching conversations once (message matches included when present).Contact-identity matches are case-insensitive substrings; they return
matchCount=0 and matches=[]. Note: identity matching is not applied when direction is set (incoming | outgoing).Also updated:
• Searchable platforms now include Twitter/X and Reddit; Bluesky is live-fetched and appears in
meta.accountsSkipped• Response adds
conversation.lastMessage (most recent message preview)Improvement
Meta placements now support delivering ads on WhatsApp by allowing
This lets you explicitly include WhatsApp inventory when using manual placements (instead of relying on automatic placements).
Set
•
Applies to:
•
•
whatsapp in placements.publisherPlatforms.This lets you explicitly include WhatsApp inventory when using manual placements (instead of relying on automatic placements).
Set
placements.publisherPlatforms to include:•
whatsapp (alongside facebook, instagram, threads, messenger, audience_network)Applies to:
•
POST /v1/ads/create•
POST /v1/ads/ctwaImprovement
POST
This lets you restrict CTWA ad delivery to specific Meta surfaces/devices instead of using automatic placements (Meta may still enforce eligibility/co-selection rules and return actionable errors).
Use
•
•
•
/v1/ads/ctwa now supports manual ad placements via placements.This lets you restrict CTWA ad delivery to specific Meta surfaces/devices instead of using automatic placements (Meta may still enforce eligibility/co-selection rules and return actionable errors).
Use
placements with:•
publisherPlatforms: facebook | instagram | threads | messenger | audience_network•
facebookPositions, instagramPositions, messengerPositions, audienceNetworkPositions, threadsPositions, whatsappPositions•
devicePlatforms: mobile | desktopImprovement
GET /v1/usage now includes estimated tax via a new tax field on UsageMetering.This lets you show an estimated tax amount (computed with Stripe Tax) on top of the window’s net spend (
totals.total). tax is null when no billing address is on file, the total is ≤ 0, or the estimate fails.New fields:
•
tax.taxUsd — estimated tax in USD (added on top of totals.total)•
tax.ratePercent — combined rate percentage (nullable)•
tax.jurisdictionLabel — human label like “ES VAT” (nullable)•
tax.reverseCharge — true for EU/UK B2B reverse charge (0 tax added)Improvement
Webhooks now support additional event subscriptions for conversations, calls, leads, and WhatsApp.
You can subscribe to these new
•
•
•
•
SMS carrier registrations (10DLC) now accept
For rejected registrations,
You can subscribe to these new
events via POST /v1/webhooks/settings or PUT /v1/webhooks/settings:•
conversation.started•
call.received, call.ended, call.failed, call.permission_request•
lead.received•
whatsapp.automatic_eventSMS carrier registrations (10DLC) now accept
campaign.subUsecases on POST /v1/sms/registrations (2–5 values): 2FA, ACCOUNTNOTIFICATION, CUSTOMERCARE, DELIVERYNOTIFICATION, FRAUDALERT, HIGHEREDUCATION, MARKETING, POLLINGVOTING, PUBLICSERVICEANNOUNCEMENT, SECURITY_ALERT.For rejected registrations,
GET /v1/sms/registrations/{id} may now include campaignContent (messageFlow, sample1, sample2), and POST /v1/sms/registrations/{id}/appeal can include corrected messageFlow/sample1/sample2 along with appealReason.New Feature
New billing snapshot endpoint:
It returns the billing “statement” view (plan, current cycle, balance/credits, spend caps, and payment/access status). Use this for billing state; use
Key response blocks:
•
•
•
•
•
Also:
• Default (no metering params): same snapshot as before
• Metering mode (billed spend by product) when passing any of:
Metering params:
•
•
•
Stripe accounts calling metering mode receive
GET /v1/billing.It returns the billing “statement” view (plan, current cycle, balance/credits, spend caps, and payment/access status). Use this for billing state; use
GET /v1/usage for usage/metering.Key response blocks:
•
plan (includes isUsageBased)•
period (start/end may be null on Stripe)•
balance (null for Stripe; populated for Metronome)•
caps (e.g. xSpendUsedCents, xSpendLimitCents)•
status (e.g. hasAccess, suspended, openInvoiceUrl, declineReason)Also:
GET /v1/usage is now dual-mode.• Default (no metering params): same snapshot as before
• Metering mode (billed spend by product) when passing any of:
range, granularity, from, toMetering params:
•
range: cycle | prev-cycle | 7d | 14d | 30d | 3mo | 12mo | custom•
granularity: day | month | total•
from/to required when range=customStripe accounts calling metering mode receive
{ "supported": false }.New Feature
POST
You can either upload bytes with
New JSON body option:
•
•
New response to handle:
•
/v1/whatsapp/business-profile/photo now accepts an image via URL in addition to multipart upload.You can either upload bytes with
multipart/form-data (file) or send application/json with url; we fetch the image server-side and upload the bytes to Meta.New JSON body option:
•
accountId•
url (public https image URL; must resolve directly without redirects)New response to handle:
•
422 when the profile photo is locked for WhatsApp coexistence numbers (must be managed in the WhatsApp Business app).Breaking Change
POST
This can break existing integrations that submit
For
For
Webhook post events now echo back your post’s free-form
•
•
/v1/sms/registrations now enforces additional required fields for 10DLC registrations.This can break existing integrations that submit
brand/campaign without the newly-required fields.For
brand, these fields are now required: website, street, city, state, postalCode (in addition to existing required fields).For
campaign, sample2 is now required and must be distinct from sample1.Webhook post events now echo back your post’s free-form
metadata (when provided at create time) in:•
WebhookPayloadPost.post.metadata•
WebhookPayloadPostPlatform.post.metadataBreaking Change
Google Business Profile posts:
If you were sending
•
•
•
offer.offerType has been removed from GoogleBusinessPlatformData.If you were sending
offerType (previously OFFER or BUYONEGET_ONE), remove it from your payloads and use the remaining offer fields instead:•
redeemOnlineUrl•
termsConditions•
couponCodeBreaking Change
The supported
If you request breakdowns that are no longer supported, your call may fail (400) or no longer return those breakdowns.
Affected endpoints:
•
•
breakdowns values were reduced on analytics endpoints.If you request breakdowns that are no longer supported, your call may fail (400) or no longer return those breakdowns.
Affected endpoints:
•
GET /v1/ads/{adId}/analytics: Meta breakdowns now limited to age, gender, country, publisherplatform, deviceplatform, region (removed: platformposition, impressiondevice, videoasset, imageasset, bodyasset, titleasset; also removed aliases placement and singular breakdown)•
GET /v1/ads/campaigns/{campaignId}/analytics: Meta breakdowns now limited to age, gender, country, publisherplatform, deviceplatform, region, platformposition, impressiondevice, videoasset, imageasset, bodyasset, titleasset (removed aliases placement and singular breakdown)New Feature
GET /v1/analytics now supports a new metric: follows.You can read
analytics.follows in responses (Instagram feed posts and stories only: organic accounts that started following from this post; 0 for reels and other platforms).You can also sort analytics results by
sortBy = follows (enum now includes: date, engagement, impressions, reach, likes, comments, shares, saves, clicks, views, follows).Breaking Change
GET /v1/ads/{adId}/analytics and GET /v1/ads/campaigns/{campaignId}/analytics now validate breakdown dimensions and will return 400 for unknown values.This prevents silent/partial breakdown results and makes invalid
breakdowns requests fail fast with a supported-values list.Updates:
•
breakdowns: unknown dimensions now return 400 (instead of being ignored)•
placement is accepted as an alias for publisher_platform•
breakdown (singular) is also acceptedNew Meta breakdown options include:
platformposition, impressiondevice, videoasset, imageasset, bodyasset, titleasset.New Feature
You can now update saved_targeting audiences via
This lets you change an audience’s
Request body (send at least one):
Also:
PUT /v1/ads/audiences/{audienceId}.This lets you change an audience’s
name, description, or fully replace its spec (no merge). Uploaded/derived audiences aren’t updatable and return 422.Request body (send at least one):
name, description, specAlso:
GET /v1/ads/audiences now returns accountId for type=savedtargeting items, and DELETE /v1/ads/audiences/{audienceId} clarifies that savedtargeting deletes only the local record (it exists only on Zernio).Improvement
Ads reporting endpoints may now return
When this happens, the response includes currently-available data plus
Applies to:
•
•
•
•
•
Also,
•
•
202 when part of the requested date range isn’t ingested yet.When this happens, the response includes currently-available data plus
backfillPending: true, and a Retry-After header with the recommended poll interval. Repeat the same request until it returns 200 with the full range.Applies to:
•
GET /v1/ads•
GET /v1/ads/tree•
GET /v1/ads/timeline•
GET /v1/ads/campaigns/{campaignId}/analytics•
GET /v1/ads/{adId}/analyticsAlso,
POST /v1/posts 403 responses now include a stable code to distinguish causes:•
ACCOUNT_DISCONNECTED•
PROFILEOVERLIMITNew Feature
WhatsApp inbox messages now support commerce interactive messages (products, product lists, catalog messages, and carousels) via
This lets you send catalog-driven messages and receive cart submissions / product inquiries back in webhooks.
New
•
Webhook
•
•
Note: interactive messages are session messages (must be sent within WhatsApp’s 24-hour window).
interactive on POST /v1/inbox/conversations/{conversationId}/messages.This lets you send catalog-driven messages and receive cart submissions / product inquiries back in webhooks.
New
interactive.type values:•
product, productlist, catalogmessage, carouselWebhook
message.received metadata adds:•
metadata.order (cart submitted from commerce messages)•
metadata.referredProduct (product inquiry context)Note: interactive messages are session messages (must be sent within WhatsApp’s 24-hour window).
Improvement
GET
You can display richer mention attribution (when available) without extra profile resolution on your side.
New fields:
•
•
•
/v1/inbox/mentions now returns additional LinkedIn author details in each mention.You can display richer mention attribution (when available) without extra profile resolution on your side.
New fields:
•
authorName - display name resolved from authorUrn (can be null)•
authorUsername - LinkedIn vanity name (can be null)•
authorPicture - author profile picture URL (can be null; CDN URLs may expire, so fetch promptly)New Feature
Meta ad metrics now include video performance fields in
You can track video starts, thruplays, 30s views, completion percentiles, and average watch time for hook/hold/drop-off analysis. These fields are Meta video ads only (0 for non-video ads and other platforms).
New fields:
•
•
•
•
•
Note: in
AdMetrics (and therefore AdDailyMetrics).You can track video starts, thruplays, 30s views, completion percentiles, and average watch time for hook/hold/drop-off analysis. These fields are Meta video ads only (0 for non-video ads and other platforms).
New fields:
•
videoPlayActions•
video30SecWatchedActions•
videoThruplayWatchedActions•
videoP25WatchedActions, videoP50WatchedActions, videoP75WatchedActions, videoP95WatchedActions, videoP100WatchedActions•
videoAvgTimeWatchedActionsNote: in
AdDailyMetrics, videoAvgTimeWatchedActions is recomputed per day; don’t sum or plain-average it across days (the range value is play-weighted).New Feature
New endpoint:
You can now search message text across stored inbox conversations and get back matching conversations with up to 3 most-recent matching messages per conversation (useful for finding threads by topic or filtering by sent/received).
Key params:
•
•
•
•
•
Response includes
Requires Inbox addon (
GET /v1/inbox/conversations/search.You can now search message text across stored inbox conversations and get back matching conversations with up to 3 most-recent matching messages per conversation (useful for finding threads by topic or filtering by sent/received).
Key params:
•
query (required, 2–200 chars)•
direction: incoming | outgoing•
platform: facebook | instagram | telegram | whatsapp | sms•
profileId, accountId•
limit (1–50, default 20), cursorResponse includes
data[].conversation, matchCount, matches (up to 3), plus pagination and meta.accountsSkipped for connected accounts on live-fetched platforms that can’t be searched.Requires Inbox addon (
403 if missing).Improvement
Inbox webhook account context now includes optional
Use
profileId in InboxWebhookAccount.Use
profileId (workspace/profile ID) to route or filter inbox webhooks by workspace. It may be omitted for the shared WhatsApp sandbox account or when the account has no resolvable profile.New Feature
New API surfaces for Usage, Calls, Voice (PSTN), SMS, and Phone Numbers are now available, including a unified call history and a new usage “hub”. Several older WhatsApp-prefixed paths are now deprecated aliases of the new canonical endpoints.
Usage snapshot + breakdowns:
•
•
•
Unified call history (WhatsApp + PSTN) + recordings:
•
•
•
WhatsApp call history improvements:
•
•
PSTN Voice calling (new):
•
•
• Call control:
• Browser softphone handshake:
SMS (new):
•
•
• Opt-outs export:
• US carrier registration flows:
Phone Numbers (new canonical resource):
•
• Purchase + inventory:
• Regulated KYC:
• Port-in:
WhatsApp Calling config is now number-keyed:
• New canonical sub-resource:
• Existing
Deprecated aliases (no immediate break, but new integrations should switch):
•
• Many
Usage snapshot + breakdowns:
•
GET /v1/usage (replaces GET /v1/usage-stats; same contract)•
GET /v1/usage/calls with optional groupBy: day | number | channel and filters since, until, channel (whatsapp | pstn), number•
GET /v1/usage/sms with optional groupBy: day | number and filters since, until, numberUnified call history (WhatsApp + PSTN) + recordings:
•
GET /v1/calls filters: channel (whatsapp | pstn), status (ringing | answered | ended | failed), direction (inbound | outbound), number, search, cursor pagination via before + nextCursor•
GET /v1/calls/{id}•
GET /v1/calls/{id}/recording (default 302; as=json returns { url })WhatsApp call history improvements:
•
GET /v1/whatsapp/calls now supports cursor pagination via before and returns nextCursor•
POST /v1/whatsapp/calls now supports idempotent retries via Idempotency-KeyPSTN Voice calling (new):
•
POST /v1/phone-numbers/{id}/voice configure inbound routing (forwardTo), recording/transcription, voicemail, business hours, IVR, blocklist•
DELETE /v1/phone-numbers/{id}/voice• Call control:
POST /v1/voice/calls (supports Idempotency-Key), GET /v1/voice/calls, GET /v1/voice/calls/{id}, POST /v1/voice/calls/{id}/end, POST /v1/voice/calls/{id}/transfer, GET /v1/voice/calls/{id}/recording (as=json), GET /v1/voice/calls/estimate• Browser softphone handshake:
POST /v1/voice/calls/web then POST /v1/voice/calls/web/dialSMS (new):
•
POST /v1/sms/messages (supports Idempotency-Key; MMS via mediaUrls)•
GET /v1/sms/lookup (carrier + line type mobile | landline | voip | toll-free | unknown)• Opt-outs export:
GET /v1/sms/opt-outs with format: json | csv• US carrier registration flows:
GET/POST /v1/sms/registrations, GET /v1/sms/registrations/{id}, POST /v1/sms/registrations/{id}/verify-otp, POST /v1/sms/registrations/{id}/appeal, POST /v1/sms/registrations/sharePhone Numbers (new canonical resource):
•
GET /v1/phone-numbers, GET /v1/phone-numbers/{id}, DELETE /v1/phone-numbers/{id}• Purchase + inventory:
POST /v1/phone-numbers/purchase, GET /v1/phone-numbers/countries, GET /v1/phone-numbers/available, GET /v1/phone-numbers/availability• Regulated KYC:
GET/POST /v1/phone-numbers/kyc, POST /v1/phone-numbers/kyc/upload-document, POST /v1/phone-numbers/kyc/validate-address, POST /v1/phone-numbers/kyc/share, POST /v1/phone-numbers/kyc/review-packet, remediation via GET/POST /v1/phone-numbers/{id}/remediate• Port-in:
GET /v1/phone-numbers/port-in, POST /v1/phone-numbers/port-in, POST /v1/phone-numbers/port-in/check, POST /v1/phone-numbers/port-in/documents, DELETE /v1/phone-numbers/port-in/{id}WhatsApp Calling config is now number-keyed:
• New canonical sub-resource:
GET/POST/PATCH/DELETE /v1/phone-numbers/{id}/whatsapp/calling• Existing
/v1/whatsapp/phone-numbers/{id}/calling endpoints are deprecated aliasesDeprecated aliases (no immediate break, but new integrations should switch):
•
GET /v1/usage-stats → GET /v1/usage• Many
/v1/whatsapp/phone-numbers/* paths → corresponding /v1/phone-numbers/* pathsImprovement
Webhooks now support TikTok URL backfill via the new event
This fires when a published TikTok post’s public URL is resolved/backfilled, using the same payload shape as
Subscribe by including
Also clarified for
post.tiktok.url_resolved.This fires when a published TikTok post’s public URL is resolved/backfilled, using the same payload shape as
post.platform.published/post.platform.failed (see WebhookPayloadPostPlatform).Subscribe by including
post.tiktok.url_resolved in events when calling POST /v1/webhooks/settings or PUT /v1/webhooks/settings.Also clarified for
PUT /v1/posts/{postId}: to promote a draft to scheduled you must send isDraft: false together with scheduledFor (or publishNow: true / queuedFromProfile). If isDraft is omitted, the post keeps its current draft status.Improvement
Webhook payloads now include
This makes it easier to consistently filter all webhook events by a single field (e.g. route staging vs production by account) while keeping
New field:
•
Added to these webhook payloads:
•
•
•
•
•
• inbox webhook payloads via
account.accountId (same value as account.id) as a canonical field for filtering/routing events.This makes it easier to consistently filter all webhook events by a single field (e.g. route staging vs production by account) while keeping
account.id for backward compatibility.New field:
•
account.accountIdAdded to these webhook payloads:
•
comment.received•
lead.received•
review.new•
review.updated•
post.external.created, post.external.updated, post.external.deleted• inbox webhook payloads via
InboxWebhookAccountImprovement
Webhook post events now include the connected social account per platform target via
This lets you route/attribute webhook deliveries by the specific SocialAccount used for each platform publish (useful when a single post spans multiple accounts).
New field:
•
•
post.platforms[].accountId.This lets you route/attribute webhook deliveries by the specific SocialAccount used for each platform publish (useful when a single post spans multiple accounts).
New field:
•
WebhookPayloadPost.post.platforms[].accountId•
WebhookPayloadPostPlatform.post.platforms[].accountId (on post.platform.published / post.platform.failed; see also the top-level account block there)Improvement
WhatsApp KYC form spec now returns an optional audience per requirement in
This lets you show/collect only the fields that apply to the end-user type (business vs individual) and avoid submitting both sets of requirements.
New field:
GET /v1/whatsapp/phone-numbers/kyc.This lets you show/collect only the fields that apply to the end-user type (business vs individual) and avoid submitting both sets of requirements.
New field:
fields[].audience = business | individual | null (applies to both).Improvement
GET /v1/connect/pending-data now supports Pinterest board selection in headless OAuth flows.For Pinterest (in addition to LinkedIn orgs and Snapchat profiles), the OAuth redirect returns
pendingDataToken and you can fetch the full selection payload via token.Use
token (query) from the redirect, and read selectionType (enum: organizations, pages, boards, locations, profiles) to determine which selection array to consume (e.g. boards for Pinterest).Improvement
Workflow send_message nodes now allow omitting
This makes interactive message configs simpler, but payloads with neither
Applies to
interactive.type; it will be inferred from the interactive payload shape.This makes interactive message configs simpler, but payloads with neither
type nor an inferable shape are now rejected.Applies to
send_message.config with messageType = interactive (WhatsApp-only).New Feature
POST /v1/invite/tokens now supports inviting users with the new admin role via role.Use
role=admin to grant team-management permissions (invite/remove members, change roles and access) without billing, ownership transfer, or account deletion permissions.role enum is now: admin, member, billing_admin, viewer.Note:
readOnly (deprecated) can’t be combined with role=billing_admin or role=admin.Improvement
WhatsApp document sends via URL now support setting the displayed filename using
This lets you control the recipient-visible file name for
Use:
•
•
•
Applies to WhatsApp only; ignored for
attachmentName on POST /v1/inbox/conversations/{conversationId}/messages.This lets you control the recipient-visible file name for
attachmentUrl document messages (otherwise WhatsApp derives it from the URL and may show “Untitled”).Use:
•
attachmentType: file•
attachmentUrl: (public URL)•
attachmentName: e.g. Report.pdfApplies to WhatsApp only; ignored for
image/video/audio and for multipart binary uploads.New Feature
New endpoint
Use it to confirm a user-submitted post exists by sending
Request body:
•
•
•
Response:
•
• If
• If no locator provided:
Returned posts use
POST /v1/posts/sync-external lets you sync/verify external (non-Zernio) posts on demand, so a just-published post can be retrieved within seconds instead of waiting for the background sync.Use it to confirm a user-submitted post exists by sending
accountId plus either url or postId.Request body:
•
accountId (required)•
url (optional)•
postId (optional)Response:
•
synced.postsFound, synced.postsSynced, synced.skipped• If
url/postId provided: found + post (or null)• If no locator provided:
posts (recent external posts)Returned posts use
ExternalPostSummary (includes platform, platformPostId, platformPostUrl, publishedAt, and basic analytics like likes/comments).New Feature
WhatsApp Business Profile now supports managing business usernames via new endpoints.
You can fetch the current username + approval state, claim/transfer a username, release it, and retrieve available suggestions.
New endpoints:
•
•
•
•
On username claim failures, expect error codes like
You can fetch the current username + approval state, claim/transfer a username, release it, and retrieve available suggestions.
New endpoints:
•
GET /v1/whatsapp/business-profile/username (accountId query) → returns username (nullable) and status (approved/reserved/none)•
POST /v1/whatsapp/business-profile/username body: accountId, username, optional transferAction (none/force_transfer)•
DELETE /v1/whatsapp/business-profile/username body: accountId•
GET /v1/whatsapp/business-profile/username/suggestions (accountId query) → returns suggestions[]On username claim failures, expect error codes like
whatsappusernameunavailable, whatsappusernameineligible, or whatsappusernametransfer_required.New Feature
New endpoint
Currently supports LinkedIn organization mentions and requires the Inbox addon.
Key query params:
•
•
•
•
•
Response includes
GET /v1/inbox/mentions is available to list mentions of your connected organization accounts delivered via platform webhooks.Currently supports LinkedIn organization mentions and requires the Inbox addon.
Key query params:
•
accountId (filter by social account ID)•
profileId (filter by profile ID)•
sortOrder (asc | desc, default desc)•
limit (1–100, default 25)•
cursor (pagination)Response includes
data items with id, platform (linkedin), content, permalink, authorUrn, organizationalEntity, publishedAt, plus pagination (hasMore, cursor).New Feature
New endpoint
Use query params
GET /v1/ads/campaigns/{campaignId}/analytics returns campaign-level analytics in one call (summary metrics, daily[] timeline, and optional Meta demographic breakdowns).Use query params
fromDate, toDate (defaults to last 90 days; max 730 days) and optional platform to disambiguate IDs. For Meta-only breakdowns, pass breakdowns as a comma-separated list: age, gender, country, publisherplatform, deviceplatform, region, platformposition, impressiondevice, videoasset, imageasset, bodyasset, titleasset.GET /v1/ads/tree now supports daily trends in the same response: set timeIncrement=1 to add daily[] metrics series, and control where it appears with dailyLevel = campaign (default) | adset | ad.New Feature
Instagram Trial Reels are now identifiable per platform target in post responses.
When an Instagram reel is created as a Trial (via
•
•
Use these fields to segment trial reels in analytics; note this reflects creation-time intent (Instagram doesn’t expose a readable trial flag).
When an Instagram reel is created as a Trial (via
platformSpecificData.trialParams), the corresponding PlatformTarget may include:•
isTrialReel (boolean) — present and true only for trial reels•
trialGraduationStrategy — MANUAL | SS_PERFORMANCE (present only when isTrialReel is true)Use these fields to segment trial reels in analytics; note this reflects creation-time intent (Instagram doesn’t expose a readable trial flag).
Breaking Change
Removed endpoint
This endpoint previously returned recent posts for a connected social account by calling the platform API directly (Facebook, Instagram, X/Twitter, Bluesky, Threads, YouTube, LinkedIn, Reddit, TikTok, Pinterest).
If you were using YouTube filtering, note that
GET /v1/accounts/{accountId}/posts.This endpoint previously returned recent posts for a connected social account by calling the platform API directly (Facebook, Instagram, X/Twitter, Bluesky, Threads, YouTube, LinkedIn, Reddit, TikTok, Pinterest).
If you were using YouTube filtering, note that
excludeUnlisted is no longer available via this route.Breaking Change
New endpoint
You can optionally filter YouTube results to avoid returning internal/unlisted content with
Use:
•
•
Also note a targeting spec change:
GET /v1/accounts/{accountId}/posts lists recent posts for a connected social account by calling the platform API directly (Facebook, Instagram, X/Twitter, Bluesky, Threads, YouTube, LinkedIn, Reddit, TikTok, Pinterest).You can optionally filter YouTube results to avoid returning internal/unlisted content with
excludeUnlisted.Use:
•
accountId (path)•
excludeUnlisted (query, boolean; YouTube only)Also note a targeting spec change:
TargetingSpec.cities[].distanceUnit is now TargetingSpec.cities[].distanceunit (with radius still supported). excludedLocations now supports excluded cities with optional radius + distanceunit, plus excluded places, neighborhoods, and excluded customLocations.New Feature
Instagram posts now support AI-generated media self-disclosure via
When
Set:
•
Applies to feed posts, Reels, Stories, and carousels.
isAiGenerated in platformSpecificData.When
isAiGenerated is true, Instagram labels the post as containing AI-generated media (this is for media, not AI-written captions).Set:
•
isAiGenerated (boolean, default false)Applies to feed posts, Reels, Stories, and carousels.
New Feature
POST /v1/whatsapp/phone-numbers/kyc now supports provisioning multiple same-country numbers in a single KYC submission via quantity.Set
quantity (default 1, min 1, max 5) to request several numbers; the same verification covers all of them and each number is billed only when it activates (best-effort if some orders fail).Response now includes
numbers (array) with all provisioned numbers. phoneNumber remains and represents the first/primary number for backward compatibility.status remains: kycsubmitted | kycreused | kycalreadysubmittedNew Feature
WhatsApp phone number provisioning now supports creating a hosted KYC link via
This generates a single-use, 7-day link your end customer can complete without a Zernio login; once submitted, the number provisions under your account (only for regulated/KYC countries).
Request fields:
•
•
•
•
Response fields:
•
•
•
To react when the form is completed, subscribe webhooks to the new event:
POST /v1/whatsapp/phone-numbers/kyc/share.This generates a single-use, 7-day link your end customer can complete without a Zernio login; once submitted, the number provisions under your account (only for regulated/KYC countries).
Request fields:
•
profileId (required)•
country (required, ISO-2; non-KYC countries return 400)•
branding (optional: companyName, logoUrl, brandColor)•
redirect_url (optional; on success appends kyc=submitted and country=<ISO-2>)Response fields:
•
url•
token•
expiresAtTo react when the form is completed, subscribe webhooks to the new event:
whatsapp.number.kyc_submitted (available in POST/PUT /v1/webhooks/settings).Improvement
Comment webhooks (
This lets you detect and render comments that have no text content; note Meta URLs may be ephemeral, so fetch promptly.
Key fields:
•
•
•
comment.received) now include an optional comment.attachment object for Facebook graphic-only comments (sticker, GIF, photo).This lets you detect and render comments that have no text content; note Meta URLs may be ephemeral, so fetch promptly.
Key fields:
•
comment.attachment.type (required)•
comment.attachment.imageUrl•
comment.attachment.urlNew Feature
Meta boosts via
Use
Key rule:
POST /v1/ads/boost now support raw Meta-native targeting with rawTargeting.Use
rawTargeting to pass a Meta targeting spec verbatim (snakecase like geolocations, customaudiences, excludedcustomaudiences, flexiblespec, targeting_automation) to target specific custom/lookalike audiences or clone targeting exactly.Key rule:
rawTargeting is mutually exclusive with targeting (sending both returns 422).New Feature
POST
You can target more precise location types and explicitly exclude locations when creating Meta ads.
New fields:
•
•
•
POST
New fields:
•
•
•
•
•
GET
Use
/v1/ads/create now supports additional Meta geo targeting controls.You can target more precise location types and explicitly exclude locations when creating Meta ads.
New fields:
•
places (Meta geoType place)•
neighborhoods (Meta geoType neighborhood)•
excludedLocations with countries, regions, cities, zipsPOST
/v1/ads/lead-forms adds richer Meta Instant Form configuration.New fields:
•
formType: MOREVOLUME | HIGHERINTENT | RICH_CREATIVE•
blockDisplayForNonTargetedViewer•
allowOrganicLeadGen•
questionPageCustomHeadline•
contextCard (title, content, style: LISTSTYLE | PARAGRAPHSTYLE, buttonText, coverPhoto)GET
/v1/ads/targeting/search geo search now supports geoType=all and returns coordinates.Use
dimension=geo with geoType=all to search across all geo types in one call, and read latitude / longitude from results (when available).Improvement
Moving an account to another profile via
This enforces the rule that a profile can hold only one account per platform.
Handle the new response:
•
PATCH /v1/accounts/{accountId} can now return 409 when the target profile already has an account on the same platform.This enforces the rule that a profile can hold only one account per platform.
Handle the new response:
•
409 - target profile already has an account of the same platform (profileplatformconflict)Improvement
GET
Key fields include
Geo targeting search via
/v1/ads/lead-forms/{formId} now returns a fully detailed form object (enough to duplicate the form via POST /v1/ads/lead-forms).Key fields include
form.status (ACTIVE/ARCHIVED), questions, thankyoupage, and context_card.Geo targeting search via
GET /v1/ads/targeting/search now supports additional geoType values when dimension=geo: subcity, neighborhood, place, metroarea, geomarket (in addition to country, region, city, zip).Improvement
Inbox conversations now include ad-click attribution via a new
This lets you identify when a conversation started from a click-to-message ad (vs organic) and store the associated ad identifiers/details.
New field:
•
Common keys you may see in
• WhatsApp CTWA:
• Meta CTM/CTD:
metadata object in responses from GET /v1/inbox/conversations and GET /v1/inbox/conversations/{conversationId}.This lets you identify when a conversation started from a click-to-message ad (vs organic) and store the associated ad identifiers/details.
New field:
•
metadata (object, nullable) — only present for ad-originated conversations; absent for organicCommon keys you may see in
metadata:• WhatsApp CTWA:
ctwaclid, ctwasourceid, ctwasourceurl, ctwaheadline, ctwasourcetype, ctwacapturedat• Meta CTM/CTD:
metaadid, metaadtitle, metaadsource, metaadtype, metaadref, metaadcapturedat, metaadphotourl, metaadvideourl, metaadpostid, metaadproductid, metaadflowidImprovement
Analytics post items now include
This lets you distinguish ad creatives from organic posts in analytics results (currently only available for LinkedIn posts; false when unavailable).
New field:
•
isAd in AnalyticsListResponse.posts[].This lets you distinguish ad creatives from organic posts in analytics results (currently only available for LinkedIn posts; false when unavailable).
New field:
•
isAd (boolean) — true for ad creatives, otherwise falseImprovement
Meta ads created via
This lets you clone an ad set’s full Meta-native targeting spec via
When both are set,
Key fields:
•
•
•
POST /v1/ads/create now allow combining manual placements with rawTargeting.This lets you clone an ad set’s full Meta-native targeting spec via
rawTargeting while still overriding placements using the structured placements object.When both are set,
placements is converted to Meta snake_case and merged into rawTargeting before sending to Meta.Key fields:
•
rawTargeting (Meta TargetingSpec, snake_case)•
placements.publisherPlatforms: facebook, instagram, threads, messenger, audience_network•
placements.facebookPositions, placements.instagramPositions, placements.messengerPositions, placements.audienceNetworkPositions, placements.threadsPositions, placements.whatsappPositions, placements.devicePlatforms: mobile/desktopImprovement
POST
You can stage Meta campaigns/ads more safely (e.g., create everything paused, or pause just the campaign while keeping the ad set ready), and you can now attach new ads using an existing creative without resending copy/media.
New/updated fields:
•
•
•
/v1/ads/create now supports more control over Meta publish state and creative reuse.You can stage Meta campaigns/ads more safely (e.g., create everything paused, or pause just the campaign while keeping the ad set ready), and you can now attach new ads using an existing creative without resending copy/media.
New/updated fields:
•
status (ACTIVE | PAUSED) now explicitly controls desired publish state; in attach mode (adSetId) it affects only the new ad•
campaignStatus (ACTIVE | PAUSED) lets you set campaign state independently on the legacy create shape (ignored when existingCampaignId is set)•
existingCreativeId can now be used with adSetId to attach an ad that reuses an existing Meta creative (copy/media fields can be omitted)New Feature
POST
This enables safer launches (no immediate spend) and easier multi-ad-set testing while keeping creatives consistent.
New request fields:
•
•
•
/v1/ads/create now supports additional Meta-only creation options: you can create ads/ad sets paused, add a new ad set under an existing campaign, and/or reuse an existing creative.This enables safer launches (no immediate spend) and easier multi-ad-set testing while keeping creatives consistent.
New request fields:
•
status: ACTIVE | PAUSED•
existingCampaignId (Meta only; mutually exclusive with adSetId and creatives[])•
existingCreativeId (Meta only; mutually exclusive with creatives[], dynamicCreative, placementAssets)Improvement
LinkedIn posts now support quote-reshare via
Set
Notes:
•
• Works on personal profiles and organization pages
Error responses are now more structured for programmatic handling:
reshareUrl in LinkedInPlatformData.Set
reshareUrl to a LinkedIn post link ("Copy link to post") or a urn:li:share / urn:li:ugcPost / urn:li:groupPost URN. The published post becomes a repost with your content as commentary and the original post embedded underneath.Notes:
•
reshareUrl is mutually exclusive with media• Works on personal profiles and organization pages
Error responses are now more structured for programmatic handling:
ErrorResponse adds type, code, param, platform, and platformError (raw upstream payload when type is platform_error).type can be: invalidrequesterror, authenticationerror, permissionerror, notfound, ratelimiterror, platformerror, api_error.New Feature
POST /v1/ads/conversions now supports TikTok conversions (platform tiktokads).You can now relay OFFLINE conversion events to TikTok via the Offline Events API. Use
destinationId as the TikTok Offline Event Set ID, and note each event must include an email or phone.Key details:
•
accountId now accepts: metaads, googleads, linkedinads, tiktokads• Response
platform enum now includes tiktokadsGET /v1/accounts/{accountId}/conversion-destinations also now supports tiktokads (platform enum includes tiktokads).GET /v1/ads/tree adds campaignId (platform campaign id) to restrict the tree to a single campaign, independent of pagination.Improvement
Google Ads conversion destination creation via
If a conversion action with the same
Key fields:
•
•
New response:
•
POST /v1/accounts/{accountId}/conversion-destinations is now effectively idempotent by name.If a conversion action with the same
name already exists, the API will reuse it and return the same response as a fresh create. If the same name is used with a different type (category), the API now returns 409 with error code IDEMPOTENCY_CONFLICT.Key fields:
•
name•
typeNew response:
•
409 (Google Ads only) — IDEMPOTENCY_CONFLICTNew Feature
POST /v1/accounts/{accountId}/conversion-destinations now supports creating conversion destinations for Google Ads in addition to LinkedIn.You can create a Google Ads conversion action (created as
UPLOAD_CLICKS for offline uploads). Standard event names are mapped automatically, and actions default to secondary unless you opt in.Key Google Ads fields:
•
countingType: MANYPERCLICK | ONEPERCLICK•
primaryForGoal: true | false (default false)Notes:
•
accountId can now be linkedinads or googleads• Creation is not idempotent — retries can create duplicates
• 201 response
platform now includes linkedinads | googleadsImprovement
WhatsApp regulated-number KYC reuse now supports choosing which prior approved verification to reuse.
When submitting with reuse,
GET /v1/whatsapp/phone-numbers/kyc adds reusable.options (newest first), listing all approved verifications (each with fromPhoneNumber + details).When submitting with reuse,
POST /v1/whatsapp/phone-numbers/kyc adds reuseFrom to select the verification to reuse (set to reusable.options[].fromPhoneNumber). Omit reuseFrom to use the newest; no match returns 409.Improvement
GET
When
New field:
/v1/whatsapp/phone-numbers/kyc now returns a human-readable summary when a reusable KYC verification is available.When
reusable.available is true, you can show what verification is already on file (best-effort; may be empty if provider lookup fails) and let users skip re-entering the form.New field:
reusable.details (array of { label, value }) alongside reusable.fromPhoneNumber.Improvement
GET /v1/connect/{platform}/ads now supports ad sync scoping via adAccountId/adAccountIds across more ads platforms (not just Meta).You can limit discovery/sync to specific ad accounts for
facebook/instagram (Meta), linkedin, googleads, and twitter. Changing the scope will also remove already-synced ads from any de-scoped ad accounts.Use:
•
adAccountId - single ad account id (platform-specific format)•
adAccountIds - multiple ids (repeat param or comma-separated)Notes:
•
tiktok ignores these params (advertisers are scoped during OAuth)•
pinterest ignores these params (no ads discovery)• Meta ids (
act_<digits>) are validated against the connected token; unreachable ids return 400• Omitting both
adAccountId and adAccountIds keeps the previously persisted scope unchangedImprovement
Broadcast recipient results now include a plain-language failure reason via
This helps you interpret WhatsApp
Use:
•
•
Webhooks for delivery status now also include
errorExplanation on GET /v1/broadcasts/{broadcastId}/recipients.This helps you interpret WhatsApp
errorCode values (e.g. opt-out / re-engagement required) without maintaining your own mapping.Use:
•
recipients[].errorCode (integer, nullable)•
recipients[].errorExplanation (string, nullable; null if unmapped — fall back to error)Webhooks for delivery status now also include
error.explanation in WebhookPayloadMessageDeliveryStatus (populated on event=message.failed).Improvement
Google campaign objects now include
This exposes the raw Google Ads
New field:
•
advertisingChannelType in AdCampaign and AdTreeCampaign.This exposes the raw Google Ads
campaign.advertisingchanneltype so you can distinguish campaign serving surfaces (e.g. Search vs Performance Max) when syncing/reporting.New field:
•
advertisingChannelType (string, nullable) — Google-only (e.g. SEARCH, PERFORMANCEMAX, VIDEO, DEMANDGEN, DISPLAY, SHOPPING)New Feature
WhatsApp interactive messages now support voice call buttons when sending inbox messages via
This lets you render WhatsApp’s native “call” CTA in-chat (requires WhatsApp Business Calling enabled on the sending number). Optional attribution data can be echoed back on the
Use
•
•
•
Also,
POST /v1/inbox/conversations/{conversationId}/messages.This lets you render WhatsApp’s native “call” CTA in-chat (requires WhatsApp Business Calling enabled on the sending number). Optional attribution data can be echoed back on the
calls webhook.Use
interactive.type = voicecall and interactive.action.name = voicecall. Optional interactive.action.parameters:•
display_text•
ttl_minutes•
payloadAlso,
GET /v1/whatsapp/calling now returns callDeepLink (nullable) for the public https://wa.me/call/<number> deep link when calling is enabled.New Feature
YouTube analytics now supports video retention curves via
This returns an aggregated (not per-day) audience retention curve for a single video, plus
Call with:
•
•
• optional
Response highlights:
•
• empty
Requires
Also added to
• top-level
• per-day
GET /v1/analytics/youtube/video-retention.This returns an aggregated (not per-day) audience retention curve for a single video, plus
durationSeconds so you can render the curve on a time axis.Call with:
•
videoId•
accountId• optional
startDate, endDateResponse highlights:
•
retentionCurve[] points with elapsedVideoTimeRatio, audienceWatchRatio (can be > 1), relativeRetentionPerformance• empty
retentionCurve for low-view / not-yet-processed videos (2–3 day delay)Requires
yt-analytics.readonly; if missing you may get 412 with code=youtubeanalyticsscope_missing.Also added to
GET /v1/analytics/youtube/daily-views responses:• top-level
durationSeconds• per-day
averageViewPercentage (can exceed 100; don’t clamp client-side)New Feature
GET
This lets you choose whether daily totals are attributed to the post’s publish date or bucketed by the day engagement was actually received (engagement-over-time).
Use
•
•
/v1/analytics/daily-metrics now supports engagement attribution via a new query param attribution.This lets you choose whether daily totals are attributed to the post’s publish date or bucketed by the day engagement was actually received (engagement-over-time).
Use
attribution:•
publish (default) — attribute each post’s lifetime total to its publish date•
received — attribute per-day engagement increases to the day they occurredNew Feature
WhatsApp adds blocked-status lookup for a single contact via
This returns a definitive blocked state using Zernio’s blocklist mirror (kept in sync by block/unblock; first call per account may backfill from Meta’s full list).
Required query params:
•
•
Response
•
GET /v1/whatsapp/block-users/status.This returns a definitive blocked state using Zernio’s blocklist mirror (kept in sync by block/unblock; first call per account may backfill from Meta’s full list).
Required query params:
•
accountId•
user (consumer wa_id or E.164 phone; leading + optional)Response
200:•
blocked (boolean)New Feature
POST
Use this to request consumer permission before placing a Business-Initiated Call; the consumer must tap Allow before
Set:
•
•
/v1/whatsapp/calls now supports sending the WhatsApp call-consent prompt via a new optional action parameter.Use this to request consumer permission before placing a Business-Initiated Call; the consumer must tap Allow before
start_call is permitted (Meta rate-limits prompts and requires an open 24h service window).Set:
•
action: sendcallpermission_request (omit action to place a call)•
bodyText: optional text shown with the consent prompt (max 1024 chars)New Feature
WhatsApp now supports managing your blocklist via
You can list blocked users, block up to 1,000 users per request, and unblock in batches (per-user failures are returned without failing the whole request).
New endpoints:
•
•
•
WhatsApp interactive messages now also support location requests in
/v1/whatsapp/block-users.You can list blocked users, block up to 1,000 users per request, and unblock in batches (per-user failures are returned without failing the whole request).
New endpoints:
•
GET /v1/whatsapp/block-users with accountId, optional limit, after (cursor pagination via nextCursor)•
POST /v1/whatsapp/block-users body: accountId, users (1..1000)•
DELETE /v1/whatsapp/block-users body: accountId, users (1..1000)WhatsApp interactive messages now also support location requests in
POST /v1/inbox/conversations/{conversationId}/messages via interactive.type = locationrequestmessage (and action can be omitted; defaults to {"name":"send_location"}).New Feature
Meta catalog ads are now supported via
This lets you create Advantage+ catalog ads (e.g. vehicle inventory) using a Meta product catalog + product set; Meta renders the visuals per catalog item (no
Discover inputs with:
•
•
Create the ad with:
•
•
•
•
Notes:
goal = catalog_sales on POST /v1/ads/create.This lets you create Advantage+ catalog ads (e.g. vehicle inventory) using a Meta product catalog + product set; Meta renders the visuals per catalog item (no
imageUrl/video sent).Discover inputs with:
•
GET /v1/ads/catalogs (accountId, adAccountId)•
GET /v1/ads/catalogs/{catalogId}/product-sets (catalogId, accountId)Create the ad with:
•
goal: catalog_sales•
promotedObject.productSetId•
promotedObject.pixelId•
promotedObject.customEventTypeNotes:
catalog_sales is single-shape only (no creatives[], adSetId, dynamicCreative, or placementAssets).Improvement
GET
This lets you list Embedded Signup–linked WABA numbers alongside purchased numbers (which remain in
New response field:
•
•
•
•
•
Included only on the default view and when
/v1/whatsapp/phone-numbers now also returns connected (bring-your-own) WhatsApp numbers in a separate connected array.This lets you list Embedded Signup–linked WABA numbers alongside purchased numbers (which remain in
numbers). Connected numbers aren’t provisioned or billed by Zernio and use accountId for messaging/inbox endpoints.New response field:
connected[] with:•
accountId•
phoneNumber•
displayName•
profileId•
connectedAtIncluded only on the default view and when
status=active.Improvement
WhatsApp phone number purchase now supports idempotent retries and duplicate-purchase protection on
Use
A second purchase within 10 minutes is now rejected with
POST /v1/whatsapp/phone-numbers/purchase.Use
purchaseIntentId (optional) as an idempotency key: retry with the same value and, if a number was already bought, the API returns { status: "already_purchased", numberId, phoneNumber } instead of provisioning a second number.A second purchase within 10 minutes is now rejected with
409 and code PURCHASE_VELOCITY. To confirm an intentional additional purchase (e.g. bulk provisioning), set allowMultiple to true.New Feature
New endpoint:
You can now fetch Google Business Profile attribute metadata (valid attribute names, value types, and allowed enum values) before reading/writing via
Query modes (mutually exclusive):
• Location mode:
• Category mode:
Pagination:
Response includes
GET /v1/accounts/{accountId}/gmb-attribute-metadata.You can now fetch Google Business Profile attribute metadata (valid attribute names, value types, and allowed enum values) before reading/writing via
gmb-attributes.Query modes (mutually exclusive):
• Location mode:
locationId (or omit to use the account’s stored selectedLocationId)• Category mode:
categoryName (must start with categories/) + regionCode (optional languageCode)Pagination:
pageSize (1–200) and pageToken.Response includes
attributeMetadata[] with parent, valueType (e.g. BOOL, ENUM, URL, REPEATED_ENUM), displayName, repeatable, deprecated, and valueMetadata[] (enum options), plus nextPageToken when more results are available.Improvement
Meta video ads created via
You can now omit
Applies to:
• Top-level
•
POST /v1/ads/create no longer require a thumbnail.You can now omit
video.thumbnailUrl and Zernio/Meta will auto-generate the poster frame using Meta’s preferred video thumbnail (same candidates as Ads Manager). Provide it only if you need an exact poster frame.Applies to:
• Top-level
video (legacy + attach shapes): video.url required, video.thumbnailUrl optional•
creatives[].video (Meta multi-creative): video.url required, video.thumbnailUrl optionalNew Feature
POST
This lets you set the secondary link text on Facebook/Instagram ads instead of relying on Meta scraping OpenGraph data.
Use:
•
•
Also clarified for Meta lead ads: when using
/v1/ads/create now supports Meta link descriptions via a new description field.This lets you set the secondary link text on Facebook/Instagram ads instead of relying on Meta scraping OpenGraph data.
Use:
•
description (Meta only) — applies to legacy + attach + placementAssets•
creatives[].description (Meta multi-creative) — per-ad override; falls back to top-level descriptionAlso clarified for Meta lead ads: when using
adSetId (attach shape) into a lead ad set, you must pass leadGenFormId on every attached ad.Deprecation
Invite creation now supports a dedicated read-only role via
Use
•
•
•
The
role on POST /v1/invite/tokens.Use
role to control access level:•
member•
billing_admin•
viewer - read-only (no publish/edit/delete/connect)The
readOnly field is now deprecated. If readOnly=true, the invite is created with role=viewer (and it can’t be combined with role=billing_admin).New Feature
Webhooks now support a new WhatsApp number event:
Subscribe to this event to be notified when a WhatsApp number needs additional action to proceed.
Add it to
•
whatsapp.number.action_required.Subscribe to this event to be notified when a WhatsApp number needs additional action to proceed.
Add it to
events when creating/updating a webhook via POST /v1/webhooks/settings or PUT /v1/webhooks/settings:•
events: ["whatsapp.number.action_required", ...]Improvement
Invite token creation now supports assigning an org role and issuing read-only invites via
Use
POST /v1/invite/tokens.Use
role to grant org-level permissions (member | billing_admin, default member), and readOnly to restrict the invitee to view-only access within their scope (default false).Breaking Change
WhatsApp template buttons updated:
This enables WhatsApp marketing “copy code” buttons where the label is fixed by WhatsApp, and the coupon code is provided via
Key changes:
•
•
•
WhatsAppTemplateButton now supports a new button type value copy_code, and text is no longer required for all button types.This enables WhatsApp marketing “copy code” buttons where the label is fixed by WhatsApp, and the coupon code is provided via
example.Key changes:
•
type enum now includes: quickreply, url, phonenumber, otp, copy_code, flow, mpm, catalog•
text: required for all types except copy_code•
example is now string or string[] (URL buttons: string[]; copy_code: coupon code as string)New Feature
Meta Lead Gen ads created via
You can run Meta’s multi-text / multi-asset optimization ("Multiple Text Options") on instant-form lead ads; Zernio will create the required Dynamic Creative ad set automatically and attach the form for you.
Use:
•
•
•
• Optional variations:
• Required:
POST /v1/ads/create now support Dynamic Creative using dynamicCreative together with goal=lead_generation.You can run Meta’s multi-text / multi-asset optimization ("Multiple Text Options") on instant-form lead ads; Zernio will create the required Dynamic Creative ad set automatically and attach the form for you.
Use:
•
goal=lead_generation•
leadGenFormId=<form_id>•
dynamicCreative.imageUrls (send 1+; send a single entry if you only want multi-text)• Optional variations:
dynamicCreative.titles, dynamicCreative.bodies, dynamicCreative.descriptions, dynamicCreative.linkUrls• Required:
dynamicCreative.callToActionTypes (e.g. LEARNMORE, SIGNUP, DOWNLOAD, REGISTER, BUY_NOW)New Feature
X (Twitter) posts now support additional labeling and media safety controls via
You can label posts as paid promotions or AI-generated media, and mark attached media with sensitive-content warnings.
New fields in
•
•
•
Reddit posts now support additional post options via
New fields in
•
•
•
•
platformSpecificData.You can label posts as paid promotions or AI-generated media, and mark attached media with sensitive-content warnings.
New fields in
TwitterPlatformData:•
paidPartnership (boolean)•
madeWithAi (boolean)•
sensitiveMedia with adultContent, graphicViolence, other (booleans; requires media)Reddit posts now support additional post options via
platformSpecificData.New fields in
RedditPlatformData:•
flairText (string; ignored if flairId is set)•
nsfw (boolean)•
spoiler (boolean)•
sendreplies (boolean)Improvement
GET
This lets you fetch only healthy accounts or only accounts that need reconnection (matching the dashboard reconnection check). Pagination totals reflect the filtered result set when used with
Use
•
•
/v1/accounts now supports filtering by connection status via the new status query param.This lets you fetch only healthy accounts or only accounts that need reconnection (matching the dashboard reconnection check). Pagination totals reflect the filtered result set when used with
page/limit.Use
status:•
connected•
disconnectedImprovement
Meta Lead Gen ads created via
You can pin different image/video assets to placement groups (e.g. Stories/Reels vs Feed) while still attaching a Lead Gen form via
Use:
•
•
•
Note:
POST /v1/ads/create now support per-placement creative using placementAssets.You can pin different image/video assets to placement groups (e.g. Stories/Reels vs Feed) while still attaching a Lead Gen form via
leadGenFormId.Use:
•
goal=lead_generation•
leadGenFormId•
placementAssets with defaultImageUrl or defaultVideoUrl + rules[].placementsNote:
dynamicCreative is still not compatible with goal=lead_generation.Improvement
Meta ads tracking-tag updates are now simpler on
This removes the previous requirement to provide the full Meta
Key fields:
•
•
•
•
PATCH /v1/ads/{adId}/tracking-tags: you can send urlTags alone and Zernio will preserve the existing creative verbatim while rebuilding/repointing the ad.This removes the previous requirement to provide the full Meta
creative payload just to add/update click-URL tags. For creatives where Meta strips objectstoryspec (e.g. share/page-post/dark/asset_feed), you may still get 422 and need to include creative explicitly.Key fields:
•
urlTags (Meta)•
creative (Meta, optional; required only when preservation isn’t possible)•
trackingUrlTemplate, finalUrlSuffix (Google)•
dynamicValueParameters, customValueParameters (LinkedIn)New Feature
Meta ads created via
This lets you override the default optimization derived from
Use
POST /v1/ads/create now support explicitly setting the ad set optimization goal via optimizationGoal.This lets you override the default optimization derived from
goal (e.g. traffic defaulting to LINKCLICKS) and pass a Meta-native optimizationgoal value directly; Meta will validate and reject incompatible combinations.Use
optimizationGoal (Meta only), e.g. LANDINGPAGEVIEWS, LINKCLICKS, REACH, IMPRESSIONS, OFFSITECONVERSIONS, THRUPLAY, LEAD_GENERATION.New Feature
Google Ads now supports conversion adjustments via
You can retract, restate value, or enhance an already-uploaded conversion (Google only; other platforms return
Send:
•
•
•
Per adjustment:
• Identify the original conversion with
•
•
•
Also: Meta standalone ad creation adds
POST /v1/ads/conversions/adjustments.You can retract, restate value, or enhance an already-uploaded conversion (Google only; other platforms return
405). Partial failure is supported (check adjustmentsFailed / failures[]).Send:
•
accountId (must be a googleads account)•
destinationId (conversion action resource name)•
adjustments[] with adjustmentType = RETRACTION | RESTATEMENT | ENHANCEMENTPer adjustment:
• Identify the original conversion with
orderId (required for ENHANCEMENT) or gclid + conversionTime•
adjustmentTime (unix seconds)•
restatementValue + currency (for RESTATEMENT)•
user.email/user.phone (+ optional userAgent) for ENHANCEMENTAlso: Meta standalone ad creation adds
goal = leadconversion on POST /v1/ads/create (and Ad.goal) for website pixel lead optimization (distinct from leadgeneration instant forms).Improvement
GET /v1/comment-automations now returns stats.trackedSends for each automation.Use
trackedSends as the CTR denominator for tracked links (divide stats.linkClicks by stats.trackedSends, not stats.dmsSent). It may lag dmsSent for automations that predate click tracking.New field:
•
stats.trackedSends - DMs sent with a trackable (wrapped) linkNew Feature
Webhooks now support external post events for posts created/updated/deleted directly on the platform (not published via Zernio).
Subscribe by including these in
•
•
•
Payload uses
Subscribe by including these in
events when calling POST /v1/webhooks/settings or PUT /v1/webhooks/settings:•
post.external.created•
post.external.updated•
post.external.deletedPayload uses
WebhookPayloadExternalPost with post = ExternalPostWebhookPost (includes post.id = platform-native ID, post.source = external; on post.external.deleted, post.deletedAt is populated). Events are sync-detected (~hourly), not real-time.New Feature
POST
You can explicitly set the created ad’s name (instead of inheriting
New fields:
•
•
•
/v1/ads/create now supports Meta-specific single-ad naming and ad-level tracking.You can explicitly set the created ad’s name (instead of inheriting
name), and attach pixel measurement + URL tags regardless of optimization goal.New fields:
•
adName (Meta only) — overrides the default ad name (default was name)•
tracking.pixelId (Meta only) — attaches pixel measurement via ad tracking_specs•
tracking.urlTags (Meta only) — sets ad url_tags as [{ key, value }]New Feature
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
•
•
•
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.releasedNew Feature
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,
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)New Feature
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
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).Improvement
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.
/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.
Improvement
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:
•
•
•
•
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 locationsImprovement
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:
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.New Feature
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
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).New Feature
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
/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
assetfeedspec + assetcustomizationrules 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.New Feature
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:
•
•
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)Improvement
GET
This lets you report delivery/read performance for comment-to-DM automations (where supported) without extra calls.
New fields:
•
•
/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 messagingseen / Messenger messagereads)New Feature
Comment-to-DM automations now support tagging contacts who click tracked links via
When
Use:
•
•
Returned in:
•
•
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}: clickTagNew Feature
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:
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.linkTrackingNew Feature
X (Twitter) posts now support quote reposting via
Set
Key property:
•
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).Improvement
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
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)Improvement
GET
You can use these to show engagement stats and recent activity without querying message history.
New fields:
• Contact:
• Channel:
/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)New Feature
New Workflows API endpoints are available to build and run branching conversation workflows (node/edge graphs), including activation/pausing and execution tracking.
Manage workflows:
•
•
•
•
•
Control lifecycle:
•
•
Track and test runs:
•
•
Manage workflows:
•
GET /v1/workflows (filters: profileId, status = draft|active|paused, limit, skip)•
POST /v1/workflows (create draft; required: profileId, accountId, name; optional: platform = whatsapp|instagram|facebook|telegram|twitter|bluesky|reddit, nodes, edges, entryNodeId)•
GET /v1/workflows/{workflowId}•
PATCH /v1/workflows/{workflowId} (graph edits only when draft or paused)•
DELETE /v1/workflows/{workflowId}Control lifecycle:
•
POST /v1/workflows/{workflowId}/activate (validates runnable graph; idempotent)•
POST /v1/workflows/{workflowId}/pause (stops matching new inbound messages; idempotent)Track and test runs:
•
GET /v1/workflows/{workflowId}/executions (filter status = running|waiting|completed|exited|failed; limit, skip)•
POST /v1/workflows/{workflowId}/executions (manual start; provide conversationId or WhatsApp-only to; optional text seeds lastMessage)New Feature
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,
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.Improvement
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
POST /v1/whatsapp/conversions.The endpoint now only requires
metaCapiDatasetId (provision via POST /v1/whatsapp/dataset) and forwards the WABA ID as userdata.whatsappbusinessaccountid 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.Improvement
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:
•
•
•
•
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.startedImprovement
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:
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.New Feature
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:
•
•
•
•
•
•
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)New Feature
POST
When sending an audio attachment, set
Key params:
•
•
•
Note: the audio must be
/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.New Feature
New endpoint:
You can now fetch recent WhatsApp conversion send events (from delivery logs, ~30-day retention) to power a “recent activity” view without maintaining your own persistence.
Required query:
Optional query:
Response includes per-event fields like
GET /v1/whatsapp/conversions.You can now fetch recent WhatsApp conversion send events (from delivery logs, ~30-day retention) to power a “recent activity” view without maintaining your own persistence.
Required query:
accountIdOptional query:
limit (1–200, default 50)Response includes per-event fields like
timestamp, eventName (LeadSubmitted, Purchase, AddToCart, InitiateCheckout, ViewContent), conversationId, eventsReceived, eventsFailed, traceId, durationMs.Improvement
Inbox webhooks now include a sender
This lets you link inbound messages/reactions directly to a Contact (via the ContactChannel mapping) without an extra Contacts API lookup. The field is omitted when no contact exists (and typically for outgoing/business sender).
New field:
•
•
•
contactId when the sender matches a Zernio CRM Contact.This lets you link inbound messages/reactions directly to a Contact (via the ContactChannel mapping) without an extra Contacts API lookup. The field is omitted when no contact exists (and typically for outgoing/business sender).
New field:
•
message.sender.contactId in message.received and message.sent•
reaction.sender.contactId in reaction.received•
InboxWebhookMessage.sender.contactIdNew Feature
WhatsApp now supports managing the Meta CTWA conversions dataset via two new endpoints.
Use these to detect whether Conversions API reporting is configured for a WhatsApp account and to provision the required Meta dataset (idempotent).
Check current dataset:
Returns
Provision (or fetch existing) dataset:
Returns
If the account token is missing
Use these to detect whether Conversions API reporting is configured for a WhatsApp account and to provision the required Meta dataset (idempotent).
Check current dataset:
GET /v1/whatsapp/dataset with accountId (query)Returns
datasetId (nullable).Provision (or fetch existing) dataset:
POST /v1/whatsapp/dataset with body accountIdReturns
datasetId and created (boolean).If the account token is missing
whatsappbusinessmanage_events, provisioning returns 422 (reconnect required).New Feature
New endpoint:
You can now look up a single pre-approved WhatsApp Template Library template by exact name to inspect its structure before importing—especially the
Required query params:
•
•
Response (
GET /v1/whatsapp/template-library.You can now look up a single pre-approved WhatsApp Template Library template by exact name to inspect its structure before importing—especially the
buttons you must mirror when creating a template (e.g., URL/PHONE_NUMBER inputs).Required query params:
•
accountId (WhatsApp social account ID)•
name (exact library template name)Response (
200): template (object or null) with key fields like bodyparams and buttons where buttons[].type can be QUICKREPLY, URL, PHONE_NUMBER, OTP, FLOW, ...New Feature
WhatsApp Flows now supports listing submitted flow responses via
This lets you fetch customer responses parsed from
Use:
•
•
•
Response items include
Also updated: when sending flows via
GET /v1/whatsapp/flow-responses.This lets you fetch customer responses parsed from
nfm_reply webhook messages (newest first), and optionally scope them to a specific flow.Use:
•
accountId (required)•
flowId (optional)•
limit (optional, max 200, default 50)Response items include
id, receivedAt, from, senderName, conversationId, flowToken, data, raw.Also updated: when sending flows via
POST /v1/whatsapp/flows/send, if flow_token is omitted it is now auto-generated as <flowId>:<uuid> so responses can be attributed to that flow in the Flow Responses view.New Feature
WhatsApp Flows now support flow previews and version history.
You can fetch Meta’s embeddable web preview URL for a flow (drafts included), and list Zernio-tracked versions for a flow’s clone lineage.
New endpoints:
•
•
Flow versioning metadata is now returned:
•
•
Cloning can now stay in the same lineage:
•
You can fetch Meta’s embeddable web preview URL for a flow (drafts included), and list Zernio-tracked versions for a flow’s clone lineage.
New endpoints:
•
GET /v1/whatsapp/flows/{flowId}/preview with accountId and optional invalidate (mint a fresh link)•
GET /v1/whatsapp/flows/{flowId}/versions with accountIdFlow versioning metadata is now returned:
•
GET /v1/whatsapp/flows adds version and lineageId per flow•
POST /v1/whatsapp/flows response adds version and lineageIdCloning can now stay in the same lineage:
•
POST /v1/whatsapp/flows adds asVersion (only when using cloneFlowId)New Feature
Inbox messages now include platform-specific metadata on each message via
This lets you read extra context like quoted replies and WhatsApp interactive/tap details without relying only on webhooks.
New field:
•
WhatsApp multipart sends now support voice note uploads via
Set
New multipart field:
•
messages[].metadata.This lets you read extra context like quoted replies and WhatsApp interactive/tap details without relying only on webhooks.
New field:
•
messages[].metadata (free-form object; commonly includes quotedMessageId, waInteractive, and inbound tap fields like interactiveType / interactiveId)WhatsApp multipart sends now support voice note uploads via
voiceNote.Set
voiceNote to true when uploading an in-browser recorded audio so it’s transcoded to WhatsApp-native ogg/Opus.New multipart field:
•
voiceNote: true (WhatsApp-only)New Feature
Inbox messages now include emoji reactions on supported platforms (WhatsApp / Telegram) via
This lets you display who reacted and when, alongside the message timeline.
New per-message field:
•
Sending messages now supports WhatsApp location and contact cards.
New request fields for
•
•
reactions on each message.This lets you display who reacted and when, alongside the message timeline.
New per-message field:
•
reactions[]: { emoji, fromMe, reactedAt }Sending messages now supports WhatsApp location and contact cards.
New request fields for
POST /v1/inbox/conversations/{conversationId}/messages:•
location: { latitude, longitude, name?, address? }•
contacts[]: contact card objects (requires name.formatted_name; optional phones[], emails[])New Feature
POST /v1/inbox/conversations now supports starting conversations on X/Twitter, Bluesky, Reddit, and WhatsApp (previously X/Twitter only).You can initiate DMs across these platforms using
participantId or participantUsername (platform-dependent).WhatsApp requires an approved template to start a conversation: set
templateName, templateLanguage, and optional templateParams (freeform initial messages aren’t allowed). message is now optional when using a WhatsApp template.skipDmCheck remains X/Twitter only.Improvement
PostAnalytics now includes Instagram Reels watch-time metrics.You can retrieve average and total watch time for Reels (values are
0 for non-Reels media and other platforms).New fields:
•
igReelsAvgWatchTime (ms)•
igReelsVideoViewTotalTime (ms)New Feature
New webhook payload schema added for Meta Lead Gen / Instant Forms: lead.received events now use
This lets webhook consumers reliably parse incoming leads, including form metadata, ad attribution (when available), and a flattened field map.
Key properties:
•
•
•
•
•
•
WebhookPayloadLead.This lets webhook consumers reliably parse incoming leads, including form metadata, ad attribution (when available), and a flattened field map.
Key properties:
•
event: lead.received•
lead.fields: key → value map (multiple-choice values are option keys, e.g. k1)•
lead.isOrganic: boolean•
lead.createdAt: ISO 8601 datetime•
account.platform: facebook•
lead.formName, lead.adId, lead.adsetId, lead.campaignId: nullable when not availableNew Feature
Meta Lead Gen is now supported end-to-end: you can manage Instant Forms and retrieve submitted leads via new Ads endpoints.
New endpoints:
• List all leads (cross-form CRM view):
• Manage forms:
• Form leads + testing:
Ad creation update (Meta only):
New endpoints:
• List all leads (cross-form CRM view):
GET /v1/ads/leads with formId, accountId, since, limit, cursor• Manage forms:
GET /v1/ads/lead-forms, POST /v1/ads/lead-forms, GET /v1/ads/lead-forms/{formId}, DELETE /v1/ads/lead-forms/{formId}• Form leads + testing:
GET /v1/ads/lead-forms/{formId}/leads, POST /v1/ads/lead-forms/{formId}/test-leadsAd creation update (Meta only):
POST /v1/ads/create now accepts leadGenFormId. When goal is lead_generation, leadGenFormId is REQUIRED, and linkUrl is NOT required (the ad opens the form).New Feature
New endpoint POST /v1/ads/targeting/reach-estimate returns a normalized pre-flight audience reach estimate for a targeting spec before creating a campaign.
Send
Response includes
GET /v1/ads/interests is now deprecated. Use GET /v1/ads/targeting/search with
GET /v1/ads/targeting/search is now cross-platform and normalized. Use
POST /v1/ads/create targeting now supports additional fields:
Audiences now support reusable targeting presets: POST /v1/ads/audiences accepts
Send
accountId + spec (same shape as TargetingSpec used by ads create). Optionally pass optimizationGoal.Response includes
available, and when available: lower, upper, optional daily, currency, and Meta-only estimateReady.GET /v1/ads/interests is now deprecated. Use GET /v1/ads/targeting/search with
dimension=interest (the deprecated alias still returns the legacy { interests: [...] } shape).GET /v1/ads/targeting/search is now cross-platform and normalized. Use
dimension = geo | interest | behavior | income, and for geo also geoType = country | region | city | zip | metro. Results return { results: [{ id, name, type, path?, audienceSize? }] }.POST /v1/ads/create targeting now supports additional fields:
zips, metros, customLocations, behaviors, incomeTier (top5 | top10 | top1025 | top2550), languages, savedTargetingId, specialAdCategories (HOUSING | EMPLOYMENT | CREDIT | ISSUESELECTIONSPOLITICS).Audiences now support reusable targeting presets: POST /v1/ads/audiences accepts
type=savedtargeting with spec (no adAccountId), and GET /v1/ads/audiences adds type filter and returns spec when type is savedtargeting.Improvement
GET
This lets you render a post preview in the inbox/comments view without an additional Reddit fetch.
Key fields in
/v1/inbox/comments/{postId} now returns (Reddit only) post metadata alongside comments in a new post object.This lets you render a post preview in the inbox/comments view without an additional Reddit fetch.
post is null/absent for non-Reddit platforms and may be missing if the upstream post listing isn’t available.Key fields in
post: id, fullname, title, selftext, author, subreddit, permalink, url, score, numComments, createdUtc, over18, stickied, flairText, isGallery.New Feature
Google Business Profile verification is now supported via new GMB Verifications endpoints.
You can fetch verification status/history, discover eligible methods, start a verification (SMS/call/email/postcard), and complete it by submitting the PIN.
New endpoints:
•
•
•
•
Note: service-area businesses may require
You can fetch verification status/history, discover eligible methods, start a verification (SMS/call/email/postcard), and complete it by submitting the PIN.
New endpoints:
•
GET /v1/accounts/{accountId}/gmb-verifications (optional locationId) returns voiceOfMerchantState.hasVoiceOfMerchant and verifications[].state = PENDING/COMPLETED/FAILED•
POST /v1/accounts/{accountId}/gmb-verifications/options requires languageCode; returns options[].verificationMethod = ADDRESS/EMAIL/PHONECALL/SMS/AUTO/VETTEDPARTNER•
POST /v1/accounts/{accountId}/gmb-verifications starts verification with method (+ method-specific fields like phoneNumber/emailAddress)•
POST /v1/accounts/{accountId}/gmb-verifications/{verificationId}/complete completes with pinNote: service-area businesses may require
context (service address) when fetching options/starting verification.New Feature
Webhooks now support message reaction events via the new
Subscribe by including
The
reaction.received subscription.Subscribe by including
reaction.received in events when calling POST /v1/webhooks/settings or PUT /v1/webhooks/settings.The
reaction payload includes emoji, action (added | removed), platformMessageId, optional messageId, sender, and reactedAt.New Feature
GET /v1/ads/audiences now supports fetching custom audiences for LinkedIn and X (Twitter) ad accounts.Use the
platform query param with one of:•
facebook, instagram, googleads, tiktok, tiktokads, pinterest, linkedin, linkedinads, twitter, xadsImprovement
GET
This provides the Meta WhatsApp error code to help you classify and handle delivery failures (only populated when
New field:
/v1/broadcasts/{broadcastId}/recipients now returns errorCode per recipient.This provides the Meta WhatsApp error code to help you classify and handle delivery failures (only populated when
status=failed).New field:
errorCode (integer, nullable) — e.g. 131049 (antispam), 131021 (invalid phone), 131026 (re-engagement required).New Feature
Instagram now supports Stories retrieval + insights.
You can list currently-active stories and fetch metrics for a specific story, including a clear indicator of whether insights are live, cached, or unavailable.
New endpoints:
•
Returns active stories (24h window). Key fields:
•
Returns
You can list currently-active stories and fetch metrics for a specific story, including a clear indicator of whether insights are live, cached, or unavailable.
New endpoints:
•
GET /v1/accounts/{accountId}/instagram/storiesReturns active stories (24h window). Key fields:
id, mediaType, mediaUrl (nullable), permalink, thumbnailUrl, timestamp•
GET /v1/accounts/{accountId}/instagram/stories/{storyId}/insightsReturns
data.source = live | cached | unavailable and data.metrics including views, reach, replies, shares, navigation, tapsForward, tapsBack, exits, swipesForward, profileVisits, follows, reposts, totalInteractions.New Feature
WhatsApp is now supported as a
You can now use
•
•
platform for connecting accounts and checking account health.You can now use
whatsapp with:•
GET /v1/connect/{platform} (path param platform enum now includes whatsapp)•
GET /v1/accounts/health (query param platform enum now includes whatsapp)Improvement
GET
This lets you control the order of returned campaigns (by recency or aggregated spend) while keeping pagination at the campaign level.
Use
•
•
•
•
/v1/ads/tree now supports campaign-level sorting via a new sort query parameter.This lets you control the order of returned campaigns (by recency or aggregated spend) while keeping pagination at the campaign level.
Use
sort:•
newest (default)•
oldest•
spend_desc•
spend_ascNew Feature
Facebook now supports multi-link carousel posts via
This lets you publish a 2–5 card carousel where each image has its own click-through link (and optional headline/description).
Set
•
•
•
Optionally set
Constraints:
facebookSettings on POST /v1/posts.This lets you publish a 2–5 card carousel where each image has its own click-through link (and optional headline/description).
Set
facebookSettings.carouselCards (2–5 items) with:•
link (required)•
name (optional)•
description (optional)Optionally set
facebookSettings.carouselLink for the carousel end-card destination.Constraints:
mediaItems must be images only, and must match carouselCards length/order. Mutually exclusive with facebookSettings.contentType = story or reel.Improvement
POST
If you send the same
Use
Duplicate protection still applies separately: identical content to the same
/v1/posts now supports request idempotency via x-request-id.If you send the same
x-request-id again within ~5 minutes (including while the first request is in-flight), the API treats it as a retry and returns HTTP 200 with the original post in existingPost (no duplicate post is created).Use
x-request-id (UUID) per logical create call. If you omit it, each request is treated as new.Duplicate protection still applies separately: identical content to the same
(platform, accountId) within 24h returns HTTP 409 with details.accountId, details.platform, details.existingPostId.Improvement
{adId} in GET /v1/ads/{adId} and GET /v1/ads/{adId}/comments now accepts multiple identifier types.You can call these endpoints using the Zernio internal
id (24-char hex), Meta numeric platformAdId (from comment.received as comment.ad.id), or the creative’s effectiveobjectstoryid / effectiveinstagrammedia_id. Any of these resolves to the same ad, so you don’t need a translation step.New Feature
Webhooks now support per-platform terminal post events:
These fire once per platform target inside a post when that specific platform reaches a terminal state (published or permanent failure), which helps track multi-platform posts more precisely.
Subscribe via
•
•
A new webhook event is also available:
•
post.platform.published and post.platform.failed.These fire once per platform target inside a post when that specific platform reaches a terminal state (published or permanent failure), which helps track multi-platform posts more precisely.
Subscribe via
events on POST /v1/webhooks/settings or PUT /v1/webhooks/settings:•
post.platform.published•
post.platform.failedA new webhook event is also available:
•
whatsapp.template.status_updatedNew Feature
GET /v1/ads/campaigns now supports filtering aggregated campaign metrics by a date range.Use
fromDate and toDate (YYYY-MM-DD, inclusive) to control the metrics window returned for each campaign.New query params:
•
fromDate - start date (defaults to 90 days ago when both date params are omitted)•
toDate - end date (defaults to today; max 730-day range)New Feature
Webhooks now support WhatsApp template status updates via the new event
This fires when Meta completes a (re)review of a template on a connected WABA, so you can react to approvals/rejections and other status transitions.
Subscribe by adding
Payload:
whatsapp.template.status_updated.This fires when Meta completes a (re)review of a template on a connected WABA, so you can react to approvals/rejections and other status transitions.
Subscribe by adding
whatsapp.template.status_updated to Webhook.events.Payload:
WebhookPayloadWhatsAppTemplateStatusUpdated with template.status ∈ APPROVED, REJECTED, PENDING, PAUSED, DISABLED, INAPPEAL, PENDINGDELETION and template.reason (e.g. "NONE" on approval).New Feature
Google Business reviews now support owner replies via new endpoints:
Use
Reply body:
New optional bidding controls on CTWA:
CTWA create response is now a tagged union via
POST /v1/accounts/{accountId}/gmb-reviews/{reviewId}/reply and DELETE /v1/accounts/{accountId}/gmb-reviews/{reviewId}/reply.Use
comment to post/update a reply (calling POST again overwrites the previous reply). Deleting removes only the reply, not the review.Reply body:
{ "comment": "..." }POST /v1/ads/ctwa now supports creating multiple CTWA ads under one campaign/ad set by sending a non-empty creatives[] array (each creative has its own headline, body, and exactly one of imageUrl/video). Single-creative requests still work.New optional bidding controls on CTWA:
bidStrategy (LOWESTCOSTWITHOUTCAP, LOWESTCOSTWITHBIDCAP, COSTCAP, LOWESTCOSTWITHMINROAS) plus bidAmount (required for bid-cap/cost-cap) and roasAverageFloor (required for min-ROAS).CTWA create response is now a tagged union via
adType: single or multi.New Feature
Webhooks now support
Subscribe to get notified when a Meta ads object (campaign/ad set/ad) changes status or enters
Add
Payload highlights:
•
•
•
•
Also,
ad.status_changed.Subscribe to get notified when a Meta ads object (campaign/ad set/ad) changes status or enters
WITH_ISSUES.Add
ad.status_changed to events when creating/updating a webhook via POST /v1/webhooks/settings or PUT /v1/webhooks/settings.Payload highlights:
•
event: ad.status_changed•
adObject.level: CAMPAIGN | AD_SET | AD•
status.raw: platform-native status (e.g. ACTIVE, PAUSED, WITH_ISSUES)•
error: optional diagnostics on most WITH_ISSUES eventsAlso,
GET /v1/ads/{adId}/analytics now returns ad.currency (ISO 4217) so you can interpret money values in summary and daily.Improvement
GET /v1/ads/timeline now supports filtering by a specific platform ad account via adAccountId.Use this when a single Zernio connection wraps multiple platform ad accounts and you want the timeline chart for just one (e.g. Meta
act_…, TikTok advertiser ID).New query param:
•
adAccountId (optional)Note: rows ingested before
2026-05-13 may not include this dimension yet; the recurring 7-day re-sync will repopulate them over time.New Feature
New endpoint
Key params:
•
•
•
Response:
GET /v1/ads/timeline returns a daily time series of aggregate ad metrics for a social account (one row per calendar day), useful for spend/conversions charts without calling /v1/ads/tree per day.Key params:
•
accountId (required)•
fromDate, toDate (YYYY-MM-DD; defaults to last 90 days; max 730 days)•
platform (optional): facebook, instagram, tiktok, linkedin, pinterest, google, twitterResponse:
rows[] with per-day metrics like spend, impressions, clicks, ctr, conversions, actions, purchaseValue, roas. Returns empty rows if no activity. 403 if Ads add-on is required.New Feature
New endpoint:
Send
Request body:
•
Auth/scope note: for profile-restricted API keys, both the account’s current profile and the target
Responses:
PATCH /v1/accounts/{accountId} to move a connected account to a different profile owned by the same user.Send
profileId in the JSON body to set the target profile.Request body:
•
profileId (required)Auth/scope note: for profile-restricted API keys, both the account’s current profile and the target
profileId must be allowed, otherwise you’ll get 403.Responses:
200 returns message and profileId; errors include 400, 401, 403, 404.Improvement
TikTok conversion ads via
For TikTok,
Set:
•
•
•
POST /v1/ads/create now support/require TikTok pixel optimization settings through promotedObject.For TikTok,
goal=conversions uses promotedObject to configure the ad group’s pixel + optimization event (or inherit them by using adSetId).Set:
•
goal: conversions•
promotedObject.pixelId (required for TikTok conversions)•
promotedObject.customEventType (optional TikTok optimizationevent code, e.g. ONWEBORDER, INITIATEORDER, ONWEBCART, ONWEBREGISTER, FORM, ONWEBDETAIL)New Feature
POST
This creates a LinkedIn Single Image Ad backed by a Direct Sponsored Content ("dark post") authored by a Company Page, with supported goals
Key request fields for LinkedIn:
•
•
•
•
•
•
Also updated:
•
• Meta-only: new
/v1/ads/create now supports creating LinkedIn standalone ads.This creates a LinkedIn Single Image Ad backed by a Direct Sponsored Content ("dark post") authored by a Company Page, with supported goals
engagement, traffic, awareness (and traffic requires linkUrl).Key request fields for LinkedIn:
•
organizationId (Company Page org ID or urn:li:organization:N; required unless it can be inferred)•
headline (now required for LinkedIn; max 400)•
body (used as LinkedIn post commentary)•
imageUrl (required for LinkedIn)•
linkUrl (required for goal=traffic)•
longHeadline (optional secondary description on LinkedIn traffic ads)Also updated:
•
callToAction enum expanded with REGISTER, JOIN, ATTEND, REQUESTDEMO, VIEWQUOTE, APPLY, SEEMORE, BUYNOW• Meta-only: new
attributionSpec to control conversion attribution windows (CLICKTHROUGH/VIEWTHROUGH/ENGAGEDVIDEOVIEW with windowDays 1/7/28).New Feature
Meta ads (boosted/dark posts) are now included in
Ad rows are flagged so you can route comment fetching to the ads comments thread.
Use
•
•
• omit
New fields on inbox rows:
GET /v1/inbox/comments for users with the Ads add-on (Metronome plans always qualify).Ad rows are flagged so you can route comment fetching to the ads comments thread.
Use
platform:•
metaads - ads only•
facebook/instagram - organic only• omit
platform - bothNew fields on inbox rows:
isAd (boolean), adId (string). For ad rows, fetch the thread via GET /v1/ads/{adId}/comments.GET /v1/inbox/comments/{postId} now returns meta.adComments when a boosted post has no organic comments (includes adId and adCommentsUrl), and may return 400 with code USEADCOMMENTS_ENDPOINT when postId is an ad creative/ad ID.GET /v1/ads adds filters to map Business Manager IDs back to Zernio ads: platformAdId, effectiveObjectStoryId, effectiveInstagramMediaId.Improvement
GET
This makes it easier to identify the boosted IG post and which connected Instagram account was used to read comments (useful for follow-up reply/hide actions via
New
•
•
•
Also clarified: for Instagram-placed ads, if no connected Instagram account on the profile can read the ad’s media, the endpoint returns
/v1/ads/{adId}/comments now returns additional Instagram metadata in meta for Instagram-placed ads.This makes it easier to identify the boosted IG post and which connected Instagram account was used to read comments (useful for follow-up reply/hide actions via
/v1/inbox/comments).New
meta fields (Instagram-only):•
instagramUserId•
instagramPermalink•
instagramAccountIdAlso clarified: for Instagram-placed ads, if no connected Instagram account on the profile can read the ad’s media, the endpoint returns
422 with code adsconnectionrequired.New Feature
Meta Ads now supports managing Tracking Tags (Meta Pixels) via new endpoints.
You can list/create/get/update pixels, share/unshare them across ad accounts, and fetch aggregated event stats.
New endpoints:
•
•
•
•
•
•
Notes: Meta-only (
You can list/create/get/update pixels, share/unshare them across ad accounts, and fetch aggregated event stats.
New endpoints:
•
GET /v1/accounts/{accountId}/tracking-tags (optional adAccountId=act_...)•
POST /v1/accounts/{accountId}/tracking-tags body: adAccountId, name (not idempotent)•
GET /v1/accounts/{accountId}/tracking-tags/{tagId} (includes install code)•
PATCH /v1/accounts/{accountId}/tracking-tags/{tagId} fields: name, enableAutomaticMatching, automaticMatchingFields (em/ph/fn/ln/ge/db/ct/st/zp/country/externalid), firstPartyCookieStatus (empty/firstpartycookiedisabled/firstpartycookieenabled), dataUseSetting (advertisingandanalytics/analyticsonly/empty)•
GET|POST|DELETE /v1/accounts/{accountId}/tracking-tags/{tagId}/shared-accounts (DELETE supports adAccountId query)•
GET /v1/accounts/{accountId}/tracking-tags/{tagId}/stats (optional aggregation, startTime, endTime; aggregation enum includes event, url, devicetype, browsertype, etc.)Notes: Meta-only (
platform=metaads; other platforms return 405). Requires the Meta ads SocialAccount from the Ads add-on connect flow; list view omits code (use get to retrieve it).New Feature
Comment-to-DM automations now support inline DM buttons via
You can attach up to 3 buttons to the auto-DM (URL, postback, or phone on Facebook) to drive clicks or capture postbacks.
Use
•
•
Button schema:
Note: when
buttons.You can attach up to 3 buttons to the auto-DM (URL, postback, or phone on Facebook) to drive clicks or capture postbacks.
Use
buttons in:•
POST /v1/comment-automations•
PATCH /v1/comment-automations/{automationId} (pass buttons: [] to clear)Button schema:
{ type, title, url|payload|phone } where type is url | postback | phone (phone = Facebook-only), and title is max 20 chars.Note: when
buttons is non-empty, dmMessage must be ≤ 640 characters. Responses from list/get/create/update may now include buttons (omitted when none are set).Deprecation
X API pricing/usage reporting now includes a new $0.200 “posts with URL” operation and tier.
This lets you attribute X spend more accurately per action; new clients should rely on per-operation counts rather than tier aggregates.
Key changes:
• New operation in
•
• In
This lets you attribute X spend more accurately per action; new clients should rely on per-operation counts rather than tier aggregates.
Key changes:
• New operation in
GET /v1/billing/x-pricing: operation=contentcreatewithurl with tier=xapi_200 and pricePerCallUsd=0.2•
contentcreate price moved to pricePerCallUsd=0.015 (now tier=xapi_015)• In
GET /v1/usage-stats, usage.xApiCalls is now deprecated and excludes xapi200 (and future tiers); use usage.xApiCallsByOperation as the source of truthImprovement
WhatsApp is now supported on
On WhatsApp, the typing indicator shows typing... for up to 25 seconds. It requires a recent inbound message in the conversation (Meta references the inbound message id) and will also mark that inbound message as read as a side-effect.
Use:
POST /v1/inbox/conversations/{conversationId}/typing.On WhatsApp, the typing indicator shows typing... for up to 25 seconds. It requires a recent inbound message in the conversation (Meta references the inbound message id) and will also mark that inbound message as read as a side-effect.
Use:
{ "accountId": "..." }New Feature
Message webhooks now include expanded Meta ad-click attribution in
This lets you attribute the first inbound message to a specific Facebook/Instagram ad click for CTM/CTD flows.
New fields in
•
•
•
•
•
metadata.referral (in addition to WhatsApp CTWA).This lets you attribute the first inbound message to a specific Facebook/Instagram ad click for CTM/CTD flows.
New fields in
metadata.referral:•
ad_id•
ref•
source•
type•
adscontextdata (object: adtitle, photourl, videourl, postid, productid, flowid)metadata.referral is now nullable and is only populated on the first inbound message after the click.New Feature
LinkedIn Ads now plugs into Zernio's unified Conversions API. Stream offline conversion events to LinkedIn's
New capabilities for
•
•
•
•
•
•
Supports the LinkedIn first-party click ID
Reconnect required for LinkedIn accounts connected before this change — LinkedIn does not silently upgrade existing OAuth grants with the new
/rest/conversionEvents through the same /v1/ads/conversions endpoint you already use for Meta and Google.New capabilities for
linkedinads accounts:•
POST /v1/ads/conversions — stream events (BATCH_CREATE, up to 5,000 per call)•
GET /v1/accounts/{accountId}/conversion-destinations — list rules across every sponsored ad account•
POST /v1/accounts/{accountId}/conversion-destinations — create a new rule (with autoAssociationType=ALL_CAMPAIGNS by default)•
GET|PATCH|DELETE /v1/accounts/{accountId}/conversion-destinations/{destinationId} — single-rule CRUD (DELETE soft-deletes via enabled: false)•
GET|POST|DELETE .../associations — campaign↔conversion mapping•
GET .../metrics?startDate=&endDate=&granularity= — externalWebsiteConversions, conversionValueInLocalCurrency, qualifiedLeads, etc., bucketed by dateSupports the LinkedIn first-party click ID
lifatid (added to user.clickIds) for higher match rates. Standard event names map to LinkedIn rule types (Lead → LEAD, Purchase → PURCHASE, ...); LinkedIn enum values pass through unchanged.Reconnect required for LinkedIn accounts connected before this change — LinkedIn does not silently upgrade existing OAuth grants with the new
rwconversions scope. Affected accounts return 403 linkedinreconnect_required until the user re-authorises.New Feature
Webhooks now support additional message events you can subscribe to when creating/updating webhook settings.
This lets you receive callbacks for outbound message lifecycle changes (send/edit/delete/delivery/read/failure), not just inbound messages.
Use
•
Also added to
This lets you receive callbacks for outbound message lifecycle changes (send/edit/delete/delivery/read/failure), not just inbound messages.
Use
events in POST /v1/webhooks/settings or PUT /v1/webhooks/settings with any of:•
message.sent, message.edited, message.deleted, message.delivered, message.read, message.failedAlso added to
WebhookPayloadMessage.metadata (Instagram only): storyReply and isStoryMention.Improvement
Ads analytics endpoints now support up to a 730-day metrics date range (previously 90 days).
You can query longer historical performance, and requests for ranges older than 90 days may trigger a one-time on-demand fetch from the ad platform, then be served from cache on subsequent requests.
Applies to:
•
•
•
Use
You can query longer historical performance, and requests for ranges older than 90 days may trigger a one-time on-demand fetch from the ad platform, then be served from cache on subsequent requests.
Applies to:
•
GET /v1/ads (max range 730 days)•
GET /v1/ads/tree (max range 730 days)•
GET /v1/ads/{adId}/analytics (max range 730 days)Use
fromDate / toDate; ranges older than 90 days may require scoping to accountId (where noted) to trigger the on-demand fetch.New Feature
POST
You can attach 1–3 buttons rendered in the same message bubble (Meta
New request field:
Button types:
•
•
•
/v1/inbox/comments/{postId}/{commentId}/private-reply now supports inline buttons on the first private reply.You can attach 1–3 buttons rendered in the same message bubble (Meta
button_template). This is recommended for cold reach because quickReplies don’t render in Instagram Message Requests.New request field:
buttons (min 1, max 3), mutually exclusive with quickReplies.Button types:
•
url: { type, title, url }•
postback: { type, title, payload }•
phone (Facebook only): { type, title, phone }New Feature
WhatsApp headless OAuth now supports multi-phone WABA selection via a new two-step flow.
When the OAuth redirect includes
Then bind the chosen number with
•
•
•
•
Note:
When the OAuth redirect includes
step=selectphonenumber, first list available numbers with GET /v1/connect/whatsapp/select-phone-number using profileId + tempToken (optional X-Connect-Token).Then bind the chosen number with
POST /v1/connect/whatsapp/select-phone-number:•
profileId•
tempToken•
wabaId•
phoneNumberIdNote:
GET /v1/connect/pending-data is now documented as only for LinkedIn organizations and Snapchat profiles; WhatsApp selection state is passed via redirect params and pending-data may return 404 for WhatsApp flows.New Feature
New endpoint
For
•
•
•
•
•
•
Also:
GET /v1/billing/x-pricing returns Zernio’s canonical X/Twitter API pricing table (per-operation rates, 0% markup). Use it with GET /v1/usage-stats to compute exact X spend from per-operation call counts.GET /v1/usage-stats now varies by billingSystem: stripe | metronome.For
metronome accounts it includes:•
usage.connectedAccounts•
usage.xApiCalls (tier buckets: xapi005 | xapi010 | xapi015)•
usage.xApiCallsByOperation (keys resolve via GET /v1/billing/x-pricing)•
spend.currentPeriodCents, spend.xSpendCents, spend.xSpendLimitCentsPUT /v1/accounts/{accountId} (X only, usage-based) accepts xCapabilities to opt into background metered operations:•
xCapabilities.analytics•
xCapabilities.inboxAlso:
POST /v1/profiles and GET /v1/connect/{platform} may now return 402 PaymentRequired.New Feature
POST
You can include up to 13 chips to let users pick an intent in-app (Instagram/Messenger apps only).
New optional field:
•
•
•
/v1/inbox/comments/{postId}/{commentId}/private-reply now supports optional quick reply chips on the first private reply.You can include up to 13 chips to let users pick an intent in-app (Instagram/Messenger apps only).
New optional field:
quickReplies (max 13)•
quickReplies[].title (max 20 chars)•
quickReplies[].payload•
quickReplies[].imageUrl (optional)Improvement
Account groups can now include accounts across multiple profiles. For API keys scoped to specific profiles,
Meta ads connect can now be scoped to specific ad accounts via
Webhook
•
•
GET /v1/account-groups only returns groups whose accountIds are all in allowed profiles.GET /v1/account-groups may now include createdBy and legacy profileId (only on older groups).POST /v1/account-groups accepts deprecated profileId (ignored) for backward compatibility.Meta ads connect can now be scoped to specific ad accounts via
GET /v1/connect/{platform}/ads (metaads only): adAccountId (format act_<digits>) or adAccountIds (repeat or comma-separated). Response may include scopedAdAccountIds.Webhook
account.ads.initialsynccompleted now includes richer correlation + error details:•
account.platformAdAccountId, account.platformAdAccountIds•
sync.error, sync.errorCode, sync.errorSubcode, sync.errorCategory = tokeninvalid | permissiondenied | noadaccounts | ratelimited | discoveryfailed | unknownBreaking Change
POST /v1/account-groups no longer requires profileId in the request body.You can now create an account group using only a name and the list of social account IDs.
Request body now requires:
•
name•
accountIdsNew Feature
POST /v1/comment-automations now supports account-wide (any post) comment-to-DM automations.You can omit
platformPostId (and postId) to evaluate comments across every post on an account. Multiple account-wide automations can be stacked and run independently; per-post automations take priority on their post.Key request rules:
• Per-post: set
platformPostId and include postId• Account-wide: omit
platformPostId (and postId)•
matchMode: exact | containsNote:
409 now applies only to per-post automations (duplicate active platformPostId).New Feature
New Meta geo targeting lookup endpoint:
It lets you resolve a human-readable location name into Meta’s opaque location
Call with
•
•
GET /v1/ads/targeting/search.It lets you resolve a human-readable location name into Meta’s opaque location
key for use in ad targeting.Call with
accountId, q, optional type (country/region/city/subcity/neighborhood/zip/metroarea/geomarket, default city), optional countryCode, and optional limit.POST /v1/ads/create now supports Meta-only geo targeting via cities[] and regions[]:•
cities[]: { key, radius?, distanceunit? } where distanceunit is mile or kilometer•
regions[]: { key }countries[] is now documented as ISO-2 codes and defaults to ["US"] when no cities/regions are provided.Improvement
TikTok ads created via
This lets you set a CTA on TikTok using the same field you already use for Meta.
Set
•
POST /v1/ads/create now honor callToAction (it’s passed through to the Spark Ad creative’s calltoaction).This lets you set a CTA on TikTok using the same field you already use for Meta.
Set
callToAction to one of:•
LEARNMORE, SHOPNOW, SIGNUP, BOOKTRAVEL, CONTACTUS, DOWNLOAD, GETOFFER, GETQUOTE, SUBSCRIBE, WATCHMOREBreaking Change
TikTok boost ads now surface clearer requirements and failure modes in
For TikTok boosts, include
The
Also note:
POST /v1/ads/boost.For TikTok boosts, include
targeting.countries (ISO country codes). TikTok requires locations on the ad group; other platforms can omit it.The
422 response can now also indicate the connected TikTok user isn’t authorized as an Identity on the target advertiser (returned with code adsconnectionrequired and an actionable remediation message).Also note:
BusinessCenter.advertiserCount is now nullable (null when the BC asset walk is empty/failed, distinct from 0).Improvement
Analytics endpoints now support filtering by social account via
This lets you scope results to a specific connected account (useful when a
Added optional query param
•
•
•
accountId.This lets you scope results to a specific connected account (useful when a
profileId contains multiple accounts).Added optional query param
accountId on:•
GET /v1/analytics/best-time•
GET /v1/analytics/content-decay•
GET /v1/analytics/posting-frequencyNew Feature
New Ads endpoints and expanded TikTok support.
You can now list TikTok Business Centers.
• List TikTok BCs:
TikTok campaign duplication is now supported via
Ad updates now support more platforms/fields:
•
Ad account listing now supports filtering/limiting:
•
TikTok boost now supports cross-creator Spark Ads:
•
Standalone ad creation “attach” mode now supports TikTok:
•
New response fields:
•
•
You can now list TikTok Business Centers.
• List TikTok BCs:
GET /v1/ads/business-centers with accountId → returns businessCenters[] (bcId, name, advertiserCount)TikTok campaign duplication is now supported via
POST /v1/ads/campaigns/{campaignId}/duplicate by setting platform to tiktok (Meta still supported).Ad updates now support more platforms/fields:
•
PUT /v1/ads/{adId} supports targeting + creative on facebook/instagram/tiktok. Other platforms return 501 (unsupportedplatformoperation) when sending targeting or creative.Ad account listing now supports filtering/limiting:
•
GET /v1/ads/accounts adds optional adAccountId and limitTikTok boost now supports cross-creator Spark Ads:
•
POST /v1/ads/boost adds sparkAuthCodeStandalone ad creation “attach” mode now supports TikTok:
•
POST /v1/ads/create adSetId is now supported for tiktok (ad group ID)New response fields:
•
Ad adds platformAdAccountName and platformCreatedAt•
AdCampaign and AdTreeCampaign add platformAdAccountNameNew Feature
Ads API now supports setting bid strategy on campaigns, ad sets, and boosted posts.
You can update campaign-level defaults via
Set
•
•
•
•
Boosting posts via
Ad read models now include
GBP location details (
You can update campaign-level defaults via
PUT /v1/ads/campaigns/{campaignId} using bidStrategy (optionally alongside budget). Ad sets can now be updated via PUT /v1/ads/ad-sets/{adSetId} with bidStrategy plus bidAmount or roasAverageFloor when required.Set
bidStrategy to:•
LOWESTCOSTWITHOUT_CAP•
LOWESTCOSTWITHBIDCAP (requires bidAmount)•
COST_CAP (requires bidAmount)•
LOWESTCOSTWITHMINROAS (requires roasAverageFloor)Boosting posts via
POST /v1/ads/boost now accepts bidStrategy, bidAmount, and roasAverageFloor. TikTok boosts also add linkUrl and callToAction.Ad read models now include
bidStrategy (normalized for Meta + TikTok) and may include bidAmount / roasAverageFloor on Ad, AdCampaign, and AdTree* responses.GBP location details (
GET /v1/accounts/{accountId}/gmb-location-details) now always includes title + metadata and always populates the derived location summary; passing location in readMask returns 400.New Feature
GET
This provides a compact, public-facing view derived from GBP
New fields under
•
•
•
•
•
Populated when
/v1/accounts/{accountId}/gmb-location-details now returns a new location summary object in the 200 response.This provides a compact, public-facing view derived from GBP
metadata, making it easy to surface “leave a review” and Maps URLs without parsing the raw metadata block.New fields under
location:•
name•
placeId•
reviewUrl•
mapsUri•
isVerifiedPopulated when
readMask includes metadata (default). For unverified/new locations, placeId/reviewUrl/mapsUri may be null.Improvement
GET
Use these fields to align daily budget reset timing and Insights day boundaries with the ad account’s local timezone.
New fields in each item of
•
•
/v1/ads/accounts now returns Meta ad account timezone details: timezoneName and timezoneOffsetHoursUtc.Use these fields to align daily budget reset timing and Insights day boundaries with the ad account’s local timezone.
New fields in each item of
accounts[]:•
timezoneName (IANA timezone, Meta only)•
timezoneOffsetHoursUtc (signed UTC offset in hours, reflects current DST, Meta only)Improvement
Meta ads now support DSA (EU) advertiser disclosures via two new optional fields on ad creation endpoints.
When your targeting intersects EU member states, Meta may require these values (enforced server-side) to comply with DSA Article 26.
Set:
•
•
Available on:
•
•
•
When your targeting intersects EU member states, Meta may require these values (enforced server-side) to comply with DSA Article 26.
Set:
•
dsaBeneficiary — legal entity benefiting from the ad•
dsaPayor — legal entity paying for the ad (Meta spelling: dsa_payor)Available on:
•
POST /v1/ads/boost•
POST /v1/ads/create•
POST /v1/ads/ctwaImprovement
GET
You can page through long conversations using an opaque cursor, and request oldest-first or newest-first results (with platform-specific limitations).
New query params:
•
•
•
New response fields:
•
•
•
Also:
/v1/inbox/conversations/{conversationId}/messages now supports cursor-based pagination and sort order control.You can page through long conversations using an opaque cursor, and request oldest-first or newest-first results (with platform-specific limitations).
New query params:
•
limit (1–100, default 100)•
cursor (pass prior pagination.nextCursor)•
sortOrder: asc | desc (default asc)New response fields:
•
pagination.hasMore•
pagination.nextCursor•
sortOrderApplied: asc | descAlso:
WebhookPayloadMessage.metadata adds referral (WhatsApp only) for Click-to-WhatsApp ad attribution on the first inbound message after a CTWA ad click (e.g. ctwaclid, sourceurl, imageurl/videourl).New Feature
POST
Use this to restrict the audience by gender when creating Meta (facebook/instagram) ads; non-Meta platforms ignore it.
Set
/v1/ads/create now supports Meta-only gender targeting via gender.Use this to restrict the audience by gender when creating Meta (facebook/instagram) ads; non-Meta platforms ignore it.
Set
gender to: • all (default) • male • femaleNew Feature
New endpoints added for Click-to-WhatsApp ads and WhatsApp conversion attribution.
Create CTWA ads on Meta in one call via
Key fields:
Send WhatsApp conversation conversion events to Meta CAPI (business messaging) via
Key fields:
Create CTWA ads on Meta in one call via
POST /v1/ads/ctwa (creates campaign → ad set → creative → ad).Key fields:
accountId, adAccountId, name, headline, body, budgetAmount, budgetType (daily | lifetime), and exactly one of imageUrl or video (url, thumbnailUrl). Optional: objective (OUTCOMEENGAGEMENT | OUTCOMESALES | OUTCOME_LEADS).Send WhatsApp conversation conversion events to Meta CAPI (business messaging) via
POST /v1/whatsapp/conversions.Key fields:
accountId, eventName (LeadSubmitted | Purchase | AddToCart | InitiateCheckout | ViewContent), eventId, optional eventTime, and at least one of conversationId or phoneE164. Note: returns 422 if no captured ctwa_clid (no attribution possible); on 200 check eventsFailed and failures[] for Meta rejections.Improvement
GET
Use it to return only posts published via a specific connected account (useful when multiple accounts exist per platform/profile).
New parameter:
•
/v1/posts now supports filtering by social account via the optional query param accountId.Use it to return only posts published via a specific connected account (useful when multiple accounts exist per platform/profile).
New parameter:
•
accountId (string, 24-char hex ObjectId) — filter posts to those published via a specific social accountNew Feature
Webhooks now support the new event
This fires once per ads-enabled account when the initial discovery + 90-day ads backfill finishes (including partial success or failure), so you can trigger downstream processing when the initial ads dataset is ready.
Subscribe via
•
•
Event:
Payload highlights:
account.ads.initialsynccompleted.This fires once per ads-enabled account when the initial discovery + 90-day ads backfill finishes (including partial success or failure), so you can trigger downstream processing when the initial ads dataset is ready.
Subscribe via
events on:•
POST /v1/webhooks/settings•
PUT /v1/webhooks/settingsEvent:
account.ads.initialsynccompletedPayload highlights:
account.accountId, account.profileId, account.platform, sync.status (success | failure), sync.totalAds, sync.synced, sync.failed, timestamp.Improvement
Comment automation logs now include separate results for the DM and the optional public comment reply in
You can now track whether the DM was sent and whether the public reply was attempted/sent, with separate error messages.
New log fields:
•
•
•
•
GET /v1/comment-automations/{automationId} and GET /v1/comment-automations/{automationId}/logs.You can now track whether the DM was sent and whether the public reply was attempted/sent, with separate error messages.
New log fields:
•
status (sent | failed | skipped) — DM outcome•
error — DM error if status is failed•
commentReplyStatus (sent | failed | skipped) — public reply outcome•
commentReplyError — public-reply error if commentReplyStatus is failedNew Feature
New analytics endpoints are available for YouTube, LinkedIn org pages, TikTok, Facebook Pages, and Instagram follower history. All new endpoints reuse the same response envelope as
YouTube channel totals (no per-video looping):
Key params:
Notes: requires
LinkedIn organization page aggregate analytics:
Key params:
Notes: requires scopes
TikTok account-level insights:
Key params:
Notes: requires
Facebook Page insights (post-Nov-2025 Meta metric names):
Key params:
Notes: deprecated Meta metrics (
Instagram follower history (daily follower count time series):
Key params:
Also added for LinkedIn personal analytics:
•
•
/v1/analytics/instagram/account-insights for consistent client handling.YouTube channel totals (no per-video looping):
GET /v1/analytics/youtube/channel-insightsKey params:
accountId, metrics, since, until, metricType (totalvalue|timeseries)Notes: requires
yt-analytics.readonly (412 if missing) + Analytics add-on; data is delayed 2–3 days (range clamped).LinkedIn organization page aggregate analytics:
GET /v1/analytics/linkedin/org-aggregate-analyticsKey params:
accountId, metrics, since, until, metricType (totalvalue|timeseries)Notes: requires scopes
rorganizationsocial + rorganizationfollowers + rorganizationadmin (412 if missing) + Analytics add-on; page-view metrics are total_value only.TikTok account-level insights:
GET /v1/analytics/tiktok/account-insightsKey params:
accountId, metrics, since, until, metricType (totalvalue|timeseries)Notes: requires
user.info.stats (412 if missing) + Analytics add-on.Facebook Page insights (post-Nov-2025 Meta metric names):
GET /v1/analytics/facebook/page-insightsKey params:
accountId, metrics, since, until, metricType (totalvalue|timeseries)Notes: deprecated Meta metrics (
pageimpressions, pagefans, pagefanadds, pagefanremoves) are rejected; use pagemediaview, pagefollows, etc. followersgained/followers_lost are synthesized.Instagram follower history (daily follower count time series):
GET /v1/analytics/instagram/follower-historyKey params:
accountId, metrics (default followercount,followersgained,followerslost), since, until, metricType (totalvalue|time_series)Also added for LinkedIn personal analytics:
•
GET /v1/accounts/{accountId}/linkedin-aggregate-analytics now supports POSTSAVE and POSTSEND in metrics•
GET /v1/accounts/{accountId}/linkedin-post-analytics now returns saves and sends (personal only; org returns 0)New Feature
LinkedIn post analytics now include
LinkedIn added POSTSAVE and POSTSEND to
•
•
Scope: personal LinkedIn accounts only. LinkedIn did not add these metrics to the organization/company-page analytics endpoint, so organization accounts return
saves and sends.LinkedIn added POSTSAVE and POSTSEND to
memberCreatorPostAnalytics in their 202604 API version. Both fields are now returned on:•
GET /v1/accounts/{accountId}/linkedin-post-analytics•
GET /v1/accounts/{accountId}/linkedin-aggregate-analytics (pass POSTSAVE and/or POSTSEND via the metrics query param, or omit metrics to get them automatically)Scope: personal LinkedIn accounts only. LinkedIn did not add these metrics to the organization/company-page analytics endpoint, so organization accounts return
0 for saves and sends. No OAuth reconnect required, the existing rmemberpostAnalytics scope already covers it.Breaking Change
POST /v1/ads/create now supports 3 mutually-exclusive request shapes (and has updated required fields).You can now (Meta-only) create multiple ads in one call via
creatives[], or attach a new ad to an existing ad set via adSetId.Key request options:
• Legacy single-creative: use top-level
goal, budgetAmount, budgetType, headline, body, imageUrl, linkUrl, callToAction• Multi-creative (Meta only): set
creatives[] (min 1). Each item requires headline, body, imageUrl, linkUrl, callToAction• Attach (Meta only): set
adSetId + a single creative at top-level; goal/budgetAmount/budgetType are inheritedcreatives[] and adSetId are mutually exclusive (400 if both). Non-Meta platforms with creatives[]/adSetId return 400.Response change: 201 may return either
ad (legacy/attach) or ads[] + platformCampaignId + platformAdSetId (multi-creative).Improvement
Ad metrics now include revenue and ROAS fields for Meta insights.
You can read monetary action totals via
•
•
Meta-only; other platforms return
You can read monetary action totals via
actionValues (mirrors actions, values in ad-account currency), plus convenience rollups:•
purchaseValue — summed purchase-type action values•
roas — purchaseValue / spendMeta-only; other platforms return
{} for actionValues and 0 for purchaseValue/roas.New Feature
New Ads API write endpoints are available for managing campaigns and ad sets (budget updates, pause/resume, duplication, deletion). This adds first-class support for CBO vs ABO budget routing and bulk status changes.
Campaign budget updates (CBO):
• Body:
• If the campaign is ABO, returns
Ad set updates (ABO budget and/or status):
• Body:
• If parent campaign is CBO and you try to update budget here, returns
Convenience ad set status toggle:
• Body:
Bulk pause/resume campaigns (up to 50):
• Body:
• Returns per-campaign results so one failure doesn’t fail the whole batch
Duplicate a campaign (Meta async copy + optional discovery):
• Key options:
Delete a campaign (cascades to ad sets/ads):
• Body:
Also added to campaign responses (
•
•
Meta-only for now where noted; other platforms may return
Campaign budget updates (CBO):
PUT /v1/ads/campaigns/{campaignId}• Body:
platform (facebook|instagram), budget.amount, budget.type (daily|lifetime)• If the campaign is ABO, returns
409 (BUDGETLEVELMISMATCH) — update the ad set insteadAd set updates (ABO budget and/or status):
PUT /v1/ads/ad-sets/{adSetId}• Body:
platform, optional budget, optional status (active|paused)• If parent campaign is CBO and you try to update budget here, returns
409 (BUDGETLEVELMISMATCH)Convenience ad set status toggle:
PUT /v1/ads/ad-sets/{adSetId}/status• Body:
platform, status (active|paused)Bulk pause/resume campaigns (up to 50):
POST /v1/ads/campaigns/bulk-status• Body:
status (active|paused), campaigns[] with platformCampaignId + platform• Returns per-campaign results so one failure doesn’t fail the whole batch
Duplicate a campaign (Meta async copy + optional discovery):
POST /v1/ads/campaigns/{campaignId}/duplicate• Key options:
deepCopy (default true), statusOption (ACTIVE|PAUSED|INHERITEDFROMSOURCE), syncAfter (default true)Delete a campaign (cascades to ad sets/ads):
DELETE /v1/ads/campaigns/{campaignId}• Body:
platform (facebook|instagram)Also added to campaign responses (
GET /v1/ads/campaigns and GET /v1/ads/tree):•
reviewStatus (inreview|approved|rejected|withissues)•
budgetLevel (campaign|adset), campaignBudget, and currency to disambiguate CBO vs ABO budgetsMeta-only for now where noted; other platforms may return
501 for unsupported operations.Improvement
Ad metrics now include conversion reporting and raw action breakdowns via new fields on
This lets you read conversion counts/cost directly and also extract any Meta action/conversion type from Insights without relying only on derived metrics.
New fields:
•
•
•
AdMetrics.This lets you read conversion counts/cost directly and also extract any Meta action/conversion type from Insights without relying only on derived metrics.
New fields:
•
conversions (integer) — conversion events matching the campaign’s promoted event type (Meta-only for now; others return 0)•
costPerConversion (number) — spend / conversions (0 when conversions is 0)•
actions (object<string, integer>) — per actiontype counts (e.g. linkclick, offsiteconversion.fbpixel_purchase)New Feature
Announcing Zernio Ads. Run paid social campaigns across 6 platforms directly through the Zernio API.
You can now boost organic posts, create standalone ads with custom creative, manage Campaign / Ad Set / Ad hierarchies, build custom audiences, target by interests and geography, pull analytics, and relay conversion events, all through one unified API.
Supported platforms: Meta (Facebook, Instagram), Google Ads, TikTok, LinkedIn, Pinterest, X/Twitter.
Endpoints:
•
•
•
•
•
•
•
•
•
Targeting supports age (13 to 65), countries, interests, custom audiences, and Meta's Advantage Audience. Goals include
Requires the Ads add-on on your account.
You can now boost organic posts, create standalone ads with custom creative, manage Campaign / Ad Set / Ad hierarchies, build custom audiences, target by interests and geography, pull analytics, and relay conversion events, all through one unified API.
Supported platforms: Meta (Facebook, Instagram), Google Ads, TikTok, LinkedIn, Pinterest, X/Twitter.
Endpoints:
•
POST /v1/ads/boost: turn an organic post into a paid ad•
POST /v1/ads/create: create standalone ads with custom creative•
GET /v1/ads: list ads with spend, impressions, clicks, CTR, CPC, CPM (up to 90 days)•
GET /v1/ads/tree: nested Campaign > Ad Set > Ad view•
GET /v1/ads/campaigns: aggregated campaign view•
GET /v1/ads/audiences, POST /v1/ads/audiences: list and create custom audiences (Meta lookalike, customer list, website pixel)•
POST /v1/ads/sync: pull external ads from platforms into Zernio•
POST /v1/ads/conversions: unified Conversions API relay (Meta, Google Ads)•
GET /v1/connect/{platform}/ads: OAuth connection flow for ad accountsTargeting supports age (13 to 65), countries, interests, custom audiences, and Meta's Advantage Audience. Goals include
engagement, traffic, awareness, videoviews, leadgeneration, conversions, and app_promotion (availability varies by platform).Requires the Ads add-on on your account.
Improvement
Meta ads now support Advantage Audience controls when creating/boosting ads and when updating Meta targeting.
This lets you explicitly enable/disable Meta’s targeting automation during ad set creation, and optionally preserve the current setting on updates.
Use:
•
•
•
This lets you explicitly enable/disable Meta’s targeting automation during ad set creation, and optionally preserve the current setting on updates.
Use:
•
POST /v1/ads/boost: targeting.advantage_audience = 0 | 1•
PUT /v1/ads/{adId}: targeting.advantage_audience = 0 | 1 (omit to keep existing)•
POST /v1/ads/create: advantageAudience = 0 | 1Improvement
PUT /v1/inbox/conversations/{conversationId} can now return 404.This happens when the conversation isn’t found on WhatsApp (other platforms upsert instead of returning not found).
Handle the new response:
404 Conversation not found.New Feature
Reddit posting now supports native video submissions via new fields in
You can upload videos to Reddit’s CDN for an embedded player (with automatic fallback to a link post if video posts aren’t allowed), or submit silent looping clips.
New fields:
•
•
•
RedditPlatformData.You can upload videos to Reddit’s CDN for an embedded player (with automatic fallback to a link post if video posts aren’t allowed), or submit silent looping clips.
New fields:
•
nativeVideo (boolean, default true) - use Reddit native video flow; set false to fall back to a legacy link post•
videogif (boolean) - submit as silent videogif when nativeVideo is active•
videoPosterUrl (uri) - optional thumbnail/poster image for native video postsNew Feature
Webhooks now support review events via
Sending inbox messages now supports WhatsApp rich interactive messages via
Set
Interactive taps/submissions are delivered in the
events: review.new, review.updated (in POST /v1/webhooks/settings and PUT /v1/webhooks/settings).Sending inbox messages now supports WhatsApp rich interactive messages via
interactive in POST /v1/inbox/conversations/{conversationId}/messages.Set
interactive.type to: list, cta_url, or flow (WhatsApp only). When interactive is set, it takes priority over buttons and quickReplies.Interactive taps/submissions are delivered in the
message.received webhook under metadata: interactiveType (buttonreply | listreply | nfm_reply), interactiveId, flowResponseJson, flowResponseData.New Feature
New Google Business Profile (GBP) capabilities are available: manage Services, update Place Action links, and fetch Reviews across multiple locations in one call.
Manage location services:
•
•
Update a Place Action link:
•
•
Batch fetch reviews for multi-location accounts:
•
Manage location services:
•
GET /v1/accounts/{accountId}/gmb-services (optional locationId)•
PUT /v1/accounts/{accountId}/gmb-services replaces the full list via serviceItems (structured or free-form, optional price)Update a Place Action link:
•
PATCH /v1/accounts/{accountId}/gmb-place-actions with name (required), and optionally uri and/or placeActionType•
placeActionType: APPOINTMENT, ONLINEAPPOINTMENT, DININGRESERVATION, FOODORDERING, FOODDELIVERY, FOODTAKEOUT, SHOPONLINEBatch fetch reviews for multi-location accounts:
•
POST /v1/accounts/{accountId}/gmb-reviews/batch with locationNames, optional pageSize (max 50) and pageTokenNew Feature
Google Business Platform posts now support EVENT and OFFER types via
This lets you publish event and offer posts (in addition to standard updates) to Google Search/Maps/GBP.
Set
When
When
topicType in GoogleBusinessPlatformData.This lets you publish event and offer posts (in addition to standard updates) to Google Search/Maps/GBP.
Set
topicType to: STANDARD | EVENT | OFFER (default: STANDARD)When
topicType is EVENT, include event (required): event.title, event.schedule.startDate, event.schedule.endDate (optional: startTime, endTime).When
topicType is OFFER, include offer (recommended): offer.offerType (OFFER | BUYONEGET_ONE), offer.redeemOnlineUrl, offer.termsConditions, offer.couponCode.Breaking Change
Webhook comment.received payloads may now include
Handle missing internal IDs by relying on the platform IDs instead.
Fields that can now be
•
•
Use
null for Zernio internal post IDs when the post was not published through Zernio.Handle missing internal IDs by relying on the platform IDs instead.
Fields that can now be
null:•
comment.postId•
post.idUse
comment.platformPostId / post.platformPostId as the stable identifiers in these cases.New Feature
Discord support has been added: you can now manage Discord account settings, list available guild channels, and post to Discord with Discord-specific options.
Manage Discord connection settings:
•
•
•
Post to Discord via
• Required:
• Optional:
Analytics responses now include
Ads goals have been expanded in
Manage Discord connection settings:
•
GET /v1/accounts/{accountId}/discord-settings (read current channel/guild + webhook identity)•
PATCH /v1/accounts/{accountId}/discord-settings (update webhookUsername/webhookAvatarUrl and/or switch channelId)•
GET /v1/accounts/{accountId}/discord-channels (discover channels: type = 0/5/15)Post to Discord via
POST /v1/posts using platformSpecificData = DiscordPlatformData:• Required:
channelId• Optional:
embeds, poll, crosspost, forumThreadName, forumAppliedTags, threadFromMessage, tts, webhookUsername, webhookAvatarUrlAnalytics responses now include
platformPostId per platform in GET /v1/analytics.Ads goals have been expanded in
POST /v1/ads/boost and POST /v1/ads/create: goal now supports engagement, traffic, awareness, videoviews, leadgeneration, conversions, app_promotion (availability varies by platform).New Feature
New Ads Conversions API endpoints are available:
You can now relay conversion events to Meta or Google Ads; platform is inferred from
Use
Send events via
Response includes
POST /v1/ads/conversions and GET /v1/accounts/{accountId}/conversion-destinations.You can now relay conversion events to Meta or Google Ads; platform is inferred from
accountId. List valid destinations first, then send a batch of events.Use
GET /v1/accounts/{accountId}/conversion-destinations to get destinations[].id (use as destinationId) and destinations[].status (active/inactive). For Google, destinations[].type is present (event type locked to the conversion action).Send events via
POST /v1/ads/conversions with accountId, destinationId, events[] (each requires eventName, eventTime, eventId, user). Optional: testCode (Meta only) and batch-level consent (adUserData/adPersonalization: GRANTED/DENIED, Google only).Response includes
platform (metaads/googleads), eventsReceived, eventsFailed, failures[], and traceId. Requires the Ads add-on.Improvement
Meta ads now return additional campaign/ad set details in ad reporting responses.
You can use these fields to display objective/optimization/bidding context and conversion event setup alongside metrics.
New fields:
• On
• On
• On
You can use these fields to display objective/optimization/bidding context and conversion event setup alongside metrics.
New fields:
• On
Ad: platformObjective, optimizationGoal, bidStrategy, promotedObject• On
AdTreeCampaign and AdCampaign: platformObjective, optimizationGoal (can be string or string[]), bidStrategy, promotedObject• On
AdTreeAdSet: optimizationGoal, bidStrategy, promotedObjectpromotedObject may include customeventtype, pixelid, pageid (and on Ad also applicationid, productset_id). Fields are null when not applicable and are only present for Meta ads.New Feature
Discord is now supported as a platform in several endpoints and response schemas.
You can now use
Updated enums:
•
•
•
• Schemas:
You can now use
platform=discord to connect accounts, validate content, and filter account health.Updated enums:
•
GET /v1/connect/{platform}: {platform} includes discord•
POST /v1/tools/validate/post: platforms[].platform includes discord•
GET /v1/accounts/health: query platform includes discord• Schemas:
SocialAccount.platform, PostLog.platform, ConnectionLog.platform include discordImprovement
GET
Use this to scope results to a specific platform ad account (e.g. Meta
New query param:
The
•
•
•
/v1/ads now supports filtering by platform ad account via adAccountId.Use this to scope results to a specific platform ad account (e.g. Meta
act_123), consistent with /v1/ads/campaigns and /v1/ads/tree.New query param:
adAccountIdThe
Ad schema also adds Meta creative metadata to improve previews for video/moderation states:•
creative.videoId (nullable)•
creative.videoUrl (nullable)•
creative.objectTypeNew Feature
Webhooks and Inbox messages now support message lifecycle updates:
You can subscribe to these via
• Edit tracking:
• Delete tracking:
• Delivery tracking:
message.edited, message.deleted, message.delivered, message.read, message.failed.You can subscribe to these via
Webhook.events and filter webhook logs with GET /v1/webhooks/logs using event values: message.edited, message.deleted, message.delivered, message.read, message.failed.GET /v1/inbox/conversations/{conversationId}/messages now returns additional fields for message state:• Edit tracking:
isEdited, editedAt, editCount, editHistory• Delete tracking:
isDeleted, deletedAt• Delivery tracking:
deliveryStatus (sent/delivered/read/failed/deleted), sentAt, deliveredAt, readAt, deliveryErrorBreaking Change
POST /v1/connect/facebook/select-page now requires userProfile in the request body.If you were previously sending only
profileId, pageId, and tempToken, you must now also include userProfile (decoded from the OAuth callback) to complete the Facebook Page selection flow.Required fields:
profileId, pageId, tempToken, userProfile.New Feature
Webhooks now support message sent events via
Use this to get notified when a message is sent via the API, including message + conversation context.
Subscribe by adding
You can also filter/view deliveries in logs with
Payload schema:
message.sent.Use this to get notified when a message is sent via the API, including message + conversation context.
Subscribe by adding
message.sent to Webhook.events.You can also filter/view deliveries in logs with
GET /v1/webhooks/logs using event=message.sent.Payload schema:
WebhookPayloadMessageSent (includes message, conversation, account, timestamp).Breaking Change
Thread publishing behavior changed for X (Twitter), Threads, and Bluesky when using
If
Key fields:
•
•
•
threadItems.If
threadItems is provided, the top-level content is now used only for display/search and is NOT published. You must include the first post as threadItems[0].Key fields:
•
platformSpecificData.twitter.threadItems•
platformSpecificData.threads.threadItems•
platformSpecificData.bluesky.threadItemsImprovement
Facebook now supports posting an optional first comment for Reels as well as feed posts.
Use
Applies when
Use
platformSpecificData.facebook.firstComment to add a comment immediately after publishing (not supported for contentType=story). Skipped when draft is true.Applies when
contentType is reel (or omitted for feed posts).New Feature
You can now edit a published X (Twitter) post via
This updates the post on X and stores edit history in Zernio. X constraints apply (Premium required, 1-hour edit window, max 5 edits, text-only).
Request body:
•
•
Response includes:
•
•
You can now start/send X DMs via
If a thread already exists, the message is appended. If the recipient doesn’t accept DMs, you’ll get
Key fields:
•
•
•
•
Also added:
• Root-level
•
POST /v1/posts/{postId}/edit.This updates the post on X and stores edit history in Zernio. X constraints apply (Premium required, 1-hour edit window, max 5 edits, text-only).
Request body:
•
platform: twitter•
content: new textResponse includes:
•
id (new tweet ID after edit)•
urlYou can now start/send X DMs via
POST /v1/inbox/conversations.If a thread already exists, the message is appended. If the recipient doesn’t accept DMs, you’ll get
422 with code=DMNOTALLOWED (or bypass the pre-check with skipDmCheck).Key fields:
•
accountId•
participantId or participantUsername•
message (or attachment via multipart/form-data)•
skipDmCheckAlso added:
• Root-level
facebookSettings on POST /v1/posts and PUT /v1/posts/{postId} (e.g. facebookSettings.draft=true to create an unpublished draft in Facebook Publishing Tools)•
TwitterPlatformData.longVideo=true to enable long video uploads (requires X Premium; may require allowlisting).New Feature
New Google Business Profile analytics endpoints are available.
Fetch daily performance metrics (impressions, clicks, calls, directions, etc.) via
Key params:
•
•
•
Fetch monthly search keywords via
Key params:
•
•
Note: keywords below Google’s minimum impression threshold are excluded.
Fetch daily performance metrics (impressions, clicks, calls, directions, etc.) via
GET /v1/analytics/googlebusiness/performance. Requires accountId and the Analytics add-on; data may be delayed 2–3 days; up to 18 months history.Key params:
•
accountId (required)•
metrics (comma-separated; defaults to all): BUSINESSIMPRESSIONSDESKTOPMAPS, BUSINESSIMPRESSIONSDESKTOPSEARCH, BUSINESSIMPRESSIONSMOBILEMAPS, BUSINESSIMPRESSIONSMOBILESEARCH, BUSINESSCONVERSATIONS, BUSINESSDIRECTIONREQUESTS, CALLCLICKS, WEBSITECLICKS, BUSINESSBOOKINGS, BUSINESSFOODORDERS, BUSINESSFOODMENU_CLICKS•
startDate, endDate (YYYY-MM-DD)Fetch monthly search keywords via
GET /v1/analytics/googlebusiness/search-keywords. Requires accountId and the Analytics add-on; up to 18 months history.Key params:
•
accountId (required)•
startMonth, endMonth (YYYY-MM)Note: keywords below Google’s minimum impression threshold are excluded.
New Feature
YouTube analytics now supports audience demographics via
Fetch demographic insights for a YouTube channel broken down by age/gender (percentages) and country (view counts). Requires the Analytics add-on and YouTube Analytics scope.
Key params:
•
•
•
WhatsApp now supports Flows (create/manage/publish and send interactive flow messages).
Manage flows:
•
•
•
•
•
Flow JSON asset:
•
•
Lifecycle:
•
•
Send a flow message:
•
• Optional
GET /v1/analytics/youtube/demographics.Fetch demographic insights for a YouTube channel broken down by age/gender (percentages) and country (view counts). Requires the Analytics add-on and YouTube Analytics scope.
Key params:
•
accountId (required)•
breakdown = age, gender, country (comma-separated; defaults to all)•
startDate, endDateWhatsApp now supports Flows (create/manage/publish and send interactive flow messages).
Manage flows:
•
GET /v1/whatsapp/flows (accountId)•
POST /v1/whatsapp/flows (accountId, name, categories, optional cloneFlowId)•
GET /v1/whatsapp/flows/{flowId} (accountId, optional fields)•
PATCH /v1/whatsapp/flows/{flowId} (accountId, name/categories; DRAFT only)•
DELETE /v1/whatsapp/flows/{flowId} (accountId; DRAFT only)Flow JSON asset:
•
GET /v1/whatsapp/flows/{flowId}/json (accountId)•
PUT /v1/whatsapp/flows/{flowId}/json (accountId, flow_json; DRAFT only)Lifecycle:
•
POST /v1/whatsapp/flows/{flowId}/publish (accountId; irreversible)•
POST /v1/whatsapp/flows/{flowId}/deprecate (accountId; irreversible)Send a flow message:
•
POST /v1/whatsapp/flows/send with accountId, to, flowid, flowcta, body• Optional
flowaction = navigate | dataexchange, flowtoken, flowaction_payload, draftImprovement
YouTube metadata updates now support additional fields on
You can now set COPPA compliance, disclose AI/synthetic media, and add a video to a playlist without re-uploading.
New optional properties:
•
•
•
POST /v1/posts/{postId}/update-metadata.You can now set COPPA compliance, disclose AI/synthetic media, and add a video to a playlist without re-uploading.
New optional properties:
•
madeForKids (boolean)•
containsSyntheticMedia (boolean)•
playlistId (string)New Feature
YouTube metadata updates now support setting a custom thumbnail via
You can update the thumbnail without re-uploading, including for existing videos not published through Zernio (direct video ID mode).
Use
Key params:
POST /v1/posts/{postId}/update-metadata.You can update the thumbnail without re-uploading, including for existing videos not published through Zernio (direct video ID mode).
Use
thumbnailUrl (public image URL) with platform youtube. In direct mode also include videoId + accountId.Key params:
platform (youtube), thumbnailUrl, videoId, accountIdNew Feature
YouTube posts now support adding a video to a playlist via
Use the new playlist endpoints to discover playlist IDs and (optionally) store a client-side default for an account.
New endpoints:
•
•
New field:
•
playlistId in YouTubePlatformData.Use the new playlist endpoints to discover playlist IDs and (optionally) store a client-side default for an account.
New endpoints:
•
GET /v1/accounts/{accountId}/youtube-playlists → returns playlists[] and defaultPlaylistId•
PUT /v1/accounts/{accountId}/youtube-playlists with defaultPlaylistId (optional defaultPlaylistName)New field:
•
platformSpecificData.youtube.playlistId (string) — optional playlist to add the video to after uploadNew Feature
POST /v1/posts/{postId}/update-metadata now supports updating YouTube video metadata even if the video was uploaded outside Zernio.
Use one of two modes:
• Post-based: call with the real
• Direct video ID: set
Key params:
•
•
•
In direct mode, the 200 response may include
Use one of two modes:
• Post-based: call with the real
{postId} and platform• Direct video ID: set
{postId} to _ and include videoId + accountId + platformKey params:
•
platform: youtube•
videoId (direct mode)•
accountId (direct mode)In direct mode, the 200 response may include
videoId.New Feature
New endpoint:
Currently supported for YouTube videos only; the post must be
Request body:
POST /v1/posts/{postId}/update-metadata to update metadata on an already-published post without re-uploading media.Currently supported for YouTube videos only; the post must be
published on the target platform and you must provide at least one updatable field.Request body:
platform (youtube) plus any of title, description, tags, categoryId, privacyStatus (public | private | unlisted).New Feature
Threads posts now support an explicit topic tag via
Use this to categorize posts for discoverability on Threads; when provided, it overrides auto-extraction from content hashtags.
Set
• 1–50 characters
• cannot contain
platformSpecificData.topic_tag.Use this to categorize posts for discoverability on Threads; when provided, it overrides auto-extraction from content hashtags.
Set
topic_tag (string):• 1–50 characters
• cannot contain
. or &Improvement
Analytics endpoints now support filtering by social account via
This lets you scope results to a specific connected account (useful when a
New query parameter:
•
•
accountId.This lets you scope results to a specific connected account (useful when a
profileId contains multiple accounts).New query parameter:
•
GET /v1/analytics: accountId•
GET /v1/analytics/daily-metrics: accountIdNew Feature
You can now send inbox attachments by URL when calling
Provide
Twitter posts now support polls via
Set
POST /v1/inbox/conversations/{conversationId}/messages (JSON body), without using multipart upload.Provide
attachmentUrl (publicly accessible) and optionally attachmentType (image, video, audio, file).Twitter posts now support polls via
TwitterPlatformData.poll.Set
poll.options (2-4 items, max 25 chars each) and poll.duration_minutes (5-10080). Polls are mutually exclusive with media attachments and threads.New Feature
Instagram Analytics now supports account-level insights and audience demographics.
Fetch account performance totals or daily reach via
Key params:
Fetch audience breakdowns via
Key params:
Fetch account performance totals or daily reach via
GET /v1/analytics/instagram/account-insights.Key params:
accountId (required), metrics, since, until, metricType (timeseries | totalvalue), breakdown (totalvalue only). Note: timeseries only works with reach. Max range: 90 days (default last 30). Data may be delayed up to 48 hours. Requires Analytics add-on.Fetch audience breakdowns via
GET /v1/analytics/instagram/demographics.Key params:
accountId (required), metric (followerdemographics | engagedaudiencedemographics), breakdown (age, city, country, gender), timeframe (thisweek | this_month). Requires 100+ followers, returns top 45 per dimension, and may be delayed up to 48 hours. Requires Analytics add-on.New Feature
TikTok video posts now support a custom cover image via
Provide a thumbnail image URL (JPG/PNG/WebP, max 20MB). When set, it overrides
Use:
•
•
videoCoverImageUrl in TikTokPlatformData.Provide a thumbnail image URL (JPG/PNG/WebP, max 20MB). When set, it overrides
videoCoverTimestampMs.Use:
•
videoCoverImageUrl - custom thumbnail image URL•
videoCoverTimestampMs - frame timestamp (ms), ignored if videoCoverImageUrl is providedNew Feature
New endpoint:
You can now fetch TikTok creator details plus the allowed posting options for an account (privacy levels, interaction settings, posting limits, and commercial content disclosures). Useful for validating post settings before publishing.
Key params:
•
•
Also added to
GET /v1/accounts/{accountId}/tiktok/creator-info.You can now fetch TikTok creator details plus the allowed posting options for an account (privacy levels, interaction settings, posting limits, and commercial content disclosures). Useful for validating post settings before publishing.
Key params:
•
accountId (path)•
mediaType (query, default video): video, photoAlso added to
TikTokPlatformData for video posts: videoCoverImageUrl (custom thumbnail URL). When set, it overrides videoCoverTimestampMs.Breaking Change
GET
Single-post lookups can return
Key changes:
• Date defaults/limits:
• Sorting:
• Single post response adds
• Per-platform analytics now include
• List responses add
/v1/analytics now supports richer analytics sync states and more sorting options.Single-post lookups can return
202 when analytics sync is still pending, or 424 when analytics are unavailable because the post failed on all platforms.Key changes:
• Date defaults/limits:
fromDate defaults to 90 days ago, toDate defaults to today, max range 366 days• Sorting:
sortBy now supports date, engagement, impressions, reach, likes, comments, shares, saves, clicks, views• Single post response adds
latePostId, syncStatus (synced/pending/partial/unavailable) and message; status can be published/failed/partial• Per-platform analytics now include
syncStatus (synced/pending/unavailable), platformPostUrl, and errorMessage; analytics may be null• List responses add
posts[].latePostId, posts[].profileId, and overview.dataStalenessNew Feature
Late API now supports X/Twitter engagement actions: retweet, bookmark, and follow (plus undo/remove/unfollow).
Use:
• Retweet:
• Undo retweet:
• Bookmark:
• Remove bookmark:
• Follow:
• Unfollow:
Inbox comment moderation also adds X/Twitter support:
•
•
For X/Twitter, the reply must be in a conversation started by the authenticated user and requires
Use:
• Retweet:
POST /v1/twitter/retweet with accountId, tweetId• Undo retweet:
DELETE /v1/twitter/retweet with accountId, tweetId• Bookmark:
POST /v1/twitter/bookmark with accountId, tweetId• Remove bookmark:
DELETE /v1/twitter/bookmark with accountId, tweetId• Follow:
POST /v1/twitter/follow with accountId, targetUserId (response may include pending_follow for protected accounts)• Unfollow:
DELETE /v1/twitter/follow with accountId, targetUserIdInbox comment moderation also adds X/Twitter support:
•
POST /v1/inbox/comments/{postId}/{commentId}/hide•
DELETE /v1/inbox/comments/{postId}/{commentId}/hideFor X/Twitter, the reply must be in a conversation started by the authenticated user and requires
tweet.moderate.write + X API Basic tier (or higher). Bookmark/follow also require bookmark.write / follows.write scopes, and X API Basic tier (or higher).Improvement
GET /v1/analytics now returns richer media metadata for analytics results.You can render previews and handle carousels consistently using the new fields on both single-post and list responses.
New fields:
•
thumbnailUrl•
mediaType = image | video | gif | document | carousel | text (single-post also supports image | video | carousel | text)•
mediaItems (array of { type: image|video, url, thumbnail }; carousel posts include one entry per slide)Improvement
The
Use
GET /v1/usage-stats response now includes billingAnchorDay.Use
billingAnchorDay (1–31) to determine the day of the month when the billing cycle resets, which can help align usage tracking and reset expectations.Improvement
GBP endpoints now support overriding the target location via optional
This lets you fetch/update reviews, media, attributes, place actions, food menus, and location details for a specific GBP location without changing the account’s selected location.
Use
•
•
•
•
•
•
locationId.This lets you fetch/update reviews, media, attributes, place actions, food menus, and location details for a specific GBP location without changing the account’s selected location.
Use
locationId (query) on:•
GET /v1/accounts/{accountId}/gmb-reviews•
GET/PUT /v1/accounts/{accountId}/gmb-food-menus•
GET/PUT /v1/accounts/{accountId}/gmb-location-details•
GET/POST/DELETE /v1/accounts/{accountId}/gmb-media•
GET/PUT /v1/accounts/{accountId}/gmb-attributes•
GET/POST/DELETE /v1/accounts/{accountId}/gmb-place-actionsNew Feature
Twitter posts now support replying to an existing tweet via
Set
replyToTweetId in TwitterPlatformData.Set
replyToTweetId to publish the first tweet (or the root of a thread) as a reply; subsequent thread items chain normally.replySettings also adds verified (now: following, mentionedUsers, subscribers, verified). Note: replySettings cannot be combined with replyToTweetId.New Feature
New endpoint
Currently supported only for LinkedIn organization/company page accounts (personal profile reaction data is restricted by LinkedIn).
Required params:
Optional:
Response includes
GET /v1/accounts/{accountId}/linkedin-post-reactions returns who reacted to a LinkedIn post, including reactor profile details.Currently supported only for LinkedIn organization/company page accounts (personal profile reaction data is restricted by LinkedIn).
Required params:
accountId (path, LinkedIn org account), urn (query, LinkedIn post URN)Optional:
limit (1–100, default 25), cursorResponse includes
reactions[] with reactionType (LIKE, PRAISE, EMPATHY, INTEREST, APPRECIATION, ENTERTAINMENT), reactedAt, and from (e.g., name, headline, profileUrl, profilePicture), plus pagination.Improvement
GET /v1/connect/{platform} redirect behavior now includes accountId in standard mode.After a successful connect, Zernio’s standard redirect to
redirect_url now appends ?connected={platform}&profileId=X&accountId=Y&username=Z (previously no accountId).In headless mode (
headless=true), the redirect includes raw OAuth data only when a post-OAuth selection step is required (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.New Feature
Posts can now be recycled (auto-reposted on a schedule) via
After the original post is published, Zernio will create new scheduled copies at a weekly/monthly interval until an expiration condition is met.
Configure with
•
•
•
•
•
•
Webhooks: a new event
Also:
recycling on POST /v1/posts and PUT /v1/posts/{postId}.After the original post is published, Zernio will create new scheduled copies at a weekly/monthly interval until an expiration condition is met.
Configure with
recycling:•
gap (int)•
gapFreq: week | month•
startDate (date-time, optional)•
expireCount (int, optional)•
expireDate (date-time, optional)•
contentVariations (string[], optional)Webhooks: a new event
post.recycled is available in POST/PUT /v1/webhooks/settings and filterable in GET /v1/webhooks/logs.Also:
GET /v1/tools/youtube/transcript may now return 503, and DELETE /v1/inbox/comments/{postId} may now return 400 when the platform rejects the delete.New Feature
New endpoint
Query params:
•
•
•
Response includes
GET /v1/analytics/post-timeline returns a daily analytics timeline for a specific post (per platform for multi-platform Zernio posts), showing how metrics evolve day-by-day since publishing. Requires the Analytics add-on.Query params:
•
postId (required) — accepts ExternalPost ID, platformPostId, or Zernio Post ID•
fromDate (optional, ISO 8601; default 90 days ago)•
toDate (optional, ISO 8601; default now)Response includes
timeline[] rows with date, platform, platformPostId, and metrics like impressions, reach, likes, comments, shares, saves, clicks, views.New Feature
New validation endpoints are available under
Validate weighted character counts per platform with
Dry-run the full post validation pipeline (same body as
Validate a public media URL and compare against per-platform size limits with
Check subreddit existence/info with
/v1/tools/validate to preflight-check content before publishing.Validate weighted character counts per platform with
POST /v1/tools/validate/post-length (body: { text }) and get per-platform { count, limit, valid }.Dry-run the full post validation pipeline (same body as
POST /v1/posts) with POST /v1/tools/validate/post. Target platforms via platforms[].platform: twitter, instagram, tiktok, youtube, facebook, linkedin, bluesky, threads, reddit, pinterest, telegram, snapchat, googlebusiness. Returns valid plus errors[] and/or warnings[].Validate a public media URL and compare against per-platform size limits with
POST /v1/tools/validate/media (body: { url }). Returns contentType, size, type (image/video/unknown), and platformLimits when available.Check subreddit existence/info with
GET /v1/tools/validate/subreddit using query name.New Feature
New Analytics endpoints are available for aggregated reporting and scheduling optimization (requires the Analytics add-on).
Daily aggregated metrics:
• Filters:
• Returns:
Best times to post:
• Filters:
• Returns:
Content performance decay:
• Filters:
• Returns:
Posting frequency vs engagement:
• Filters:
• Returns:
Daily aggregated metrics:
GET /v1/analytics/daily-metrics• Filters:
platform, profileId, fromDate, toDate• Returns:
dailyData + platformBreakdown with summed metrics (impressions, reach, likes, comments, shares, saves, clicks, views)Best times to post:
GET /v1/analytics/best-time• Filters:
platform, profileId• Returns:
slots grouped by dayofweek (0=Monday..6=Sunday) and hour (UTC 0-23) with avg_engagementContent performance decay:
GET /v1/analytics/content-decay• Filters:
platform, profileId• Returns:
buckets with bucketlabel and avgpctoffinalPosting frequency vs engagement:
GET /v1/analytics/posting-frequency• Filters:
platform, profileId• Returns:
frequency rows with postsperweek, avgengagementrate, weeks_countImprovement
LinkedIn document (PDF/carousel) posts now let you control the displayed document title via
LinkedIn requires a title for document posts; if omitted, Zernio will fall back to the media item title, then the filename.
Use:
•
•
platformSpecificData.linkedin.documentTitle.LinkedIn requires a title for document posts; if omitted, Zernio will fall back to the media item title, then the filename.
Use:
•
platformSpecificData.linkedin.documentTitle•
media[].title (used as the LinkedIn document title if documentTitle is not set; otherwise falls back to filename)New Feature
API keys can now be created with restricted access using
This lets you issue keys limited to specific profiles and/or make keys read-only for safer analytics/integration use.
New request fields:
•
•
•
Key responses now include
scope, profileIds, and permission on POST /v1/api-keys.This lets you issue keys limited to specific profiles and/or make keys read-only for safer analytics/integration use.
New request fields:
•
scope: full | profiles (default full)•
profileIds: required when scope=profiles•
permission: read-write | read (default read-write)Key responses now include
scope, profileIds (populated profile objects when scoped), and permission (e.g., in GET /v1/api-keys and create responses).New Feature
Facebook publishing now supports Reels via
Set
New field for reels:
•
Note:
FacebookPlatformData.contentType.Set
contentType to story or reel (omit for a feed post). Reels require a single vertical video (9:16, 3–60s).New field for reels:
•
title — Reel title (only when contentType=reel)Note:
firstComment applies to feed posts only (not stories or reels).New Feature
New endpoint:
You can now delete a previously published post from a specific social platform while keeping the Zernio post record (platform status becomes
Request body:
Notes: Instagram/TikTok/Snapchat deletion isn’t supported. Telegram deletions may fail for messages older than 48h. YouTube deletion permanently removes the video.
POST /v1/posts/{postId}/unpublish.You can now delete a previously published post from a specific social platform while keeping the Zernio post record (platform status becomes
cancelled).Request body:
platform = threads | facebook | twitter | linkedin | youtube | pinterest | reddit | bluesky | googlebusiness | telegram.Notes: Instagram/TikTok/Snapchat deletion isn’t supported. Telegram deletions may fail for messages older than 48h. YouTube deletion permanently removes the video.
Improvement
Instagram photo tagging now supports tagging specific slides in carousel posts via
This lets you place tags on any image within a carousel. Tags without
Use:
•
Notes:
• Not supported for stories or videos; tags targeting video items (or out-of-range indices) are ignored.
mediaIndex in platformSpecificData.userTags.This lets you place tags on any image within a carousel. Tags without
mediaIndex still default to the first image (index 0).Use:
•
userTags[].mediaIndex (integer, 0-based)Notes:
• Not supported for stories or videos; tags targeting video items (or out-of-range indices) are ignored.
New Feature
POST
You can send a private reply to a Facebook post comment, which opens a Messenger conversation with the commenter (text-only; still limited to 1 private reply per comment within 7 days).
Use
/v1/inbox/comments/{postId}/{commentId}/private-reply now supports Facebook in addition to Instagram.You can send a private reply to a Facebook post comment, which opens a Messenger conversation with the commenter (text-only; still limited to 1 private reply per comment within 7 days).
Use
accountId (Instagram or Facebook) and message in the JSON body. The response platform is now instagram or facebook.Improvement
Google Business Profile posts now support explicitly setting the content language via
If omitted, the language is auto-detected from the post text; set it when auto-detection may be unreliable (short posts, mixed languages, transliteration).
New field:
languageCode in GoogleBusinessPlatformData.If omitted, the language is auto-detected from the post text; set it when auto-detection may be unreliable (short posts, mixed languages, transliteration).
New field:
languageCode (BCP 47, e.g. en, de, es, fr).New Feature
Reddit posting now supports post flairs via
Some subreddits require a flair; you can now fetch available flairs and set the one you want on the post.
New endpoint:
Required query:
New field:
If omitted, the API will attempt to use the first available flair as a fallback.
flairId in platformSpecificData.Some subreddits require a flair; you can now fetch available flairs and set the one you want on the post.
New endpoint:
GET /v1/accounts/{accountId}/reddit-flairsRequired query:
subreddit (without r/)New field:
platformSpecificData.reddit.flairId (string)If omitted, the API will attempt to use the first available flair as a fallback.
Improvement
Instagram conversations now include optional participant profile context via
This lets you show follower/verification info (and follower count) alongside DMs, and use it in routing/automation.
Added to:
•
•
Fields:
•
Webhook update:
•
instagramProfile.This lets you show follower/verification info (and follower count) alongside DMs, and use it in routing/automation.
Added to:
•
GET /v1/inbox/conversations → data[].instagramProfile•
GET /v1/inbox/conversations/{conversationId} → data.instagramProfileFields:
•
isFollower, isFollowing, followerCount, isVerified, fetchedAtWebhook update:
•
WebhookPayloadMessage.message.sender.instagramProfile (Instagram only) with isFollower, isFollowing, followerCount, isVerified.New Feature
Interactive messaging support for the Inbox API.
• Quick replies (
• Buttons (
• Carousels (
• Telegram keyboards (
• Message tags (
• Reply to (
Incoming messages now include
Also added:
POST /v1/inbox/conversations/{conversationId}/messages now supports:• Quick replies (
quickReplies) - Up to 13 quick reply buttons (Instagram, Facebook, Telegram)• Buttons (
buttons) - Up to 3 action buttons: URL, postback, or phone (Instagram, Facebook, Telegram)• Carousels (
template) - Generic template with up to 10 elements (Instagram, Facebook)• Telegram keyboards (
replyMarkup) - Native inline or reply keyboards• Message tags (
messageTag) - Send outside the 24h window: HUMANAGENT (Instagram), CONFIRMEDEVENTUPDATE, POSTPURCHASEUPDATE, ACCOUNTUPDATE, HUMAN_AGENT (Facebook)• Reply to (
replyTo) - Reply to a specific message (Telegram)Incoming messages now include
metadata with quickReplyPayload, postbackPayload, postbackTitle, and callbackData to identify interactive message taps.Also added:
PATCH /v1/inbox/conversations/{conversationId}/messages/{messageId} to edit sent Telegram messages (text and inline keyboard).New Feature
New Account Settings endpoints for managing platform-specific messaging features.
Facebook Persistent Menu (
GET/PUT/DELETE to manage the persistent menu shown in Facebook Messenger conversations. Max 3 top-level items, max 5 nested items.
Instagram Ice Breakers (
GET/PUT/DELETE to manage ice breaker prompts shown when users start a new Instagram DM. Max 4 ice breakers, question max 80 chars.
Telegram Bot Commands (
GET/PUT/DELETE to manage the bot command menu shown in Telegram chats.
Facebook Persistent Menu (
/v1/accounts/{accountId}/messenger-menu)GET/PUT/DELETE to manage the persistent menu shown in Facebook Messenger conversations. Max 3 top-level items, max 5 nested items.
Instagram Ice Breakers (
/v1/accounts/{accountId}/instagram-ice-breakers)GET/PUT/DELETE to manage ice breaker prompts shown when users start a new Instagram DM. Max 4 ice breakers, question max 80 chars.
Telegram Bot Commands (
/v1/accounts/{accountId}/telegram-commands)GET/PUT/DELETE to manage the bot command menu shown in Telegram chats.
Minor
Added 2 new endpoints:
GET /v1/posts/logs - Get publishing logsGET /v1/connections/logs - Get connection logsNew Feature
New Google Business Profile endpoints are now available for managing your GMB listings programmatically.
Location Details (
GET/PUT to read and update business hours, special hours, description, phone numbers, and website. Use
Media (
GET/POST/DELETE to manage photos. Upload via public URL with categories:
Attributes (
GET/PUT to manage amenities and services like
Place Actions (
GET/POST/DELETE to manage booking and ordering buttons. Types include:
Location Details (
/v1/accounts/{accountId}/gmb-location-details)GET/PUT to read and update business hours, special hours, description, phone numbers, and website. Use
readMask and updateMask to specify fields.Media (
/v1/accounts/{accountId}/gmb-media)GET/POST/DELETE to manage photos. Upload via public URL with categories:
COVER, PROFILE, LOGO, EXTERIOR, INTERIOR, FOODANDDRINK, MENU, PRODUCT, TEAMS, ADDITIONALAttributes (
/v1/accounts/{accountId}/gmb-attributes)GET/PUT to manage amenities and services like
hasdelivery, hastakeout, hasoutdoorseating, has_wifi, payment types, etc.Place Actions (
/v1/accounts/{accountId}/gmb-place-actions)GET/POST/DELETE to manage booking and ordering buttons. Types include:
APPOINTMENT, DININGRESERVATION, FOODORDERING, FOODDELIVERY, FOODTAKEOUT, SHOP_ONLINENew Feature
New endpoints for Google Business Profile food menus:
Fetch the full menu structure for a connected GBP location.
Update food menus with sections, items, pricing, dietary info, and allergens.
Menu items support:
•
•
•
•
Only available for GBP locations with food menu support (restaurants, cafes, etc.).
Also:
GET /v1/accounts/{accountId}/gmb-food-menusFetch the full menu structure for a connected GBP location.
PUT /v1/accounts/{accountId}/gmb-food-menusUpdate food menus with sections, items, pricing, dietary info, and allergens.
Menu items support:
•
price with currency code•
dietaryRestriction - VEGETARIAN, VEGAN, GLUTEN_FREE, etc.•
allergen - DAIRY, GLUTEN, SHELLFISH, etc.•
spiciness, servesNumPeople, preparationMethodsOnly available for GBP locations with food menu support (restaurants, cafes, etc.).
Also:
PostAnalytics now includes saves for tracking bookmarks on Instagram and Pinterest.New Feature
The Inbox API now supports Twitter/X for conversations, comments, and comment interactions.
Conversations (
Filter by
Comments (
Twitter/X posts with replies are now included. Also added Threads support for comments listing.
Like/Unlike comments:
Conversations (
GET /v1/inbox/conversations):Filter by
platform=twitter to fetch Twitter/X DMs.Comments (
GET /v1/inbox/comments):Twitter/X posts with replies are now included. Also added Threads support for comments listing.
Like/Unlike comments:
POST and DELETE /v1/inbox/comments/{postId}/{commentId}/like now work with Twitter/X replies.New Feature
The
Values:
•
•
•
This makes it easier to separate analytics for posts you scheduled through Zernio from posts that were published directly on the platform.
GET /v1/analytics endpoint now supports a source query parameter to filter posts by origin.Values:
•
late - only posts scheduled/published via Zernio API•
external - only posts synced from the platform (not posted via Late)•
all - all posts (default)This makes it easier to separate analytics for posts you scheduled through Zernio from posts that were published directly on the platform.
New Feature
The
Three new fields are available:
•
•
•
•
•
•
•
•
•
•
•
These fields are populated when a platform's
PlatformTarget schema now includes detailed error information when posts fail to publish.Three new fields are available:
errorMessage - Human-readable explanation of why the publish failederrorCategory - Programmatic category for handling:•
auth_expired - token expired, reconnect needed•
user_content - content doesn't meet platform requirements•
user_abuse - rate limits or spam detection•
account_issue - account configuration problems•
platform_rejected - policy violation•
platform_error - platform-side issues•
system_error - Zernio infrastructure issues•
unknown - unclassifiederrorSource - Who caused the error:•
user - user action required•
platform - platform-side issue•
system - Zernio system issueThese fields are populated when a platform's
status is failed. Posts with mixed results now return status: "partial" at the post level.New Feature
YouTube uploads now support video categories via the new
You can now specify which category your video belongs to. Defaults to
Common category IDs:
•
•
•
•
•
•
categoryId field in platformSpecificData.You can now specify which category your video belongs to. Defaults to
22 (People & Blogs) if not set.Common category IDs:
•
1 - Film & Animation•
10 - Music•
20 - Gaming•
24 - Entertainment•
27 - Education•
28 - Science & TechnologyNew Feature
Multi-page/multi-location posting is now supported for Facebook, LinkedIn, and Google Business.
You can now post to multiple pages, organizations, or locations from a single account connection by using the same
• Facebook:
• LinkedIn:
• Google Business:
List available targets via:
•
•
•
Also:
You can now post to multiple pages, organizations, or locations from a single account connection by using the same
accountId multiple times with different targets in platformSpecificData:• Facebook:
pageId - post to multiple Pages• LinkedIn:
organizationUrn - post to multiple organizations• Google Business:
locationId - post to multiple locationsList available targets via:
•
GET /v1/accounts/{id}/facebook-page•
GET /v1/accounts/{id}/linkedin-organizations•
GET /v1/accounts/{id}/gmb-locationsAlso:
content is now optional when media is attached or all platforms have customContent set.New Feature
New endpoint:
Send a private DM to the author of a comment on your Instagram post. Useful for handling customer inquiries or sensitive matters privately.
Required body:
•
•
Limitations:
• Instagram only (not available on other platforms)
• One private reply per comment
• Must be sent within 7 days of the comment
• Only works for comments on posts you own
• Requires the Inbox addon
POST /v1/inbox/comments/{postId}/{commentId}/private-replySend a private DM to the author of a comment on your Instagram post. Useful for handling customer inquiries or sensitive matters privately.
Required body:
•
accountId - Instagram social account ID•
message - text to send as DMLimitations:
• Instagram only (not available on other platforms)
• One private reply per comment
• Must be sent within 7 days of the comment
• Only works for comments on posts you own
• Requires the Inbox addon
New Feature
New endpoints for managing Facebook Pages and Google Business Profile locations.
List all Facebook pages the connected account can access, see which one is currently selected.
List all Google Business Profile locations available to the account.
Change the selected GBP location by passing
Useful if you manage multiple pages/locations and need to switch between them programmatically.
GET /v1/accounts/{accountId}/facebook-pageList all Facebook pages the connected account can access, see which one is currently selected.
GET /v1/accounts/{accountId}/gmb-locationsList all Google Business Profile locations available to the account.
PUT /v1/accounts/{accountId}/gmb-locationsChange the selected GBP location by passing
selectedLocationId in the request body.Useful if you manage multiple pages/locations and need to switch between them programmatically.
Improvement
POST /v1/posts now returns
If you post identical content to the same account within 24 hours, you'll get:
Additionally,
• Velocity limit: 15 posts/hour per account
• Account cooldown: Escalating delays (10min → 24h) after repeated errors
• Daily post limits: Platform-specific (X: 20, Pinterest: 25, Instagram/Facebook: 100, Threads: 250, others: 50)
New headers on 429:
These changes also apply to
409 Conflict when duplicate content is detected.If you post identical content to the same account within 24 hours, you'll get:
{
"error": "This exact content was already posted...",
"details": {
"accountId": "...",
"platform": "...",
"existingPostId": "..."
}
}Additionally,
429 responses now include detailed context about which limit was hit:• Velocity limit: 15 posts/hour per account
• Account cooldown: Escalating delays (10min → 24h) after repeated errors
• Daily post limits: Platform-specific (X: 20, Pinterest: 25, Instagram/Facebook: 100, Threads: 250, others: 50)
New headers on 429:
Retry-After, X-RateLimit-Limit, X-RateLimit-RemainingThese changes also apply to
POST /v1/posts/bulk-upload and POST /v1/posts/{postId}/retry.New Feature
YouTube uploads now support
This COPPA compliance field declares whether your video is child-directed content. Defaults to
Set to
Important: YouTube requires this to be explicitly set. If omitted, the video defaults to not made for kids, but may be blocked from views until configured in YouTube Studio.
madeForKids in platformSpecificData.youtube.This COPPA compliance field declares whether your video is child-directed content. Defaults to
false.Set to
true if your video is made for kids. Note: kid-directed videos have restricted features (no comments, no notifications, limited ad targeting).Important: YouTube requires this to be explicitly set. If omitted, the video defaults to not made for kids, but may be blocked from views until configured in YouTube Studio.
Improvement
Analytics responses now include
When an external post originated from a Late-scheduled post, the response now includes the original Zernio Post ID directly. This makes it easier to correlate analytics data with posts created via
The field appears in both single post queries and paginated list responses. It's
latePostId field.When an external post originated from a Late-scheduled post, the response now includes the original Zernio Post ID directly. This makes it easier to correlate analytics data with posts created via
POST /v1/posts.The field appears in both single post queries and paginated list responses. It's
null for posts that weren't scheduled through Zernio.Breaking Change
LinkedIn headless OAuth flow updated
LinkedIn headless mode now uses a token-based approach to retrieve OAuth data, preventing URITOOLONG errors for users with many organizations.
What changed:
After OAuth redirect, you now receive
Call the new endpoint to fetch the data:
Returns:
Important:
• One-time use: data is deleted after fetching
• Data expires after 10 minutes if not fetched
• No authentication required, just the token
Other platforms (Facebook, Pinterest, Google Business, Snapchat) are unchanged.
LinkedIn headless mode now uses a token-based approach to retrieve OAuth data, preventing URITOOLONG errors for users with many organizations.
What changed:
After OAuth redirect, you now receive
pendingDataToken instead of tempToken, userProfile, and organizations in the URL.Call the new endpoint to fetch the data:
GET /v1/connect/pending-data?token=PENDINGDATATOKENReturns:
tempToken, refreshToken, expiresIn, userProfile, organizations, selectionTypeImportant:
• One-time use: data is deleted after fetching
• Data expires after 10 minutes if not fetched
• No authentication required, just the token
Other platforms (Facebook, Pinterest, Google Business, Snapchat) are unchanged.
New Feature
Instagram Reels now support thumbnail offset selection via
Specify a millisecond offset from the start of the video to use as the Reel cover image. Defaults to 0 (first frame).
If you provide a custom thumbnail URL via
thumbOffset in platformSpecificData.Specify a millisecond offset from the start of the video to use as the Reel cover image. Defaults to 0 (first frame).
thumbOffset: integer, minimum 0 (milliseconds)If you provide a custom thumbnail URL via
instagramThumbnail in mediaItems, it takes priority and this offset is ignored.New Feature
New webhook event:
You can now subscribe to notifications when a social account is connected to a profile. The webhook payload includes
Add it to your
account.connectedYou can now subscribe to notifications when a social account is connected to a profile. The webhook payload includes
accountId, profileId, platform, username, and displayName.Add it to your
events array when creating or updating webhooks.New Feature
YouTube daily views breakdown is now available via
GET /v1/analytics/youtube/daily-views. This endpoint returns historical daily view counts for a specific YouTube video, including views, watch time, and subscriber changes. Required parameters include videoId and accountId, with optional date range parameters startDate and endDate.Improvement
Zernio now automatically compresses media that exceeds platform limits during publishing, simplifying the upload process.
Image compression thresholds are set for platforms like
Video compression thresholds include
Image compression thresholds are set for platforms like
Twitter/X: >5 MB, Instagram: >8 MB, Facebook: >10 MB, and more. Video compression thresholds include
Twitter/X: >512 MB, Instagram Stories: >100 MB, Facebook: >4 GB, among others.Breaking Change
The endpoint
POST /v1/profiles/{profileId}/clone-connection has been removed. This endpoint was used to clone an existing connection to a profile, allowing users to manage multiple brands with the same underlying social media account.Improvement
YouTube now supports AI-generated content disclosure via
Set
containsSyntheticMedia in YouTubePlatformData.Set
containsSyntheticMedia to true if your video contains AI-generated or synthetic content that could be mistaken for real people, places, or events. YouTube may add a label to videos when this is set.Improvement
Instagram now supports custom audio names for Reels via
You can set a custom name for the original audio, replacing the default "Original Audio" label. This can only be set once during creation or later from the Instagram audio page in the app.
audioName in platformSpecificData.You can set a custom name for the original audio, replacing the default "Original Audio" label. This can only be set once during creation or later from the Instagram audio page in the app.
Improvement
InstagramPlatformData Schema Update
The
Here are the details of the new
-
-
- Possible values:
- This field determines how a trial reel transitions to a regular reel:
-
-
The rest of the schema remains unchanged, including the parameters
This update enhances your ability to manage Reels effectively, allowing for strategic sharing and performance-based visibility adjustments. Keep this in mind as you plan your content strategy.
The
InstagramPlatformData schema has been updated to include a new parameter: trialParams. This parameter allows for configuration of trial Reels, which are initially shared only with non-followers. Here are the details of the new
trialParams field:-
trialParams: object (optional)-
graduationStrategy: string (required)- Possible values:
MANUAL, SS_PERFORMANCE- This field determines how a trial reel transitions to a regular reel:
-
MANUAL: Requires manual graduation via the Instagram app.-
SS_PERFORMANCE: Automatically graduates based on performance metrics with non-followers.The rest of the schema remains unchanged, including the parameters
contentType, shareToFeed, collaborators, firstComment, and userTags. This update enhances your ability to manage Reels effectively, allowing for strategic sharing and performance-based visibility adjustments. Keep this in mind as you plan your content strategy.
New Feature
New Endpoints Available:
1.
- This endpoint allows you to retrieve publishing logs for all posts. You can filter logs by status (
-
-
-
-
-
-
- The response includes an array of logs and pagination details.
2.
- Use this endpoint to retrieve detailed information about a specific log entry, including full request and response bodies for debugging purposes.
-
- The response contains the log entry details, including the full context of the publishing attempt.
3.
- This endpoint retrieves all publishing logs for a specific post, showing the complete history of publishing attempts across all platforms.
-
-
- The response includes an array of logs specific to the post and the count of logs returned.
1.
GET /v1/logs- This endpoint allows you to retrieve publishing logs for all posts. You can filter logs by status (
status), platform (platform), and action (action). The logs include detailed information about each publishing attempt, such as API requests, responses, and timing data. -
status (string, optional): Filter by log status (options: success, failed, pending, skipped, all).-
platform (string, optional): Filter by platform (options include tiktok, instagram, facebook, etc.).-
action (string, optional): Filter by action type (options: publish, retry, media_upload, etc.).-
days (integer, optional): Number of days to look back (max 7, default 7).-
limit (integer, optional): Maximum number of logs to return (max 100, default 50).-
skip (integer, optional): Number of logs to skip for pagination (default 0).- The response includes an array of logs and pagination details.
2.
GET /v1/logs/{logId}- Use this endpoint to retrieve detailed information about a specific log entry, including full request and response bodies for debugging purposes.
-
logId (string, required): The ID of the log entry you want to retrieve.- The response contains the log entry details, including the full context of the publishing attempt.
3.
GET /v1/posts/{postId}/logs- This endpoint retrieves all publishing logs for a specific post, showing the complete history of publishing attempts across all platforms.
-
postId (string, required): The ID of the post for which you want to retrieve logs.-
limit (integer, optional): Maximum number of logs to return (max 100, default 50).- The response includes an array of logs specific to the post and the count of logs returned.
New Feature
New Endpoints for Pinterest Integration
We have added two new endpoints to enhance your integration with Pinterest in headless mode:
1.
- Summary: List Pinterest Boards after OAuth (Headless Mode)
- Description: This endpoint retrieves a list of Pinterest boards available for selection after initiating OAuth via
- Parameters:
-
-
-
- Responses:
-
-
-
-
-
2.
- Summary: Select a Pinterest Board to complete the connection (Headless Mode)
- Description: Use this endpoint to save the selected board and complete the Pinterest account connection after OAuth.
- Request Body: Must include the following fields:
-
-
-
-
-
-
-
-
- Responses:
-
-
-
-
-
We have added two new endpoints to enhance your integration with Pinterest in headless mode:
1.
GET /v1/connect/pinterest/select-board- Summary: List Pinterest Boards after OAuth (Headless Mode)
- Description: This endpoint retrieves a list of Pinterest boards available for selection after initiating OAuth via
/v1/connect/pinterest with headless=true. It allows you to build your own fully-branded board selector instead of using Zernio's hosted UI.- Parameters:
-
X-Connect-Token (header, required): Short-lived connect token from the OAuth redirect.-
profileId (query, required): Your Zernio profile ID.-
tempToken (query, required): Temporary Pinterest access token from the OAuth callback redirect.- Responses:
-
200: Returns a list of Pinterest boards available for connection, including each board's ID, name, description, and privacy setting.-
400: Missing required parameters.-
401: Unauthorized access.-
403: No access to profile.-
500: Failed to fetch boards.2.
POST /v1/connect/pinterest/select-board- Summary: Select a Pinterest Board to complete the connection (Headless Mode)
- Description: Use this endpoint to save the selected board and complete the Pinterest account connection after OAuth.
- Request Body: Must include the following fields:
-
profileId (string, required): Your Zernio profile ID.-
boardId (string, required): The Pinterest Board ID selected by the user.-
boardName (string, optional): The board name for display purposes.-
tempToken (string, required): Temporary Pinterest access token from OAuth.-
userProfile (object, optional): User profile data from OAuth redirect.-
refreshToken (string, optional): Pinterest refresh token if available.-
expiresIn (integer, optional): Token expiration time in seconds.-
redirect_url (string, optional): Custom redirect URL after connection completes.- Responses:
-
200: Pinterest Board connected successfully, returns a message and account details.-
400: Missing required fields.-
401: Unauthorized access.-
403: No access to profile or profile limit exceeded.-
500: Failed to save Pinterest connection.Improvement
GET /v1/accounts/{accountId}/linkedin-mentions
This endpoint resolves a LinkedIn profile URL (for a person) or a company page URL (for an organization) to a URN that can be used to @mention them in posts.
Parameters:
-
-
- Person:
- Organization:
-
Response:
On success (HTTP 200), the response contains:
-
-
-
-
-
-
This change allows developers to mention organizations without needing to be an admin of a LinkedIn organization, which simplifies the process of tagging companies in posts. Person mentions still require admin access for the organization but now support a broader range of input formats.
This endpoint resolves a LinkedIn profile URL (for a person) or a company page URL (for an organization) to a URN that can be used to @mention them in posts.
Parameters:
-
accountId (path, required): The LinkedIn account ID.-
url (query, required): LinkedIn profile URL, company URL, or vanity name. It supports:- Person:
miquelpalet, linkedin.com/in/miquelpalet- Organization:
company/microsoft, linkedin.com/company/microsoft-
displayName (query, optional): The exact display name as shown on LinkedIn. This is required for clickable person mentions. If not provided, the name is derived from the vanity URL, which may not match exactly.Response:
On success (HTTP 200), the response contains:
-
urn: The LinkedIn URN (either for a person or organization).-
type: The type of entity, which can be either person or organization.-
displayName: The display name (provided, from API, or derived from vanity URL).-
mentionFormat: Ready-to-use mention format for post content.-
vanityName: The vanity name/slug (only for organization mentions).-
warning: A warning about clickable mentions (only present for person mentions if displayName was not provided).This change allows developers to mention organizations without needing to be an admin of a LinkedIn organization, which simplifies the process of tagging companies in posts. Person mentions still require admin access for the organization but now support a broader range of input formats.
Improvement
GET /v1/profiles
This endpoint lists profiles visible to the authenticated user. It now includes a new optional query parameter
Response contains:
-
-
-
-
-
-
-
GET /v1/accounts
This endpoint lists connected social accounts. It now also includes the
Response contains:
-
-
-
-
-
-
-
-
-
This endpoint lists profiles visible to the authenticated user. It now includes a new optional query parameter
includeOverLimit (type: boolean, default: false). When set to true, it includes profiles that exceed the user's plan limit, which will have isOverLimit: true in the response. This is useful for managing or deleting profiles after a plan downgrade. The profiles are sorted by creation date (oldest first).Response contains:
-
profiles: an array of profile objects, each containing:-
id: string-
name: string-
color: string-
isDefault: boolean-
isOverLimit: boolean (only present when includeOverLimit=true)-
createdAt: string (date-time)GET /v1/accounts
This endpoint lists connected social accounts. It now also includes the
includeOverLimit parameter (type: boolean, default: false). When true, it includes accounts from profiles that exceed the user's plan limit, allowing users to disconnect accounts from over-limit profiles for deletion.Response contains:
-
accounts: an array of account objects, each containing:-
id: string-
platform: string-
profileId: object containing profile details-
username: string-
displayName: string-
profileUrl: string-
isActive: boolean-
hasAnalyticsAccess: boolean (indicates if the user has analytics add-on access)Improvement
The
-
-
-
These fields help you understand why an account was disconnected and quickly look up related data.
account.disconnected webhook payload now includes additional fields for better context:-
accountId - The account's unique identifier (same as used in /v1/accounts/{accountId})-
profileId - The profile's unique identifier this account belongs to-
disconnectionType - Either intentional (user disconnected manually) or unintentional (token expired or was revoked)These fields help you understand why an account was disconnected and quickly look up related data.