Zernio | Developer News
693 subscribers
1 photo
1 video
487 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
Invite creation now supports a dedicated read-only role via role on POST /v1/invite/tokens.

Use role to control access level:
member
billing_admin
viewer - read-only (no publish/edit/delete/connect)

The readOnly field is now deprecated. If readOnly=true, the invite is created with role=viewer (and it can’t be combined with role=billing_admin).

View documentation
1
POST /v1/ads/create now supports Meta link descriptions via a new description field.

This lets you set the secondary link text on Facebook/Instagram ads instead of relying on Meta scraping OpenGraph data.

Use:
description (Meta only) — applies to legacy + attach + placementAssets
creatives[].description (Meta multi-creative) — per-ad override; falls back to top-level description

Also clarified for Meta lead ads: when using adSetId (attach shape) into a lead ad set, you must pass leadGenFormId on every attached ad.

View documentation
1
Meta video ads created via POST /v1/ads/create no longer require a thumbnail.

You can now omit video.thumbnailUrl and Zernio/Meta will auto-generate the poster frame using Meta’s preferred video thumbnail (same candidates as Ads Manager). Provide it only if you need an exact poster frame.

Applies to:
• Top-level video (legacy + attach shapes): video.url required, video.thumbnailUrl optional
creatives[].video (Meta multi-creative): video.url required, video.thumbnailUrl optional

View documentation
1
New endpoint: GET /v1/accounts/{accountId}/gmb-attribute-metadata.

You can now fetch Google Business Profile attribute metadata (valid attribute names, value types, and allowed enum values) before reading/writing via gmb-attributes.

Query modes (mutually exclusive):
• Location mode: locationId (or omit to use the account’s stored selectedLocationId)
• Category mode: categoryName (must start with categories/) + regionCode (optional languageCode)

Pagination: pageSize (1–200) and pageToken.

Response includes attributeMetadata[] with parent, valueType (e.g. BOOL, ENUM, URL, REPEATED_ENUM), displayName, repeatable, deprecated, and valueMetadata[] (enum options), plus nextPageToken when more results are available.

View documentation
2
WhatsApp phone number purchase now supports idempotent retries and duplicate-purchase protection on POST /v1/whatsapp/phone-numbers/purchase.

Use purchaseIntentId (optional) as an idempotency key: retry with the same value and, if a number was already bought, the API returns { status: "already_purchased", numberId, phoneNumber } instead of provisioning a second number.

A second purchase within 10 minutes is now rejected with 409 and code PURCHASE_VELOCITY. To confirm an intentional additional purchase (e.g. bulk provisioning), set allowMultiple to true.

View documentation
1
GET /v1/whatsapp/phone-numbers now also returns connected (bring-your-own) WhatsApp numbers in a separate connected array.

This lets you list Embedded Signup–linked WABA numbers alongside purchased numbers (which remain in numbers). Connected numbers aren’t provisioned or billed by Zernio and use accountId for messaging/inbox endpoints.

New response field: connected[] with:
accountId
phoneNumber
displayName
profileId
connectedAt

Included only on the default view and when status=active.

View documentation
2
Meta catalog ads are now supported via goal = catalog_sales on POST /v1/ads/create.

This lets you create Advantage+ catalog ads (e.g. vehicle inventory) using a Meta product catalog + product set; Meta renders the visuals per catalog item (no imageUrl/video sent).

Discover inputs with:
GET /v1/ads/catalogs (accountId, adAccountId)
GET /v1/ads/catalogs/{catalogId}/product-sets (catalogId, accountId)

Create the ad with:
goal: catalog_sales
promotedObject.productSetId
promotedObject.pixelId
promotedObject.customEventType

Notes: catalog_sales is single-shape only (no creatives[], adSetId, dynamicCreative, or placementAssets).

View documentation
1
WhatsApp now supports managing your blocklist via /v1/whatsapp/block-users.

You can list blocked users, block up to 1,000 users per request, and unblock in batches (per-user failures are returned without failing the whole request).

New endpoints:
GET /v1/whatsapp/block-users with accountId, optional limit, after (cursor pagination via nextCursor)
POST /v1/whatsapp/block-users body: accountId, users (1..1000)
DELETE /v1/whatsapp/block-users body: accountId, users (1..1000)

WhatsApp interactive messages now also support location requests in POST /v1/inbox/conversations/{conversationId}/messages via interactive.type = location_request_message (and action can be omitted; defaults to {"name":"send_location"}).

View documentation
1
POST /v1/whatsapp/calls now supports sending the WhatsApp call-consent prompt via a new optional action parameter.

Use this to request consumer permission before placing a Business-Initiated Call; the consumer must tap Allow before start_call is permitted (Meta rate-limits prompts and requires an open 24h service window).

Set:
action: send_call_permission_request (omit action to place a call)
bodyText: optional text shown with the consent prompt (max 1024 chars)

View documentation
1
WhatsApp adds blocked-status lookup for a single contact via GET /v1/whatsapp/block-users/status.

This returns a definitive blocked state using Zernio’s blocklist mirror (kept in sync by block/unblock; first call per account may backfill from Meta’s full list).

Required query params:
accountId
user (consumer wa_id or E.164 phone; leading + optional)

Response 200:
blocked (boolean)

View documentation
1
GET /v1/analytics/daily-metrics now supports engagement attribution via a new query param attribution.

This lets you choose whether daily totals are attributed to the post’s publish date or bucketed by the day engagement was actually received (engagement-over-time).

Use attribution:
publish (default) — attribute each post’s lifetime total to its publish date
received — attribute per-day engagement increases to the day they occurred

