Ad rule schedules now support set times and optional start/end windows, and
When reading rules, handle
You can now schedule rules with:
•
•
•
Sending
View documentation
everyMinutes is no longer guaranteed to be present.When reading rules, handle
schedule.everyMinutes being missing or null (it’s null when a rule runs at set times).You can now schedule rules with:
•
everyMinutes: 15, 30, 60, 180, 360, 720, 1440, or null•
times: weekly run times (days + HH:MM)•
startsAt / endsAt: optional date-time boundsSending
schedule replaces the rule’s whole timing; if omitted on create, a new rule defaults to every 60 minutes.View documentation
Ad rules actions have changed (breaking): budget adjustment actions are no longer represented as
If your integration reads or creates budget-change actions, update your parsing/validation to match the new action variants, and handle the new
Also updated:
•
• Activity entries and webhook payloads may include rename details:
View documentation
type=adjust_budget in rule payloads/requests.If your integration reads or creates budget-change actions, update your parsing/validation to match the new action variants, and handle the new
type=edit_name action.Also updated:
•
GET /v1/ads/rules/activity filter type now includes edit_name (alongside pause, activate, adjust_budget, duplicate)• Activity entries and webhook payloads may include rename details:
previousName, newNamecurl -G "https://api.zernio.com/v1/ads/rules/activity" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "type=edit_name" \
--data-urlencode "limit=50"
View documentation
Ad Rules: update your integrations for action schema changes and new alert lifecycle support.
Breaking changes
• Ad rule
•
New capabilities
• New endpoint to list a rule’s alert episodes:
• New webhook events:
View documentation
Breaking changes
• Ad rule
actions now include adjust_bid and may no longer match older oneOf shapes (some fields/enums were removed/narrowed). If you validate/deserialize actions, update your models to handle the new variants.•
AdRule now includes lifecycle (nullable) and POST/PATCH ad rule bodies accept lifecycle.New capabilities
• New endpoint to list a rule’s alert episodes:
GET /v1/ads/rules/{ruleId}/alerts with state = pending | open | resolved, plus limit and cursor pagination.• New webhook events:
automation.alert.opened, automation.alert.escalated, automation.alert.resolved (payload: WebhookPayloadAutomationAlert). You can also request these samples via POST /v1/webhooks/test.curl -sS -H "Authorization: Bearer $ZERNIO_API_KEY" \
"https://api.zernio.com/v1/ads/rules/$RULE_ID/alerts?state=open&limit=50"
View documentation
Ad rules filters have changed: the
If you create or parse rules, update your integration to stop sending/expecting
You can now filter by budget placement using
Rule actions now also support
View documentation
days_live filter is no longer supported, and filter typing/enums were updated.If you create or parse rules, update your integration to stop sending/expecting
{field: "days_live", op: ">="|"<", value: number} in filters.You can now filter by budget placement using
filters[].field = budget_level with op = equals and value = campaign or adset.Rule actions now also support
maxChangesPerObject (in addition to maxChangesPerDay) for pause, activate, duplicate, adjust_bid, edit_name, and adjust_budget.View documentation
Shipped today: 14 API updates
• Ad Rules: Build richer automations with budget metrics, rank ops, filters, quiet hours, undo, and activate options via
• Webhooks: Subscribe to automation and ads lifecycle events and generate sample payloads via
• Meta Ads: Handle Meta write limits on ad creation by retrying on
• TikTok Analytics: Fetch follower demographics proportions by age/gender/country/city via
• Billing: Link to the right top-up document using
• Ad rule templates now include a required
• Ad Rules: Build richer automations with budget metrics, rank ops, filters, quiet hours, undo, and activate options via
POST /v1/ads/rules and POST /v1/ads/rules/activity/{activityId}/undo.• Webhooks: Subscribe to automation and ads lifecycle events and generate sample payloads via
POST /v1/webhooks/settings and POST /v1/webhooks/test.• Meta Ads: Handle Meta write limits on ad creation by retrying on
429 MetaAdAccountWriteLimited from POST /v1/ads/messaging, POST /v1/ads/call, POST /v1/ads/ctwa.• TikTok Analytics: Fetch follower demographics proportions by age/gender/country/city via
GET /v1/analytics/tiktok/demographics with breakdown.• Billing: Link to the right top-up document using
invoiceUrl, receiptUrl, and hasInvoice from GET /v1/balance/top-ups/{topupId}/receipt.• Ad rule templates now include a required
goal field in GET /v1/ads/rules/templates responses.Call billing no longer includes
If your integration reads
Impacted responses:
•
•
•
Ads rules now also support optional campaign grouping via
View documentation
billing.recordingSeconds in call records.If your integration reads
recordingSeconds from call history or call detail responses, remove that dependency and rely on available cost fields like billing.recordingCostUSD, billing.billableCostUSD, and billing.totalCostUSD.Impacted responses:
•
GET /v1/calls, GET /v1/calls/{id}•
GET /v1/voice/calls•
GET /v1/whatsapp/callsAds rules now also support optional campaign grouping via
groups (returned on rules and in rule previews).curl -sS -H "Authorization: Bearer $TOKEN" \
"$BASE_URL/v1/calls?accountId=$ACCOUNT_ID&limit=1"
View documentation
Shipped today: 7 API updates
• Ads: Build ad rules with month windows and calendar metrics using
• Ads: Reuse existing videos in placement-customized creatives via
• Publishing: Create platform-less drafts scoped to a profile using
• Accounts: Enable Meta ads sync on a Facebook posting account by setting
• Commerce: Route commerce order events by profile using
• You can now create single-use connect links with
• Ads: Build ad rules with month windows and calendar metrics using
window:this_month|last_month and metric:day_of_month|working_day_of_month.• Ads: Reuse existing videos in placement-customized creatives via
placementAssets.defaultVideoId and placementAssets.rules[].videoId on POST /v1/ads/create.• Publishing: Create platform-less drafts scoped to a profile using
profileId with POST /v1/posts (isDraft=true), and read it via posts[].profileId.• Accounts: Enable Meta ads sync on a Facebook posting account by setting
metaAdsSyncEnabled on PUT /v1/accounts/{accountId}.• Commerce: Route commerce order events by profile using
profiles in WebhookPayloadCommerceOrder webhooks.• You can now create single-use connect links with
POST /v1/platform-invites.Top-ups no longer have a card fee, and
When creating a top-up via
You can now fetch a paid top-up statement (no VAT) via
View documentation
GET /v1/balance/top-ups/card-fee has been removed (update any integrations that call it).When creating a top-up via
POST /v1/balance/top-ups, the card is now charged exactly amountCents and your balance is credited the same amount (feeCents is always 0, feeIsExact is always true for compatibility). The minimum amountCents is now 500.You can now fetch a paid top-up statement (no VAT) via
GET /v1/balance/top-ups/{topupId}/statement. Response includes format = pdf or page, plus pdfUrl/pageUrl (short-lived links).curl -sS -H "Authorization: Bearer $TOKEN" \
"https://api.zernio.com/v1/balance/top-ups/$TOPUP_ID/statement"
View documentation
Ad rules now support new action types
If you validate or deserialize ad rule actions, update your models to handle action
For
The activity filter
View documentation
adjust_target and reallocate_budget, and activity/run/webhook payloads include additional fields for these actions.If you validate or deserialize ad rule actions, update your models to handle action
type values: pause, activate, adjust_budget, adjust_bid, adjust_target, reallocate_budget, duplicate, edit_name.For
adjust_target actions, target is now required when creating rules. Webhook payload ad_rule.triggered, rule runs, and rule activity entries may now include targetMetric, previousTarget, newTarget.The activity filter
GET /v1/ads/rules/activity also accepts type=adjust_target and type=reallocate_budget.curl -G "$ZERNIO_API/v1/ads/rules/activity" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "type=adjust_target" \
--data-urlencode "limit=50"
View documentation
Automations are now available via the API: you can create and manage ad rules, event automations, and scheduled post automations, plus preview/backtest ad rules and track runs/actions.
Core endpoints include
Automation
Templates are supported for reuse and sharing:
View documentation
Core endpoints include
GET/POST /v1/automations, PATCH/DELETE /v1/automations/{automationId}, POST /v1/automations/{automationId}/activate, POST /v1/automations/{automationId}/pause, POST /v1/automations/preview, POST /v1/automations/backtest, and run history via GET /v1/automations/{automationId}/checks and GET /v1/automations/actions.Automation
kind is ad_rule, event, or scheduled. Use GET /v1/automations/catalog to discover supported triggers/steps/metrics and the JSON schema used for validation.Templates are supported for reuse and sharing:
/v1/automations/templates (team), /v1/automations/templates/shared/{shareToken}, and /v1/automations/templates/zernio/{templateId}, with install endpoints that support multi-target installs (207 for partial success).curl -sS -X GET "https://api.zernio.com/v1/automations?limit=50" \
-H "Authorization: Bearer $ZERNIO_API_KEY"
View documentation
Shipped today: 14 API updates
• Billing: Preview and charge top-ups with tax + fetch invoices via
• Billing: Auto-top up when balance drops below a threshold by updating
• Errors: Handle billing-required failures as non-retryable by checking
• Ads: Harden ads workflows: Meta create retries (
• Attribution: Attribute results to campaigns via
• Billing: Preview and charge top-ups with tax + fetch invoices via
POST /v1/balance/top-ups/preview and GET /v1/balance/top-ups/{topupId}/invoice.• Billing: Auto-top up when balance drops below a threshold by updating
PATCH /v1/balance/auto-recharge (enabled, belowCents, toCents, limits).• Errors: Handle billing-required failures as non-retryable by checking
402 BalanceRequired on send/call/verify endpoints like POST /v1/verify/verifications.• Ads: Harden ads workflows: Meta create retries (
retryOnServerError/recoveredWrites), library 429, status=not_deleted, IG actor, defaults, intro cards.• Attribution: Attribute results to campaigns via
events[].campaign on POST /v1/events and count HubSpot closed-won deals via PATCH /v1/accounts/{id}/hubspot-settings.Media validation responses changed:
The endpoint now verifies media by inspecting the actual bytes (not just headers) and returns stable failure reasons via
Post validation now reports media decode failures with
View documentation
POST /v1/tools/validate/media no longer returns type=unknown. Update any enum parsing/validation to handle only type = image | video | document.The endpoint now verifies media by inspecting the actual bytes (not just headers) and returns stable failure reasons via
code: MEDIA_UNDECODABLE | MEDIA_URL_UNREACHABLE | MEDIA_URL_NOT_ALLOWED. It also adds format, width, height, and inspection (decoded | header).Post validation now reports media decode failures with
errors[].code = MEDIA_UNDECODABLE in POST /v1/tools/validate/post.curl -sS -X POST "$ZERNIO_API/v1/tools/validate/media" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/image.jpg"}'
View documentation
POST /v1/transfers has been removed and now always returns 410. If you were paying creators from your balance, switch to paying via payout batches.Treasury campaign payouts are now card-based: use
POST /v1/creator-campaigns/{campaignId}/payout-batches (one card payment per batch). GET /v1/balance no longer represents creator payout funds; payoutLockedCents / payoutLocks are deprecated and always empty/0.New: preview what a payout batch would charge with
POST /v1/creator-campaigns/{campaignId}/payout-batches/preview. Response includes amountCents, feeCents, taxCents, totalCents, taxLabel, reverseCharge.Also: payout batch responses now include
batch.releasesAt, and items add status value refunded plus refundedCents.curl -X POST "$BASE_URL/v1/creator-campaigns/$CAMPAIGN_ID/payout-batches/preview" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"excludeParticipantIds":["ptc_..."]}'
View documentation
Shipped since Friday: 14 API updates
• Events API: Avoid duplicate conversion/event ingestion and track delivery outcomes via
• Balance & Billing: Build balance-aware billing UX using
• Webhooks: Trigger automations on billing and ad set changes using webhook events
• Ads Accounts: Refresh ad account catalogs live and broaden IG identity discovery via
• Publishing & Payments: Handle billing blocks and payment throttling via X publish errors (
• Events API: Avoid duplicate conversion/event ingestion and track delivery outcomes via
Idempotency-Key, mode=async, and GET /v1/events/{eventId}.• Balance & Billing: Build balance-aware billing UX using
GET /v1/balance fields (recentCreditRecharges, balanceBilling, spendableCents) plus lineItems[].paidFrom.• Webhooks: Trigger automations on billing and ad set changes using webhook events
balance.low|empty|charged and ad_set.created|updated in events.• Ads Accounts: Refresh ad account catalogs live and broaden IG identity discovery via
GET /v1/ads/accounts?live=true and GET /v1/ads/instagram-accounts source.• Publishing & Payments: Handle billing blocks and payment throttling via X publish errors (
POST/PUT /v1/posts, /retry) plus 429 payment_attempts_limited on top-ups/payouts.Action required:
Pinterest now supports account-level analytics via
Use
View documentation
account.permissions_changed webhook payloads may now return account.oauthAppId as null (when the account uses Zernio’s OAuth app). Update any strict schema validation / deserialization to accept null.Pinterest now supports account-level analytics via
GET /v1/analytics/pinterest/account-insights.Use
accountId (Pinterest SocialAccount), optional metrics (default impressions,engagements,follower_count), fromDate/toDate (max 89 days), and metricType (total_value | time_series). since/until remain as deprecated aliases.curl -G "https://api.zernio.com/v1/analytics/pinterest/account-insights" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "accountId=acc_123" \
--data-urlencode "metricType=time_series"
View documentation
Many content fields can now be
You can now read and change the team-wide mode via the new
•
•
Also: profiles can set
View documentation
null when a team (or profile) uses zero content retention (mode=none). Update your integration to handle contentNotRetained: true and nullable fields (e.g. post content/title, inbox lastMessage/message, mentions/reviews text, lead answers, call recording URLs).You can now read and change the team-wide mode via the new
Content Retention endpoints:•
GET /v1/content-retention•
PUT /v1/content-retention with mode: standard | noneAlso: profiles can set
contentRetention on create/update, and webhooks add events mention.received, call.transcript_segment, call.recording_ready (important when content isn’t stored).curl -X PUT "$ZERNIO_API/v1/content-retention" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"none"}'
View documentation
Action required:
Removed:
•
•
•
•
•
Also,
New capability: you can now manage Zernio-stored signatures (works across providers) and explicitly declare Outlook “send as” addresses (e.g. shared mailboxes) so they become valid
View documentation
GET /v1/email/send-as response fields changed.Removed:
displayName, isPrimary, verified, and meta.completeList/meta.signatures. Replace with:•
data[].name•
data[].type = primary | alias | shared•
data[].verificationStatus = accepted | pending | unverified•
data[].source = provider | declared•
meta.list = provider | partial and meta.providerSignaturesAlso,
data[].signature is now an object (or null) describing what appendSignature would add (Zernio default first, else Gmail).New capability: you can now manage Zernio-stored signatures (works across providers) and explicitly declare Outlook “send as” addresses (e.g. shared mailboxes) so they become valid
from values.curl -X POST "$ZERNI0/v1/email/signatures" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Sales","html":"<b>Ada</b>","defaultFor":["sales@acme.com"]}'
View documentation
Email mailbox connection is now supported via a new Connect flow and IMAP APIs.
Use
Key query params:
If you’re building your own UI, use
To connect without the hosted page, use
Webhooks:
View documentation
Use
GET /v1/connect/email to generate a 1-hour hosted connect link that routes users to Google/Microsoft OAuth or IMAP (with provider app-password steps).Key query params:
profileId (required), redirect_url, email, name, reconnectAccountId.If you’re building your own UI, use
POST /v1/email/imap/discover to decide the route (imap | google_oauth | microsoft_oauth | unsupported) and get suggested IMAP/SMTP settings + auth guidance.To connect without the hosted page, use
POST /v1/email/imap/accounts with profileId + email (and optionally password, imap, smtp, identities). Supports dryRun validation and in-place reconnect via reconnectAccountId. Failures return 422 with stage codes (e.g. use_oauth, app_password_required, imap_auth_failed).Webhooks:
account.connected now may include account.reconnected and account.replacedAccountId. account.disconnected now may include account.reasonCode (auth_failed, imap_disabled, tls_error, unreachable, replaced) and account.reconnectUrl (hosted reconnect link).curl -sS -H "Authorization: Bearer $TOKEN" \
"https://api.zernio.com/v1/connect/email?profileId=$PROFILE_ID&redirect_url=https://app.example.com/callback"
View documentation
Calendar free-busy responses can now return
When an account/calendar/person can’t be read, you’ll now get
In
• Send either
•
•
• Response adds
Also added: list recurring event instances via
View documentation
busy: null per account, and free-busy requests now support per-account options.When an account/calendar/person can’t be read, you’ll now get
busy: null plus an error, while other accounts still return results.In
POST /v1/calendar/free-busy:• Send either
accountIds (now optional) or accounts•
accounts[].calendarIds lets you choose calendars (or primary)•
accounts[].emails lets you read coworkers via that account• Response adds
calendars, people, and error detailsAlso added: list recurring event instances via
GET /v1/calendar/events/{eventId}/instances (requires accountId, from, to; supports timezone, cursor, limit). Instances include type (single/series/occurrence/exception) and originalStart.curl -X POST https://api.zernio.com/v1/calendar/free-busy \
-H 'Authorization: Bearer $TOKEN' -H 'Content-Type: application/json' \
-d '{"from":"2026-11-10T00:00:00Z","to":"2026-11-11T00:00:00Z","accounts":[{"accountId":"acc_123","calendarIds":["primary"]}]}'
View documentation
Shipped today: 22 API updates
• Email: Build full email workflows: schedule/hold drafts, track opens/clicks/replies, manage drafts/forward/labels/send-as/IMAP, and handle webhooks via
• Creator Campaigns: Run creator campaigns end-to-end: draft review, samples, join approval, Spark codes, and launch posts as ads via
• Instagram: Backfill Story history and insights:
• Ads & Conversions: Unify lead + conversion pipelines:
• Core APIs: Handle truncation, ownership, metadata, mentions, and calendar notifications:
• Email: Build full email workflows: schedule/hold drafts, track opens/clicks/replies, manage drafts/forward/labels/send-as/IMAP, and handle webhooks via
v1/email/*.• Creator Campaigns: Run creator campaigns end-to-end: draft review, samples, join approval, Spark codes, and launch posts as ads via
public/creator-campaigns/* endpoints.• Instagram: Backfill Story history and insights:
GET /v1/accounts/{accountId}/instagram/stories?includeExpired=true plus insights source=archived and metrics.• Ads & Conversions: Unify lead + conversion pipelines:
GET /v1/ads/leads?platform=google, lead.received includes lead.platform, and conversions use PATCH|DELETE /v1/events/{eventId} + forwarding rules.• Core APIs: Handle truncation, ownership, metadata, mentions, and calendar notifications:
warning+pagination.nextCursor, posts[].isOwner, update-metadata, mentionAuthor, notifyParticipants.Organization-wide mailbox connections are now supported for Google Workspace and Microsoft 365.
Admins can grant access once (domain-wide delegation / admin consent), then you can add mailboxes without each user signing in.
Start an org connection with:
•
•
Manage connections via
View documentation
Admins can grant access once (domain-wide delegation / admin consent), then you can add mailboxes without each user signing in.
Start an org connection with:
•
POST /v1/connect/google/org using profileId, domain, scopes (email/calendar/files/contacts)•
POST /v1/connect/microsoft/org using profileId, scopes, optional redirectUrlManage connections via
/v1/org-connections (list/get/update/delete), activate with POST /v1/org-connections/{orgConnectionId}/verify, list users with GET /v1/org-connections/{orgConnectionId}/users, and add mailboxes with POST /v1/org-connections/{orgConnectionId}/mailboxes.curl -X POST "$ZERNI0_API/v1/connect/microsoft/org" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"profileId":"prof_123","scopes":["email","calendar"],"redirectUrl":"https://app.example.com/callback"}'
View documentation