Zernio | Developer News
699 subscribers
1 photo
1 video
488 links
This channel is for recurrent updates and announcements on https://zernio.com.

Zernio is a Social API for Posting and Analytics on 14 platforms.
Download Telegram
WhatsApp call billing now includes billableCostUSD in call history, cost estimates, and call.ended webhooks.

This makes it explicit what Zernio bills you (Telnyx + recording) vs what Meta bills directly to your WABA (display-only).

New/updated billing fields:
billing.billableCostUSD - amount Zernio bills (excludes Meta)
billing.metaCostUSD - Meta per-minute charge (billed by Meta directly; display only)
billing.totalCostUSD - full cost including Meta (display only)

Applies to:
GET /v1/whatsapp/calls
GET /v1/whatsapp/calls/estimate (in breakdown)
• Webhook schema WebhookPayloadCallEnded (in call.billing)

View documentation
🔥1
X (Twitter) posts now support quote reposting via quoteTweetId in TwitterPlatformData.

Set quoteTweetId to a tweet ID (or full status URL) to publish a quote tweet. For threads, it applies to the first tweet only.

Key property:
quoteTweetId - mutually exclusive with media and poll; X only allows quoting your own posts or posts you’re mentioned in / part of the conversation thread of; billed at the standard create rate ($0.015).

View documentation
1
Comment-to-DM automations now support link tracking for DM button URLs, and the list endpoint includes click metrics.

When enabled, link buttons are wrapped in a tracked redirect so you can measure clicks and CTR.

New fields:
• Create/update: linkTracking (POST default: true; set false to send links untouched)
• List: automations[].linkTracking
• List stats: automations[].stats.linkClicks, automations[].stats.uniqueClicks
• Details/create responses: automation.linkTracking

View documentation
🤯42👏1
Comment-to-DM automations now support tagging contacts who click tracked links via clickTag.

When linkTracking is enabled, you can set clickTag so anyone who clicks a tracked link button in the DM gets tagged for segmentation (broadcasts/sequences).

Use:
POST /v1/comment-automations: clickTag (optional; requires linkTracking)
PATCH /v1/comment-automations/{automationId}: clickTag (empty string clears it)

Returned in:
GET /v1/comment-automations: clickTag
GET /v1/comment-automations/{automationId}: clickTag

View documentation
👍21
GET /v1/comment-automations now returns additional automation stats: stats.delivered and stats.read.

This lets you report delivery/read performance for comment-to-DM automations (where supported) without extra calls.

New fields:
stats.delivered - DMs confirmed delivered (Messenger; IG emits no delivery receipt)
stats.read - DMs confirmed read (IG messaging_seen / Messenger message_reads)

View documentation
1🔥1
Comment-to-DM automations now support Instagram story reply triggers via a new trigger field.

You can create automations that fire on keyword replies to stories (in addition to post comments). For story replies, platformPostId is the story media id (omit it to target any story).

Use trigger:
comment
story_reply

Applies to:
POST /v1/comment-automations (new request field trigger, default comment)
GET /v1/comment-automations and GET /v1/comment-automations/{automationId} (responses now include trigger)

View documentation
1🔥1
POST /v1/ads/create now supports Meta placement asset customization via placementAssets.

This lets you pin a specific image to each placement group (e.g. 9:16 for Stories/Reels and 4:5 for Feed) within a single ad, using Meta’s asset_feed_spec + asset_customization_rules behavior.

Use placementAssets:
defaultImageUrl (required)
rules[] (1-10), each with imageUrl + placements

placements supports: publisherPlatforms, facebookPositions, instagramPositions, messengerPositions, audienceNetworkPositions, threadsPositions, whatsappPositions, devicePlatforms.

Constraints: Meta-only; cannot be combined with dynamicCreative, creatives[], or adSetId.

View documentation
🔥21🫡1
Ads now support unified read/update of click-URL tracking tags via GET /v1/ads/{adId}/tracking-tags and PATCH /v1/ads/{adId}/tracking-tags.

This lets you audit and set platform-native tracking params across Meta/Google/LinkedIn (platforms without a click-URL tracking surface return 405).

Read returns platform, level (creative | campaign) plus platform fields:
• Meta: urlTags, templateUrlSpec
• Google: trackingUrlTemplate, finalUrlSuffix
• LinkedIn: dynamicValueParameters, customValueParameters