View documentation
1
YouTube analytics now supports video retention curves via GET /v1/analytics/youtube/video-retention.

This returns an aggregated (not per-day) audience retention curve for a single video, plus durationSeconds so you can render the curve on a time axis.

Call with:
videoId
accountId
• optional startDate, endDate

Response highlights:
retentionCurve[] points with elapsedVideoTimeRatio, audienceWatchRatio (can be > 1), relativeRetentionPerformance
• empty retentionCurve for low-view / not-yet-processed videos (2–3 day delay)

Requires yt-analytics.readonly; if missing you may get 412 with code=youtube_analytics_scope_missing.

Also added to GET /v1/analytics/youtube/daily-views responses:
• top-level durationSeconds
• per-day averageViewPercentage (can exceed 100; don’t clamp client-side)

View documentation
1
WhatsApp interactive messages now support voice call buttons when sending inbox messages via POST /v1/inbox/conversations/{conversationId}/messages.

This lets you render WhatsApp’s native “call” CTA in-chat (requires WhatsApp Business Calling enabled on the sending number). Optional attribution data can be echoed back on the calls webhook.

Use interactive.type = voice_call and interactive.action.name = voice_call. Optional interactive.action.parameters:
display_text
ttl_minutes
payload

Also, GET /v1/whatsapp/calling now returns callDeepLink (nullable) for the public https://wa.me/call/<number> deep link when calling is enabled.

View documentation
1
Google campaign objects now include advertisingChannelType in AdCampaign and AdTreeCampaign.

This exposes the raw Google Ads campaign.advertising_channel_type so you can distinguish campaign serving surfaces (e.g. Search vs Performance Max) when syncing/reporting.

New field:
advertisingChannelType (string, nullable) — Google-only (e.g. SEARCH, PERFORMANCE_MAX, VIDEO, DEMAND_GEN, DISPLAY, SHOPPING)

View documentation
1
Broadcast recipient results now include a plain-language failure reason via errorExplanation on GET /v1/broadcasts/{broadcastId}/recipients.

This helps you interpret WhatsApp errorCode values (e.g. opt-out / re-engagement required) without maintaining your own mapping.

Use:
recipients[].errorCode (integer, nullable)
recipients[].errorExplanation (string, nullable; null if unmapped — fall back to error)

Webhooks for delivery status now also include error.explanation in WebhookPayloadMessageDeliveryStatus (populated on event=message.failed).

View documentation
1
GET /v1/connect/{platform}/ads now supports ad sync scoping via adAccountId/adAccountIds across more ads platforms (not just Meta).

You can limit discovery/sync to specific ad accounts for facebook/instagram (Meta), linkedin, googleads, and twitter. Changing the scope will also remove already-synced ads from any de-scoped ad accounts.

Use:
adAccountId - single ad account id (platform-specific format)
adAccountIds - multiple ids (repeat param or comma-separated)

Notes:
tiktok ignores these params (advertisers are scoped during OAuth)
pinterest ignores these params (no ads discovery)
• Meta ids (act_<digits>) are validated against the connected token; unreachable ids return 400
• Omitting both adAccountId and adAccountIds keeps the previously persisted scope unchanged

View documentation
GET /v1/whatsapp/phone-numbers/kyc now returns a human-readable summary when a reusable KYC verification is available.

When reusable.available is true, you can show what verification is already on file (best-effort; may be empty if provider lookup fails) and let users skip re-entering the form.

New field: reusable.details (array of { label, value }) alongside reusable.fromPhoneNumber.

View documentation
1
WhatsApp regulated-number KYC reuse now supports choosing which prior approved verification to reuse.

GET /v1/whatsapp/phone-numbers/kyc adds reusable.options (newest first), listing all approved verifications (each with fromPhoneNumber + details).

When submitting with reuse, POST /v1/whatsapp/phone-numbers/kyc adds reuseFrom to select the verification to reuse (set to reusable.options[].fromPhoneNumber). Omit reuseFrom to use the newest; no match returns 409.

View documentation
1
POST /v1/accounts/{accountId}/conversion-destinations now supports creating conversion destinations for Google Ads in addition to LinkedIn.

You can create a Google Ads conversion action (created as UPLOAD_CLICKS for offline uploads). Standard event names are mapped automatically, and actions default to secondary unless you opt in.

Key Google Ads fields:
countingType: MANY_PER_CLICK | ONE_PER_CLICK
primaryForGoal: true | false (default false)

Notes:
accountId can now be linkedinads or googleads
• Creation is not idempotent — retries can create duplicates
• 201 response platform now includes linkedinads | googleads

View documentation
1
Google Ads conversion destination creation via POST /v1/accounts/{accountId}/conversion-destinations is now effectively idempotent by name.

If a conversion action with the same name already exists, the API will reuse it and return the same response as a fresh create. If the same name is used with a different type (category), the API now returns 409 with error code IDEMPOTENCY_CONFLICT.

Key fields:
name
type

New response:
409 (Google Ads only) — IDEMPOTENCY_CONFLICT

View documentation
1
POST /v1/ads/conversions now supports TikTok conversions (platform tiktokads).

You can now relay OFFLINE conversion events to TikTok via the Offline Events API. Use destinationId as the TikTok Offline Event Set ID, and note each event must include an email or phone.

Key details:
accountId now accepts: metaads, googleads, linkedinads, tiktokads
• Response platform enum now includes tiktokads

GET /v1/accounts/{accountId}/conversion-destinations also now supports tiktokads (platform enum includes tiktokads).

GET /v1/ads/tree adds campaignId (platform campaign id) to restrict the tree to a single campaign, independent of pagination.

View documentation
3