Zernio Developers
1.38K subscribers
1 photo
1 video
890 links
Changelog updates from zernio.com, the marketing infrastructure for products and agents

zernio.com/changelog
Download Telegram
Shipped since Friday: 23 API updates

• Facebook: Build Page management and insights: facebook-tagged-posts, facebook-visitor-posts, facebook-page-info (GET/PATCH), plus pin/unpin via POST /v1/posts/{postId}/pin.
• Inbox: Triage mentions and label Messenger threads: GET /v1/inbox/mentions supports platform=facebook, and GET/POST/DELETE /v1/inbox/labels plus conversation label endpoints.
• Ads: Control tracking and objectives plus detect partial TikTok reports: tracking.zernioTag on POST /v1/ads/create, metaObjective on POST /v1/ads/boost, missingRows on TikTok materials.
• Connect & Accounts: Ship safer connects and listings: Instagram QR handoff via handoff=true, GA4 headless picker via pendingDataToken, and cursor paging on GET /v1/accounts + /follower-stats.
• Webhooks & Admin: Automate ad-rule alerts and team access: subscribe to ad_rule.triggered, inspect runs[].evaluation.notification, and restrict invites via disabledResourceGroups on POST /v1/invite/tokens.
• LinkedIn @mentions can now be written directly in post text and resolved automatically when creating or updating posts.
🔥2
Zernio now supports Google/Microsoft Email, Calendar, and Files via new API surfaces.

Connect mailboxes/drives with GET /v1/connect/{platform} where platform now includes google and microsoft (and scopes is required for these platforms: email, calendar, files, contacts).