Update expects only the platform fields:
• Meta: urlTags (array of {key,value}) + full creative (headline, body, callToAction, linkUrl, imageUrl); may return 422 if the creative can’t be rebuilt
• Google: trackingUrlTemplate and/or finalUrlSuffix
• LinkedIn: dynamicValueParameters and/or customValueParameters

Meta-only: you can now read Event Match Quality (EMQ) + pixelCAPI coverage via GET /v1/ads/conversions/quality with accountId and destinationId (non-Meta returns 405).

Also added Meta advanced matching fields to ConversionEvent.user: city, state, zip, dob, gender (Meta-only; hashed server-side).

View documentation
1
Meta placement asset customization in POST /v1/ads/create now supports pinning video per placement group (not just images).

You can now run a single ad with different assets by placement (e.g. 9:16 video on Stories/Reels, 4:5 on Feed). A placementAssets block must be all-image or all-video (no mixing).

Use placementAssets in one of these modes:
• Image mode: defaultImageUrl + rules[].imageUrl
• Video mode: defaultVideoUrl + rules[].videoUrl (+ optional defaultThumbnailUrl / rules[].thumbnailUrl)

placementAssets still can’t be combined with dynamicCreative, creatives[], or adSetId.

View documentation
1
Google Business Profile location listing now supports server-side narrowing for large accounts via search and advanced filter.

This helps users find a specific location without loading the full list, and responses can now indicate when the list is bounded.

Changes:
GET /v1/connect/googlebusiness/locations: new search, filter; response adds hasMore and per-location storeCode
GET /v1/accounts/{accountId}/gmb-locations: new search, filter; response adds hasMore and per-location storeCode
POST /v1/connect/googlebusiness/select-location: request body adds optional (recommended) accountId to resolve the location directly for large accounts
PUT /v1/accounts/{accountId}/gmb-locations: request body adds optional (recommended) accountId when switching locations

View documentation
2
POST /v1/ads/create now supports safe retries via an optional Idempotency-Key header.

This endpoint isn’t idempotent at the ad-platform level (a blind retry can create duplicate campaigns/ad sets/ads). With Idempotency-Key, retries return the original stored response instead of creating duplicates.

Use Idempotency-Key (e.g. a UUID):
• Same key + same body → replays the original response (response header Idempotent-Replayed: true)
• Same key + different body → 422
• Key still processing → 409 (retry after backoff)

Keys are scoped to your credential and expire after 24h.

View documentation
1
Meta ads created via POST /v1/ads/create now support raw Meta-native targeting via rawTargeting.

This lets you pass a Meta targeting spec through verbatim (snake_case) to clone an existing campaign’s targeting exactly, including advanced fields not covered by the camelCase targeting fields.

Use rawTargeting (Meta only) and do not combine it with:
• camelCase targeting fields (e.g. countries, regions, cities, interests, ageMin, ...)
audienceId
savedTargetingId

Sending both will return 422. If targeting EU users, also provide dsaBeneficiary / dsaPayor separately (not inside rawTargeting).

View documentation
1
You can now rename Meta ads objects via update endpoints.

This adds name updates without recreating entities (Meta only; other platforms return 501).

PUT /v1/ads/campaigns/{campaignId} now accepts name (max 255)
PUT /v1/ads/ad-sets/{adSetId} now accepts name (max 255)
PUT /v1/ads/{adId} now supports name (max 255) and propagates it to Meta; non-Meta returns 501

Ad creation on Meta also adds more naming control:
POST /v1/ads/create now accepts campaignName and adSetName (max 255)
• In Meta multi-creative mode, creatives[].name sets the per-ad name (max 255)

View documentation
1
New Inbox Analytics endpoints are available to query messaging volume, response times, and conversation-level stats (max date range: 365 days).

New endpoints:
GET /v1/analytics/inbox/volume — volume + KPIs + per-platform split (key params: fromDate, toDate, profileId, platform, accountId, source)
GET /v1/analytics/inbox/heatmap — day-of-week × hour heatmap (key params: fromDate, toDate, action=message.received|message.sent|message.read|all)
GET /v1/analytics/inbox/source-breakdown — breakdown by metadata.source
GET /v1/analytics/inbox/response-time — time-to-first-response summary + histogram
GET /v1/analytics/inbox/top-accounts — top accounts by inbox volume (key param: limit 1–50)
GET /v1/analytics/inbox/conversations — paginated conversation analytics (key params: limit, page, sortBy=lastMessageAt|firstMessageAt|totalMessages|received|sent|read|failed, order=asc|desc)
GET /v1/analytics/inbox/conversations/{conversationId} — single-conversation analytics ({conversationId} accepts Mongo _id or platformConversationId)

