Zernio | Developer News
682 subscribers
1 photo
1 video
478 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
Instagram and Facebook Inbox now include pre-connect DM history replay in GET /v1/inbox/conversations and GET /v1/inbox/conversations/{conversationId}/messages.

When an IG/FB account is connected, Zernio replays existing Meta DM history in the background so older threads can appear in listings; if you sync into your own store, you should re-sweep rather than relying on a single pass at connect time.

Key behavior:
GET /v1/inbox/conversations: up to 500 conversations per account are replayed; replayed threads keep their original lastMessageAt/updatedTime so they sort into date order (not bumped to the top)
• Replayed history emits no webhooks and is stored as read (does not affect unreadCount)
GET /v1/inbox/conversations/{conversationId}/messages: replay includes the 500 most recent messages per conversation; older messages beyond that are not retrievable

View documentation
New Google Ads keyword research endpoints are available, and GET /v1/ads/insights now supports Google Ads queries.

You can now pull Keyword Planner data via:
POST /v1/ads/keywords/ideas (generate ideas from seedKeywords and/or seedUrl)
POST /v1/ads/keywords/historical-metrics (metrics for up to keywords = 1000)

Key request fields:
accountId (required)
customerId (optional; needed if the connection has several Google Ads accounts)
countries (optional; omitted = worldwide)
languageConstantId (default 1000)
network: GOOGLE_SEARCH | GOOGLE_SEARCH_AND_PARTNERS

GET /v1/ads/insights now routes by platform:
• Meta: use objectId (+ fields/breakdowns/filtering as before)
• Google Ads: use query (GAQL SELECT), with paging via pageToken and paging.nextPageToken (fixed 10,000 rows/page)

Note: Google responses return raw rows (camelCase) with int64 counters encoded as strings; bid/CPC values are in micros.

View documentation
POST /v1/inbox/conversations/{conversationId}/messages now returns more detailed send failures in 400 responses.

You can distinguish missing-recipient cases and, for Instagram/Facebook, get Meta’s diagnostic fields to debug rejected sends.

New 400 fields:
code: PLATFORM_LIMITATION | MISSING_PARTICIPANT
platformError (Instagram/Facebook only): code, subcode, fbtraceId, type

View documentation
POST /v1/posts/sync-external now supports LinkedIn personal profiles.

Because LinkedIn personal profiles don’t have a listing API, you must provide url to import a single post authored by the connected member (works even for posts published before the account was connected).

Use accountId + url (required for LinkedIn personal), where url can be:
linkedin.com/posts/…
linkedin.com/feed/update/urn:li:activity:…
urn:li:share:… / urn:li:ugcPost:…

Imported LinkedIn personal posts return analytics (impressions, reach, reactions, comments, reshares, saves) but no content/media.

View documentation
Instagram user tagging behavior has changed for platformSpecificData.instagram.userTags.

userTags items now require only username (previously username + x + y were required). Tag handling now depends on media type:
• Photos: x/y are required; photo tags without valid coordinates are skipped
• Reels/videos: username-only tags; any x/y provided are ignored
• Stories: x/y are optional

Carousel targeting still uses mediaIndex (defaults to 0); out-of-range indices are ignored.

View documentation
Phone number purchases can now be auto-assigned to a different profile when the requested profileId already has a number.

Send profileId as the preferred profile, but the API may assign the number to the next free profile (or create one) and will return the actual assignment.

Check the assigned profile in:
phoneNumber.profileId (when a number is provisioned)
profileId in the { status: "already_purchased" } response when using purchaseIntentId

View documentation
POST /v1/media/presign now supports generating presigned upload URLs for audio files.

You can upload audio by setting contentType to one of: audio/mpeg, audio/mp4, audio/aac, audio/ogg, audio/wav, audio/webm, audio/x-m4a.

View documentation
Facebook analytics now supports per-post monetization earnings via GET /v1/analytics/facebook/post-earnings.

This returns lifetime cumulative earnings for a single post, read live from Meta on each request (no date range supported).

Required params:
accountId
postId (e.g. {pageId}_{postId} or bare Reels video ID)

Optional:
metrics = content_monetization_earnings, monetization_approximate_earnings (defaults to both)

Notes:
since/until/period/metricType/breakdown are rejected with 400 (lifetime only).
• Money metrics include unit (micro_amount | unspecified) and currency (string | null), and are never rescaled.
• Metrics Meta can’t serve are omitted from metrics and listed in unavailableMetrics (HTTP 200).

Also: GET /v1/analytics/facebook/page-insights now accepts monetization metrics (content_monetization_earnings, monetization_approximate_earnings) and may return unavailableMetrics with the same omit-vs-zero behavior.

View documentation
Meta ads reporting now supports filtering by Facebook Page via pageId on ads, campaigns, and the campaign tree.

This lets you scope results and rolled-up metrics to ads whose creative is backed by a specific Page (useful when one Meta ad account serves multiple Pages).

New query param:
pageId (Meta only)

Available on:
GET /v1/ads
GET /v1/ads/campaigns
GET /v1/ads/tree

Matches against ad.creative.pageId (may be null for non-Meta ads and rare IG-only creatives).

View documentation
Meta ad URL tags now preserve Meta dynamic macros in tracking parameters.

When setting Meta urlTags, macros like {{ad.id}}, {{campaign.id}}, {{placement}} are sent through unescaped so Meta can expand them; all other characters are percent-encoded.

Applies to:
PATCH /v1/ads/{adId}/tracking-tags via urlTags
POST /v1/ads/boost via tracking.urlTags
POST /v1/ads/create via tracking.urlTags

View documentation
Rate limit guidance has been updated: the per-account velocity limit referenced in 429 responses is now 25 posts/hour per account (was 15) for:
POST /v1/posts
POST /v1/posts/{postId}/retry