New endpoint families:
• Email: list threads/messages, read bodies, send/reply, move/mark, download attachments (/v1/email/*)
• Calendar: list calendars/events, create/update/delete, RSVP, free-busy, availability (/v1/calendar/*)
• Files: list/search, upload, create folders, download, share links, Google Picker sessions (/v1/files/*)

Operational additions:
• GET /v1/accounts/{accountId}/health adds sendCap and push for Google/Microsoft
• Webhooks add events: calendar.event.created/updated/deleted, file.created/updated/deleted, file.picked, account.rate_limited
• Microsoft tenants that require admin approval can use GET /v1/connect/microsoft/admin-consent

curl -sS -H "Authorization: Bearer $ZERNIO_API_KEY" \
"https://api.zernio.com/v1/connect/google?profileId=$PROFILE_ID&scopes=email,calendar,files"


View documentation
❤1
Shipped today: 7 API updates

• Ads Reporting: List account issues and compare periods in reports via GET /v1/ads/alerts and compare=previous on GET /v1/ads/tree//v1/ads/timeline.
• Meta Ad Sets: Configure Meta ad set schedules and compliance fields via PUT /v1/ads/ad-sets/{adSetId} using platformSpecificData.adSchedule, dsaBeneficiary, dsaPayor.
• Ads Create: Create ads without a name and read inferred settings from appliedDefaults in POST /v1/ads/create responses.
• Meta Lead Gen: Read disclaimer checkbox consent per lead via consents on lead list endpoints and lead.received webhook payloads.
• Connect: Detect connect token/profile mismatches via 403 INSUFFICIENT_PERMISSIONS on connect endpoints like GET /v1/connect/googlebusiness/locations.
• Meta ad accounts can now be pre-checked with GET /v1/ads/accounts/health before creating ads.
GET ad review responses can now return adId: null on success.

When calling GET /v1/ads/{adId}/review with a Meta platformAdId plus accountId (for an ad not yet synced into Zernio), the response is read live from Meta and returns synced: false and adId: null. Update your code to treat adId as nullable.

You can now also pass accountId to read unsynced Meta ads via:
• GET /v1/ads/{adId} (returns ad.synced)
• GET /v1/ads/{adId}/preview (returns synced)
• GET /v1/ads/{adId}/media (returns synced)

curl -sS -H "Authorization: Bearer $ZERNI0_KEY" \
"https://api.zernio.com/v1/ads/123456789012345/review?accountId=acc_abc"


View documentation
❤1
You can now manage and use your own OAuth apps for Connect.

Use the new /v1/connect/oauth-apps endpoints to store per-platform client credentials, rotate secrets, and validate keys. Then pass oauthAppId on GET /v1/connect/{platform} so the consent screen shows your app and the platform’s limits/quotas apply to your app.

Key details:
• List supported platforms and setup info via GET /v1/connect/oauth-apps (see platforms and redirectUri)
• Create/update apps with scopeAreas: posting, analytics, comments, messaging, ads
• App status: ok, unchecked, invalid
• New webhook event account.permissions_changed is available for subscriptions and test fires

curl -X POST "$ZERNIO_API/v1/connect/oauth-apps" \
-H "Authorization: Bearer $ZERNIO_KEY" \
-H "Content-Type: application/json" \
-d '{"platform":"youtube","label":"Acme","clientId":"...","clientSecret":"..."}'


View documentation
OAuth app scope areas no longer include ads.

If your integration sends scopeAreas when creating/updating OAuth apps, remove ads (allowed: posting, analytics, comments, messaging). Also update any code that parses apps[].scopeAreas, platforms[].scopeAreas[].area, or webhook account.missingScopeAreas to not expect ads.

New: OAuthApp.webhook is now returned (Facebook/Instagram only) with callbackUrl, verifyToken, object (page|instagram), and fields.

curl -X PATCH "$ZERNIO_API/v1/connect/oauth-apps/$APP_ID" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"scopeAreas":["posting","comments"]}'


View documentation
OAuth app scopeAreas no longer supports ads.

If your integration sends or expects ads in OAuth app setup, update it to use only: posting, analytics, comments, messaging.

This affects:
• POST /v1/connect/oauth-apps body scopeAreas
• PATCH /v1/connect/oauth-apps/{appId} body scopeAreas
• GET /v1/connect/oauth-apps response apps[].scopeAreas and platforms[].scopeAreas[].area
• Webhook account.permissions_changed payload account.missingScopeAreas

Also added: apps[].webhook in GET /v1/connect/oauth-apps (Facebook/Instagram only) with callbackUrl, verifyToken, object (page | instagram), and fields.

curl -X PATCH "$ZERNIO_API/v1/connect/oauth-apps/$APP_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"scopeAreas":["posting","comments"]}'


View documentation
Shipped today: 10 API updates

• Ads: Manage Reddit audiences and ad groups: GET/POST /v1/ads/audiences, POST /v1/ads/ad-sets, GET /v1/ads/ad-sets/{id}/targeting, PUT /v1/ads/ad-sets/{id}.
• Ads Rules: Audit every rule action and keep past runs readable: GET /v1/ads/rules/activity and GET /v1/ads/rules/{ruleId}/runs with runs[].evaluation.rule.
• Publishing: Incrementally sync posts with GET /v1/posts using updatedSince to fetch items whose updatedAt changed since a timestamp.
• Meta Ads: Show Meta ad set learning phase in your UI: GET /v1/ads/tree returns campaigns[].adSets[].learningStatus.
• Instagram: Explain collaborator removals on publish: Instagram create post responses expose platformSpecificData.droppedCollaborators[] with username and reason.
Meta Dynamic Creative: update your dynamicCreative.callToActionTypes values.

The CTA enum for POST /v1/ads/create Dynamic Creative has changed: these values were removed and will now be rejected:
• REGISTER JOIN ATTEND REQUEST_DEMO VIEW_QUOTE APPLY

Meta CTA coverage was also expanded across callToAction, creatives[].callToAction, and dynamicCreative.callToActionTypes (e.g. SEE_DETAILS, LIKE_PAGE, MESSAGE_PAGE, OPEN_LINK, NO_BUTTON, CALL_NOW, WHATSAPP_MESSAGE, etc.).

Additionally, GET /v1/ads now returns richer Meta creative fields like creative.headline, creative.bodies, creative.description, creative.callToAction, creative.leadGenFormId, creative.imageHash, and creative.urlTags, and creative.headlines[]/creative.descriptions[] can now be strings or objects.

curl -X POST "$ZERNIO_API/v1/ads/create" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"accountId":"...","adAccountId":"act_...","goal":"traffic","dynamicCreative":{"imageUrls":["https://..."],"callToActionTypes":["LEARN_MORE"],"linkUrls":["https://..."],"bodies":["Text"],"titles":["Title"]}}'


View documentation
Meta Facebook placements: video_feeds was removed from facebookPositions.

If your integration sends placements.facebookPositions (or placementAssets.rules[].placements.facebookPositions) with video_feeds, update your requests to omit it or replace it with supported positions.

Affected endpoints include PUT /v1/ads/ad-sets/{adSetId}, POST /v1/ads/create, POST /v1/ads/messaging, POST /v1/ads/call, POST /v1/ads/ctwa.

curl -X POST "$ZERNIO_API/v1/ads/create" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"accountId":"...","adAccountId":"...","name":"...","placements":{"publisherPlatforms":["facebook"],"facebookPositions":["feed","story"]}}'


View documentation
❤1
Shipped today: 13 API updates

• Ads: Control attribution tags, reach estimates, and duplication correlation using tracking.zernioTag, rawTargeting, and adSetIdMap/adIdMap.
• Inbox: Route FB/IG conversations by Page and handle comment-reply failures with structured errors via pageId and POST /v1/inbox/comments/{postId}.
• Connect: Keep connect flows on your OAuth app and detect token mismatches via oauthAppId in selection/WhatsApp credentials and 403 INSUFFICIENT_PERMISSIONS.
• Meta Ads: Audit ad set delivery/compliance details from the ads tree using destinationType, attributionSpec, and regionalRegulatedCategories.
• Slack & Health: Propagate Slack identity across a workspace and debug disconnects via applyToWorkspace and GET /v1/accounts/health fields like disconnectReason.
• OAuth apps now return sharedWebhookUrl on GET /v1/connect/oauth-apps.
Top-ups and payout batches no longer return a Checkout URL; they now charge the billing owner’s saved card directly and may require 3D Secure.

For POST /v1/balance/top-ups:
• Response field url was removed (breaking)
• Response now includes status: succeeded | processing | requires_action
• When status=requires_action, use clientSecret with Stripe.js, then call POST /v1/balance/top-ups/{topupId}/confirm
• You can also end an unfinished payment with POST /v1/balance/top-ups/{topupId}/cancel

For POST /v1/creator-campaigns/{campaignId}/payout-batches:
• Response field url was removed (breaking)
• When payment.status=requires_action, complete 3D Secure then call POST /v1/payout-batches/{batchId}/confirm (or /cancel to end it)

Also, GET /v1/balance now includes payoutLockedCents and payoutLocks, and transfers/payouts may return 409 payout_funds_locked until 7 days after a card charge.

curl -X POST "$ZERNIO_API/v1/balance/top-ups/$TOPUP_ID/confirm" \
-H "Authorization: Bearer $API_KEY"


View documentation
Ad campaign results are now available via the new Ad Campaign Results endpoints.

You can upload your own daily per-campaign metrics (e.g. leads, sales, revenue) and query summed results per campaign over a date range, so rules and reporting can use them alongside spend.

New endpoints:
• GET /v1/ads/campaign-results with fromDate, toDate (inclusive, max 400 days), optional campaignIds (≤500), pagination via limit and cursor → nextCursor
• POST /v1/ads/campaign-results uploads rows (≤1000) and supports Idempotency-Key; returns 202 with uploadId and Location
• GET /v1/ads/campaign-results/uploads/{uploadId} to check status queued/done/failed and unmatched reasons no_campaign/ambiguous
• GET /v1/ads/campaign-results/metrics and PUT /v1/ads/campaign-results/metrics/{key} to name metrics (kind: count or money with currency)

curl -X POST "https://api.zernio.com/v1/ads/campaign-results" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7b1c2c" \
-d '{"rows":[{"date":"2026-10-01","campaignId":"123","values":{"qualified_leads":14,"revenue":7800}}]}'


View documentation
Shipped today: 10 API updates

• Ads: Automate ads ops with rule templates, ad-level rules, and computed campaign results via GET /v1/ads/rules/templates, PUT /v1/ads/campaign-results/metrics/{key}.
• Ads: List each ad account row and troubleshoot connections with scoped alerts via GET /v1/accounts?adAccountRows=true and GET /v1/ads/alerts?profileId=....
• Ads: Launch a branded ads connect flow using GET /v1/connect/{platform}/ads with welcome=true plus brandName, logoUrl, primaryColor, welcomeTheme.
• Creator campaigns: Pay creators on engagements or organic-only views and review paid-view flags via metric=engagements, organicViewsOnly, and submissions fields viewsPaid/engagementsLatest.
• Inbox & Webhooks: Filter inbox conversations by contact tags and track GBP review deletions/restores via GET /v1/inbox/conversations?tags=... and webhook events review.deleted/review.restored.
The TikTok Tools download endpoint has been removed: GET /v1/tools/tiktok/download.

If your integration relied on this to fetch a download URL or available formats for TikTok videos, you’ll need to remove/replace those calls—requests to this endpoint will no longer work.

Affected endpoint: GET /v1/tools/tiktok/download

curl -X GET \
"$ZERNIO_API_BASE/v1/tools/tiktok/download?url=..." \
-H "Authorization: Bearer $ZERNIO_API_KEY"


View documentation
Shipped since Sunday: 7 API updates

• Publishing: Label AI-generated Facebook Reels/video Stories via platformSpecificData.isAiGenerated, and invite up to 10 Reel collaborators via platformSpecificData.collaborators.
• Analytics: Compute date-range sums without client aggregation: GET /v1/analytics/daily-metrics returns totals (impressions, reach, engagement, etc.).
• Inbox: Render Facebook comment attachments (GIFs, photos, links, videos) from comments[].attachment in GET /v1/inbox/comments/{postId}.
• Ads: Rebuild Meta catalog template ad creatives with a different format using creative.catalogFormat on PUT /v1/ads/{adId}.
• Creator Campaigns: Move a creator participant to another campaign while keeping the same participant id via POST /v1/creator-campaigns/{campaignId}/participants/{participantId}/move.
• Card top-ups now support fee-on-top pricing, and you can fetch the estimated card fee before charging.
Shipped today: 15 API updates

• Ads: Build richer ads UIs: rank ads GET /v1/ads/performance, read schedules/special categories via GET /v1/ads/tree, and label audiences with audiences[].summary.
• Ads Reporting: Report conversions by goal and booked appointments: timeline rows[].conversionsByType and Meta metrics.funnel.schedules.
• Ads Writes: Handle ads write edge cases: Meta asset_feed text edits via PUT /v1/ads, lead forms return 409 AccountDisconnected, and campaign status uses 422 ad_account_unusable.
• Account Health: Gate create/boost and inbox health: GET /v1/ads/accounts/health returns ready/blockers, and /v1/accounts/health returns inboundActivity stamps.
• Analytics & Voice: Detect missing YouTube segments via segmentMetricsAvailable, estimate forwarded call costs with forwardTo, and debug uploads using failureReason on results status.
Ad rules conditions are now a strict group structure and no longer accept extra fields.

When creating rules, conditions must be either { all: [...] } or { any: [...] } (no other top-level keys). Items inside all/any can be a condition or another nested group (up to 3 levels).

Key changes:
• conditions is now oneOf: all or any
• conditions and each group are additionalProperties: false
• all[]/any[] items are now AdRuleConditionItem (condition or nested group)

curl -X POST "$ZERNIO_API/v1/ads/rules" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"conditions":{"any":[{"metric":"cpc","window":"today","op":">","value":2}]}}'


View documentation
Ad rules budget actions now support fixed-amount updates, and adjust_budget actions may no longer include direction/percent/limit.

If you parse rules[].actions[], update your logic to handle two adjust_budget shapes:
• Fixed amount: { type: "adjust_budget", amount } (required amount)
• Percent change: { type: "adjust_budget", direction, percent, limit }

Also, notify actions can now include send to deliver alerts via connected Slack or email destinations (in addition to the ad_rule.triggered webhook).

View documentation
Ad rules now support a new action type: duplicate.

If your integration strictly validates/parses rule actions, update your models to accept actions[].type = duplicate (in addition to notify, pause, activate, adjust_budget) and handle its fields.

duplicate action fields:
• status: paused | active (default paused)
• renameSuffix
• maxChangesPerDay

You can also filter rule activity by type=duplicate on GET /v1/ads/rules/activity, and webhook/run/activity payloads may now include type = duplicate.

curl -G "$ZERNIO_API/v1/ads/rules/activity" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "type=duplicate" \
--data-urlencode "limit=50"


View documentation
Ad rule schedules now support set times and optional start/end windows, and 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 bounds

Sending schedule replaces the rule’s whole timing; if omitted on create, a new rule defaults to every 60 minutes.

View documentation