Webhook event enums were expanded in POST /v1/webhooks/settings, PUT /v1/webhooks/settings, and the Webhook schema to include:
whatsapp.number.suspended
whatsapp.number.reactivated
whatsapp.number.released

View documentation
5
POST /v1/ads/create now supports Meta-specific single-ad naming and ad-level tracking.

You can explicitly set the created ad’s name (instead of inheriting name), and attach pixel measurement + URL tags regardless of optimization goal.

New fields:
adName (Meta only) — overrides the default ad name (default was name)
tracking.pixelId (Meta only) — attaches pixel measurement via ad tracking_specs
tracking.urlTags (Meta only) — sets ad url_tags as [{ key, value }]

View documentation
2
Webhooks now support external post events for posts created/updated/deleted directly on the platform (not published via Zernio).

Subscribe by including these in events when calling POST /v1/webhooks/settings or PUT /v1/webhooks/settings:
post.external.created
post.external.updated
post.external.deleted

Payload uses WebhookPayloadExternalPost with post = ExternalPostWebhookPost (includes post.id = platform-native ID, post.source = external; on post.external.deleted, post.deletedAt is populated). Events are sync-detected (~hourly), not real-time.

View documentation
2
GET /v1/comment-automations now returns stats.trackedSends for each automation.

Use trackedSends as the CTR denominator for tracked links (divide stats.linkClicks by stats.trackedSends, not stats.dmsSent). It may lag dmsSent for automations that predate click tracking.

New field:
stats.trackedSends - DMs sent with a trackable (wrapped) link

View documentation
2🔥1
Google Ads now supports conversion adjustments via POST /v1/ads/conversions/adjustments.

You can retract, restate value, or enhance an already-uploaded conversion (Google only; other platforms return 405). Partial failure is supported (check adjustmentsFailed / failures[]).

Send:
accountId (must be a googleads account)
destinationId (conversion action resource name)
adjustments[] with adjustmentType = RETRACTION | RESTATEMENT | ENHANCEMENT

Per adjustment:
• Identify the original conversion with orderId (required for ENHANCEMENT) or gclid + conversionTime
adjustmentTime (unix seconds)
restatementValue + currency (for RESTATEMENT)
user.email/user.phone (+ optional userAgent) for ENHANCEMENT

Also: Meta standalone ad creation adds goal = lead_conversion on POST /v1/ads/create (and Ad.goal) for website pixel lead optimization (distinct from lead_generation instant forms).

View documentation
1
Meta ads created via POST /v1/ads/create now support explicitly setting the ad set optimization goal via optimizationGoal.

This lets you override the default optimization derived from goal (e.g. traffic defaulting to LINK_CLICKS) and pass a Meta-native optimization_goal value directly; Meta will validate and reject incompatible combinations.

Use optimizationGoal (Meta only), e.g. LANDING_PAGE_VIEWS, LINK_CLICKS, REACH, IMPRESSIONS, OFFSITE_CONVERSIONS, THRUPLAY, LEAD_GENERATION.

View documentation
3
Meta ads tracking-tag updates are now simpler on PATCH /v1/ads/{adId}/tracking-tags: you can send urlTags alone and Zernio will preserve the existing creative verbatim while rebuilding/repointing the ad.

This removes the previous requirement to provide the full Meta creative payload just to add/update click-URL tags. For creatives where Meta strips object_story_spec (e.g. share/page-post/dark/asset_feed), you may still get 422 and need to include creative explicitly.

Key fields:
urlTags (Meta)
creative (Meta, optional; required only when preservation isn’t possible)
trackingUrlTemplate, finalUrlSuffix (Google)
dynamicValueParameters, customValueParameters (LinkedIn)

View documentation
❤‍🔥1
Meta Lead Gen ads created via POST /v1/ads/create now support per-placement creative using placementAssets.

You can pin different image/video assets to placement groups (e.g. Stories/Reels vs Feed) while still attaching a Lead Gen form via leadGenFormId.

Use:
goal=lead_generation
leadGenFormId
placementAssets with defaultImageUrl or defaultVideoUrl + rules[].placements

Note: dynamicCreative is still not compatible with goal=lead_generation.

View documentation
1