If you throttle based on the error text for 429, update your assumptions to match the new 25 posts/hour limit.

View documentation
Facebook posts now support large-text background presets via textFormatPresetId in FacebookPlatformData.

This lets you render a text-only feed post as large text on a colored background using Meta’s text_format_preset_id.

Use textFormatPresetId (numeric string, pattern ^\d+$). Constraints:
• Text-only feed posts only: request is rejected if mediaItems or carouselCards are present
• Not allowed with contentType story or reel
content must be non-empty and ≤ 130 chars (otherwise rejected)
• If a URL is present in content, no link preview is attached while a preset is set

View documentation
WhatsApp Calling endpoints now return caller ID details for tel: forwards via callerIdMode (and verification status on GET).

This helps you understand whether the PSTN forward-leg will present the business number or a Zernio platform number when caller ID isn’t verified.

New response fields:
POST /v1/phone-numbers/{id}/whatsapp/calling and POST /v1/whatsapp/phone-numbers/{id}/calling: callerIdMode = business | platform
GET /v1/phone-numbers/{id}/whatsapp/calling: callerIdMode = business | platform, callerIdVerified (boolean)

Also clarified: 400 can be returned if forwardTo is set to the number itself.

View documentation
WhatsApp Calling now supports caller-ID verification for customer-brought (BYO) phone numbers, so tel: call forwards can present the business number as caller ID.

Start (or resend) a verification code via POST /v1/phone-numbers/{id}/whatsapp/caller-id-verification with optional method: sms | call.

Confirm the code via POST /v1/phone-numbers/{id}/whatsapp/caller-id-verification/verify with required code.

GET /v1/whatsapp/calling now returns:
callerIdMode: business | platform
callerIdVerified: true | false

View documentation
Bulk contact import (POST /v1/contacts/bulk) now validates and normalizes phone identifiers for phone platforms.

When platform is whatsapp or sms, each contact’s platformIdentifier is normalized to digits; values that aren’t phone-shaped are rejected per contact and reported in errors[] (not imported).

Check your handling of errors[] in the 200 response (now returned as strings describing per-contact failures).

View documentation
WhatsApp Calling config now supports a call duration cap and forwarded caller ID control on calling endpoints.

You can limit forwarded call length (to prevent dead-air billing) and, for SIP forwards, choose whether the destination sees the business number or the end-caller.

New fields:
maxCallDurationSeconds (request/response) — 30..14400 or null (no cap / clear cap)
forwardCallerId (request/response) — business | caller

Available on:
GET /v1/whatsapp/calling
GET /v1/phone-numbers/{id}/whatsapp/calling
POST/PATCH /v1/phone-numbers/{id}/whatsapp/calling (and the deprecated alias /v1/whatsapp/phone-numbers/{id}/calling)

View documentation
Facebook text background posts via textFormatPresetId no longer reject long captions.

Previously, requests were rejected with 400 when content exceeded ~130 characters. Now, length is not rejected; Facebook may publish and return a warning instead.

Use textFormatPresetId (numeric string, ^\d+$) for Pages + text-only feed posts. Requests are still rejected with 400 if mediaItems or carouselCards are present, if contentType is story or reel, or if content is empty.

View documentation
WhatsApp now supports re-registering a connected number on Meta Cloud API, and the credentials connect flow can include a 2-step verification PIN.

If a number has its own 2-step PIN, Meta can reject registration (error 133005) and sends may fail with misleading permission errors. You can now pass the PIN during connect, or re-run registration later.

Use:
POST /v1/connect/whatsapp/credentials with optional pin (6 digits, ^\d{6}$)
• New: POST /v1/accounts/{accountId}/whatsapp/register with optional pin

Connect response may include registrationWarning when the account was created but Cloud API registration was rejected (number can’t send until resolved).

Inbox comments endpoints now also return platform/upstream error responses you may want to handle: 403 (platform permission), 429 (rate limited), 502 (upstream platform error) on GET/POST/DELETE /v1/inbox/comments/{postId}.

View documentation
You can now manage OAuth connected apps for the authenticated user: list authorized clients and revoke their access.

List connected apps with GET /v1/me/connected-apps. Each item includes clientId, clientName, redirectHost, scopes, authorizedAt, lastUsedAt, tokenCount.

Revoke an app with DELETE /v1/me/connected-apps/{clientId} (idempotent). Response includes revoked, revokedTokens, invalidatedCodes.

Auth note: requires a session or full-scope API key; profile-scoped API keys and OAuth access tokens get 403 (insufficient_permissions).

View documentation
Create/duplicate ads endpoints now support safe retries via an Idempotency-Key header.

This prevents accidental duplicate campaigns/ad sets/ads when your client retries after timeouts or network errors.

Now supported on:
POST /v1/ads/campaigns
POST /v1/ads/campaigns/{campaignId}/duplicate
POST /v1/ads/ad-sets/{adSetId}/duplicate
POST /v1/ads/{adId}/duplicate

Behavior:
• same Idempotency-Key + same body → replay original 2xx response
• same key + different body → 422
• key still processing → 409

Also: metrics conversions is now a number (can be fractional) in GET /v1/ads/timeline and the AdMetrics schema (attribution splitting + Google modeled conversions).

View documentation
GET /v1/accounts/{accountId}/linkedin-mentions now returns 403 when LinkedIn blocks person-mention lookup due to missing company page posting privileges.

This lets you distinguish “insufficient LinkedIn org/page role” from invalid input (400) or not found (404), and show a clearer remediation message.

New response:
403 - account has no organization role that can resolve person mentions (error message indicates needing Admin/Content Admin on a page, or mentioning an organization instead)

View documentation