New billing snapshot endpoint:
It returns the billing “statement” view (plan, current cycle, balance/credits, spend caps, and payment/access status). Use this for billing state; use
Key response blocks:
•
•
•
•
•
Also:
• Default (no metering params): same snapshot as before
• Metering mode (billed spend by product) when passing any of:
Metering params:
•
•
•
Stripe accounts calling metering mode receive
View documentation
GET /v1/billing.It returns the billing “statement” view (plan, current cycle, balance/credits, spend caps, and payment/access status). Use this for billing state; use
GET /v1/usage for usage/metering.Key response blocks:
•
plan (includes isUsageBased)•
period (start/end may be null on Stripe)•
balance (null for Stripe; populated for Metronome)•
caps (e.g. xSpendUsedCents, xSpendLimitCents)•
status (e.g. hasAccess, suspended, openInvoiceUrl, declineReason)Also:
GET /v1/usage is now dual-mode.• Default (no metering params): same snapshot as before
• Metering mode (billed spend by product) when passing any of:
range, granularity, from, toMetering params:
•
range: cycle | prev-cycle | 7d | 14d | 30d | 3mo | 12mo | custom•
granularity: day | month | total•
from/to required when range=customStripe accounts calling metering mode receive
{ "supported": false }.View documentation
❤1
Webhooks now support additional event subscriptions for conversations, calls, leads, and WhatsApp.
You can subscribe to these new
•
•
•
•
SMS carrier registrations (10DLC) now accept
For rejected registrations,
View documentation
You can subscribe to these new
events via POST /v1/webhooks/settings or PUT /v1/webhooks/settings:•
conversation.started•
call.received, call.ended, call.failed, call.permission_request•
lead.received•
whatsapp.automatic_eventSMS carrier registrations (10DLC) now accept
campaign.subUsecases on POST /v1/sms/registrations (2–5 values): 2FA, ACCOUNT_NOTIFICATION, CUSTOMER_CARE, DELIVERY_NOTIFICATION, FRAUD_ALERT, HIGHER_EDUCATION, MARKETING, POLLING_VOTING, PUBLIC_SERVICE_ANNOUNCEMENT, SECURITY_ALERT.For rejected registrations,
GET /v1/sms/registrations/{id} may now include campaignContent (messageFlow, sample1, sample2), and POST /v1/sms/registrations/{id}/appeal can include corrected messageFlow/sample1/sample2 along with appealReason.View documentation
❤2
GET /v1/usage now includes estimated tax via a new tax field on UsageMetering.This lets you show an estimated tax amount (computed with Stripe Tax) on top of the window’s net spend (
totals.total). tax is null when no billing address is on file, the total is ≤ 0, or the estimate fails.New fields:
•
tax.taxUsd — estimated tax in USD (added on top of totals.total)•
tax.ratePercent — combined rate percentage (nullable)•
tax.jurisdictionLabel — human label like “ES VAT” (nullable)•
tax.reverseCharge — true for EU/UK B2B reverse charge (0 tax added)View documentation
❤2
POST
This lets you restrict CTWA ad delivery to specific Meta surfaces/devices instead of using automatic placements (Meta may still enforce eligibility/co-selection rules and return actionable errors).
Use
•
•
•
View documentation
/v1/ads/ctwa now supports manual ad placements via placements.This lets you restrict CTWA ad delivery to specific Meta surfaces/devices instead of using automatic placements (Meta may still enforce eligibility/co-selection rules and return actionable errors).
Use
placements with:•
publisherPlatforms: facebook | instagram | threads | messenger | audience_network•
facebookPositions, instagramPositions, messengerPositions, audienceNetworkPositions, threadsPositions, whatsappPositions•
devicePlatforms: mobile | desktopView documentation
❤2
Meta placements now support delivering ads on WhatsApp by allowing
This lets you explicitly include WhatsApp inventory when using manual placements (instead of relying on automatic placements).
Set
•
Applies to:
•
•
View documentation
whatsapp in placements.publisherPlatforms.This lets you explicitly include WhatsApp inventory when using manual placements (instead of relying on automatic placements).
Set
placements.publisherPlatforms to include:•
whatsapp (alongside facebook, instagram, threads, messenger, audience_network)Applies to:
•
POST /v1/ads/create•
POST /v1/ads/ctwaView documentation
❤4
GET /v1/inbox/conversations/search now searches by contact identity (participant name/username/phone) in addition to message text, returning matching conversations once (message matches included when present).Contact-identity matches are case-insensitive substrings; they return
matchCount=0 and matches=[]. Note: identity matching is not applied when direction is set (incoming | outgoing).Also updated:
• Searchable platforms now include Twitter/X and Reddit; Bluesky is live-fetched and appears in
meta.accountsSkipped• Response adds
conversation.lastMessage (most recent message preview)View documentation
GET
This lets you filter out ad accounts that can’t currently create/run ads and show a user-friendly reason in your UI.
New fields in
•
•
On non-Meta platforms these fields are absent (treat
View documentation
/v1/ads/accounts now returns Meta ad account usability flags: selectable and unusableReason.This lets you filter out ad accounts that can’t currently create/run ads and show a user-friendly reason in your UI.
New fields in
accounts[] (Meta only):•
selectable (boolean) — whether the account can create/run ads now•
unusableReason (string|null) — reason when selectable is false; null when selectableOn non-Meta platforms these fields are absent (treat
selectable as true).View documentation
❤2
WhatsApp template sends via
This lets you use a single approved template with an image/video/document header while sending a different asset for each recipient (e.g. a unique invoice PDF), instead of always sending the template’s approved sample asset.
Set
•
• Provide exactly one of
• Optional:
View documentation
POST /v1/inbox/conversations now support overriding a media-header template asset per message using headerMedia.This lets you use a single approved template with an image/video/document header while sending a different asset for each recipient (e.g. a unique invoice PDF), instead of always sending the template’s approved sample asset.
Set
headerMedia (JSON body only):•
type: image | video | document (must match the template header type)• Provide exactly one of
link (public URL) or id (Meta media id)• Optional:
filename (document only)View documentation
❤1
conversation.started webhooks now include SMS conversations via conversation.platform.This lets you receive “new conversation started” events for SMS in the same platform-agnostic subscription.
New enum value:
•
conversation.platform: sms (in addition to existing platforms)View documentation
❤2
New endpoint:
This is ad-scoped only (does not affect the parent ad set/campaign), and is a thin wrapper around updating the ad
Set
Response includes
View documentation
PUT /v1/ads/{adId}/status to pause/resume a single ad.This is ad-scoped only (does not affect the parent ad set/campaign), and is a thin wrapper around updating the ad
status.Set
status to active or paused. {adId} accepts Zernio _id, Meta platformAdId, or the creative’s effective story/media IDs.Response includes
updated (1/0) and skipped (1/0); message is returned when the change is skipped (terminal status or already in target state).View documentation
❤1
POST
Use
New/updated request behavior:
•
•
•
View documentation
/v1/phone-numbers/port-in now supports portType to specify whether you’re porting the entire losing account or only some numbers.Use
portType to avoid ambiguity on ports where the losing account keeps some numbers.New/updated request behavior:
•
portType: full | partial (default: full)•
endUser.billingPhoneNumber: now documented as the number on the losing carrier’s bill; defaults to the ported number itself on single-number orders•
focDatetimeRequested: when omitted, defaults to ~1 week out (shifted off weekends)View documentation
❤2
Meta ads now support setting EU DSA (Article 26) defaults at the ad-account level, so EU-targeted calls can omit per-ad
Set defaults once via
Read current defaults via
View documentation
dsaBeneficiary/dsaPayor when defaults are configured.Set defaults once via
PATCH /v1/ads/accounts with accountId, adAccountId, defaultDsaBeneficiary, optional defaultDsaPayor (if omitted, payor defaults to beneficiary).Read current defaults via
GET /v1/ads/dsa-defaults (accountId, adAccountId), and fetch Meta-provided suggestions via GET /v1/ads/dsa-recommendations (accountId, adAccountId).POST /v1/ads/create, POST /v1/ads/boost, and POST /v1/ads/ctwa now treat dsaBeneficiary/dsaPayor as optional for EU targeting when the Meta ad account has defaults set (Meta accounts only; other platforms return 400).View documentation
❤1
GET
This lets you detect and display reviews with attached photos (Google Business only; other platforms return
New fields:
•
•
GET
Use this to validate budget inputs against account-level minimums (field may be absent if the connected token can’t read it).
New field:
•
View documentation
/v1/inbox/reviews now returns Google Business review photo info via hasPhotos and photoCount.This lets you detect and display reviews with attached photos (Google Business only; other platforms return
hasPhotos=false and photoCount=0).New fields:
•
hasPhotos•
photoCountGET
/v1/ads/accounts now includes Meta’s minimum daily budget via minimumDailyBudget.Use this to validate budget inputs against account-level minimums (field may be absent if the connected token can’t read it).
New field:
•
minimumDailyBudgetView documentation
❤1
Analytics responses now include media accessibility alt text via
Use this to display or audit the alt text set on each media item when available.
New field:
•
Included in:
•
•
View documentation
mediaItems[].altText.Use this to display or audit the alt text set on each media item when available.
New field:
•
mediaItems[].altText (string)Included in:
•
AnalyticsSinglePostResponse•
AnalyticsListResponseView documentation
❤1
Comment-to-DM automations now support message variations for random rotation of DM text and public comment replies.
This lets you provide multiple alternate texts so repeat triggers don’t always send identical messages.
New optional fields:
• Create/Update:
• Returned on list/detail/update responses:
Rotation behavior:
• DM text is picked at random from
• Public reply is picked at random from
Applies to:
View documentation
This lets you provide multiple alternate texts so repeat triggers don’t always send identical messages.
New optional fields:
• Create/Update:
dmMessageVariations (up to 5), commentReplyVariations (up to 5)• Returned on list/detail/update responses:
dmMessageVariations, commentReplyVariationsRotation behavior:
• DM text is picked at random from
[dmMessage, ...dmMessageVariations]• Public reply is picked at random from
[commentReply, ...commentReplyVariations]Applies to:
POST /v1/comment-automations, PATCH /v1/comment-automations/{automationId}, GET /v1/comment-automations, GET /v1/comment-automations/{automationId}.View documentation
❤2
LinkedIn ads now support campaign bidding & delivery controls via
This lets you set LinkedIn-specific options (manual bids, cost model, audience expansion, Audience Network, etc.) while keeping the platform inferred from
Use
•
•
•
•
•
View documentation
platformSpecificData on POST /v1/ads/create and POST /v1/ads/boost.This lets you set LinkedIn-specific options (manual bids, cost model, audience expansion, Audience Network, etc.) while keeping the platform inferred from
accountId (sending options for a different platform returns 400).Use
platformSpecificData (LinkedIn only):•
costType: CPM | CPC | CPV•
unitCost (manual bid; requires costType)•
optimizationTargetType (pass-through)•
creativeSelection: OPTIMIZED | ROUND_ROBIN•
audienceExpansionEnabled, offsiteDeliveryEnabled, connectedTelevisionOnlyView documentation
Sole-prop 10DLC registrations can now re-send the OTP via
Use this when the original code expired or never arrived. It only works while the registration is pending and awaiting OTP, and is rate-limited to 1 request/min.
Request:
Response:
Errors:
Port-in updates:
•
•
10DLC campaign submissions:
•
View documentation
POST /v1/sms/registrations/{id}/resend-otp.Use this when the original code expired or never arrived. It only works while the registration is pending and awaiting OTP, and is rate-limited to 1 request/min.
Request:
id (path)Response:
{ sent: boolean }Errors:
400 not awaiting OTP, 404 not found, 429 wait 1 minutePort-in updates:
•
POST /v1/phone-numbers/port-in: endUser.accountNumber is now required (and endUser.countryCode is restricted to US/CA)•
POST /v1/phone-numbers/port-in/check: response adds lineType (when known) to indicate if a transfer PIN is required at submit10DLC campaign submissions:
•
POST /v1/sms/registrations: campaign.optinMessage, campaign.optoutMessage, and campaign.helpMessage are now optional; when omitted, compliant templates are generated.View documentation
❤1👏1
POST
You can create LinkedIn-only creatives (beyond single image/video) by setting one of these mutually-exclusive options:
•
•
•
•
•
•
Notes:
• Carousel cards use
• Document ads use
• Spotlight ads use
• Follower ads use
Also clarified: on LinkedIn,
View documentation
/v1/ads/create now supports more LinkedIn ad formats via platformSpecificData.You can create LinkedIn-only creatives (beyond single image/video) by setting one of these mutually-exclusive options:
•
platformSpecificData.carousel (2–10 cards)•
platformSpecificData.document (PDF/PPT/DOC)•
platformSpecificData.spotlight (dynamic spotlight)•
platformSpecificData.follower (dynamic follower)•
platformSpecificData.textAd (right-rail text ad)•
platformSpecificData.event (promote an existing event)Notes:
• Carousel cards use
cards[].imageUrl and optionally cards[].headline / cards[].landingUrl (falls back to ad-level linkUrl).• Document ads use
document.url + document.title.• Spotlight ads use
spotlight.headline + spotlight.callToAction + spotlight.landingUrl.• Follower ads use
follower.callToAction enum: VISIT_ORGANIZATION_COMPANY_PAGE, VISIT_ORGANIZATION_LIFE_PAGE, VISIT_ORGANIZATION_JOBS_PAGE, VISIT_ORGANIZATION_CAREERS_PAGE.Also clarified: on LinkedIn,
imageUrl + linkUrl publishes an ARTICLE-content creative (with longHeadline as the description).View documentation
❤1👏1
POST /v1/ads/create now supports LinkedIn Jobs ads via a new goal
This lets you create Dynamic Jobs Ads that promote open roles (requires a Company Page with active job postings).
Use:
•
•
Also added for LinkedIn-only creatives on
•
View documentation
job_applicants.This lets you create Dynamic Jobs Ads that promote open roles (requires a Company Page with active job postings).
Use:
•
goal: job_applicants•
platformSpecificData.jobs with headline and buttonLabel (each takes exactly one of preApproved or custom)Also added for LinkedIn-only creatives on
platformSpecificData:•
conversation (Conversation Ads) with subject, firstMessageId, and messages (buttons use exactly one of nextMessageId or url).View documentation
LinkedIn firmographic breakdowns are now supported in analytics via the
This lets you request LinkedIn aggregated firmographic segments for the requested date range (note: LinkedIn data is aggregated over the whole range, delayed 12–24h, and segments with <3 events are omitted).
Use
•
•
•
LinkedIn breakdown rows include the raw pivot
View documentation
breakdowns query param on GET /v1/ads/{adId}/analytics and GET /v1/ads/campaigns/{campaignId}/analytics.This lets you request LinkedIn aggregated firmographic segments for the requested date range (note: LinkedIn data is aggregated over the whole range, delayed 12–24h, and segments with <3 events are omitted).
Use
breakdowns with LinkedIn dimensions:•
job_title, job_function, seniority, industry•
company, company_size•
country, regionLinkedIn breakdown rows include the raw pivot
value plus a resolved name.View documentation
Custom audiences now support new types:
You can list and filter these via
To create them via
•
•
View documentation
company_list and engagement on /v1/ads/audiences.You can list and filter these via
GET /v1/ads/audiences using type = customer_list | company_list | engagement | website | lookalike | saved_targeting.To create them via
POST /v1/ads/audiences:•
type=engagement (LinkedIn): requires sourceType (VIDEO_ADS | LEAD_GEN_FORMS | ORGANIZATION_PAGES | EVENT_PAGES | SINGLE_IMAGE_ADS), plus trigger, lookbackDays (30 | 60 | 90 | 180 | 365), and engagementSources.•
type=company_list (LinkedIn): requires companies (array of company rows like name, domain, website, linkedinPageUrl).View documentation
❤2