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
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.