Zernio | Developer News
688 subscribers
1 photo
1 video
484 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
Meta campaign updates now support a lifetime spend cap via platformSpecificData.spendCap on PUT /v1/ads/campaigns/{campaignId}.

This lets you set or remove a campaign-level spend cap without recreating the campaign.

Use:
platformSpecificData.spendCap = number (sets cap)
platformSpecificData.spendCap = null (removes cap; Meta rejects 0)

Meta ad set updates now accept post-launch delivery settings via platformSpecificData on PUT /v1/ads/ad-sets/{adSetId}.

Set any of:
platformSpecificData.optimizationGoal
platformSpecificData.billingEvent
platformSpecificData.startDate, platformSpecificData.endDate
platformSpecificData.promotedObject (e.g. pixelId, customEventType, pageId, applicationId, objectStoreUrl, customConversionId, productCatalogId, productSetId)

Also added: billingEvent (Meta only) on POST /v1/ads/create to explicitly set the ad set’s billing event (defaults to IMPRESSIONS).

View documentation
Google Business reviews now include attached photos in review responses.

You can display/download reviewer-uploaded images and know how many photos are attached per review.

Added fields:
GET /v1/accounts/{accountId}/gmb-reviewsreviews[].photoCount, reviews[].photos[] (each item: url)
GET /v1/inbox/reviewsdata[].photos[] (Google Business only; each item: url)

Notes: photoCount counts photos only (videos not counted). For non-Google platforms, photos is always an empty array.

View documentation
Google Business Profiles: you can now assign a GBP location to a different profile by reusing an existing OAuth grant (no browser re-auth).

Use POST /v1/accounts/{accountId}/gmb-locations/assign with:
profileId (target profile)
selectedLocationId (e.g. locations/123)
googleAccountId (optional, recommended for accounts with many locations)
Returns 409 if the target profile already has a Google Business connection.

Phone number purchasing now supports selecting a number type.

On POST /v1/phone-numbers/purchase you can pass numberType: local | mobile | national | toll_free. Availability/KYC can vary by (country, type).

Country/type discovery updates:
GET /v1/phone-numbers/countries now includes inStock and types[] (per-type monthlyCents, needsKyc, whatsappAvailable, smsAvailable, callsAvailable, inStock)
GET /v1/phone-numbers/availability adds optional numberType
GET /v1/phone-numbers/kyc adds optional numberType

Facebook connect flow: POST /v1/connect/facebook/select-page can now return 409 with code RECONNECT_ACCOUNT_MISMATCH when a force=true token-recovery re-auth lands on a different user/page than the existing connection.

View documentation
New Meta Ads insights endpoints are available: GET /v1/ads/insights, POST /v1/ads/insights/reports, GET /v1/ads/insights/reports/{reportRunId}.

You can now run a flexible live insights query that forwards your chosen Meta Graph parameters (fields/breakdowns/filtering) and returns rows in Meta’s raw shape; use the async report flow for long ranges or large accounts.

Sync query: GET /v1/ads/insights with accountId, objectId, optional level (ad/adset/campaign/account), fields, breakdowns, filtering, datePreset or fromDate+toDate, timeIncrement, limit, after.

Async flow:
• Submit: POST /v1/ads/insights/reports (body includes accountId, objectId, optional level, fields, breakdowns, filtering, datePreset or fromDate/toDate, timeIncrement (1-90 | monthly | all_days)) → returns reportRunId
• Poll: GET /v1/ads/insights/reports/{reportRunId} with accountId, limit, after → returns status and percentCompletion; when status is Job Completed, includes data + paging.

Meta only (facebook/instagram). Invalid field/breakdown combos return 400 with Meta’s error message.

View documentation
❤‍🔥1
TikTok conversion ads created via POST /v1/ads/create now accept TikTok Events Manager event names in promotedObject.customEventType (auto-resolved to the underlying optimization_event code).

This makes it easier to configure goal=conversions without manually mapping to TikTok’s internal codes; note that ON_WEB_ORDER is now deprecated.

Use promotedObject.customEventType with one of:
SHOPPING, ON_WEB_CART, INITIATE_ORDER, FORM, ON_WEB_REGISTER, ON_WEB_DETAIL

Applies to TikTok only; promotedObject.pixelId is still required for goal=conversions.

View documentation
1
POST /v1/ads/create now supports more TikTok controls and targeting.

You can create TikTok ads/campaigns in a paused state and use additional geo targeting fields for TikTok.

Key changes:
status now applies to Meta and TikTok: ACTIVE | PAUSED (TikTok pauses campaign > ad group > ad)
• Geo targeting fields now support TikTok: cities, regions, metros

GET /v1/ads/targeting/search: TikTok geo searches now return mixed levels in one list (type can be country | region | city | district | metro), and geoType is not applied for TikTok results.

View documentation
1🔥1
POST /v1/inbox/comments/{postId} now supports attaching an image when replying on Facebook via attachmentUrl.

This lets you publish a photo comment alongside the text reply. The image URL must be publicly accessible so Meta can fetch it.

New request field:
attachmentUrl (uri) — Facebook only

If attachmentUrl is sent for non-Facebook platforms, the API now returns 400 (e.g. code PLATFORM_NOT_SUPPORTED).

View documentation
Google Business batch reviews now supports server-side sorting via orderBy on POST /v1/accounts/{accountId}/gmb-reviews/batch.

This lets you fetch newest-updated reviews first (default) and stop paginating earlier when polling for recent changes.

Use orderBy:
updateTime desc (default)
rating
rating desc

Also note: locationNames is now capped at maxItems: 50 per request (chunk larger sets).

Responses now clarify attribution: each locationReviews[].name is the LOCATION resource name (not the review resource name), and review includes review.name (full review resource name) plus reviewMediaItems (photos/videos).

Inbox reviews (GET /v1/inbox/reviews) now includes Google Business location attribution fields: locationId (bare id) and locationName (display name).

View documentation
Meta insights now supports action-level segmentation and attribution controls on both the sync and async insights APIs.

You can segment actions[] and control attribution windows/reporting time without changing endpoints.

New on GET /v1/ads/insights:
actionBreakdowns
actionAttributionWindows
actionReportTime
useUnifiedAttributionSetting

New on POST /v1/ads/insights/reports:
actionBreakdowns
actionAttributionWindows (array of strings)
actionReportTime
useUnifiedAttributionSetting

Meta ad creation also adds hand-built carousels via carouselCards on POST /v1/ads/create (2–10 cards, deterministic order).

View documentation
2
New Meta Ads capabilities are available: ad previews, click-to-message ads, and click-to-call ads.

You can now render embeddable preview iframes before creating an ad via POST /v1/ads/preview (provide exactly one of existingCreativeId or creativeSpec) or for an existing ad via GET /v1/ads/{adId}/preview. Use formats (Meta ad_format values, max 10) to control placements.

Click-to-message ads are now unified under POST /v1/ads/messaging with destination:
whatsapp
messenger
instagram_direct

Click-to-call ads are supported via POST /v1/ads/call using phoneNumber (E.164) and linkUrl.

POST /v1/ads/ctwa is now deprecated; use POST /v1/ads/messaging with destination: whatsapp (the old endpoint remains for back-compat).

View documentation
New Meta Ads endpoints are available for live reads, auditing, studies, finances, and asset upload.

You can now:
• Read a live Meta ad set (incl. learning phase) via GET /v1/ads/ad-sets/{adSetId} with accountId and optional fields (default includes learning_stage_info).
• Fetch account audit/activity log via GET /v1/ads/activity using accountId, adAccountId, optional since/until, optional objectId (client-side filter), plus paging limit/after.
• List A/B tests & lift studies via GET /v1/ads/studies with accountId, adAccountId, optional fields, and paging limit/after.
• Read ad account finances via GET /v1/ads/accounts/finance (balance, amountSpent, spendCap, fundingSource).
• Upload ad images from base64 via POST /v1/ads/images with accountId, adAccountId, imageBase64 (optional filename); returns image.hash and image.url.

Also updated:
specialAdCategories now includes FINANCIAL_PRODUCTS_SERVICES and ONLINE_GAMBLING_AND_GAMING on POST /v1/ads/boost and POST /v1/ads/create.
callToAction enums expanded on POST /v1/ads/create (and Meta creatives[].callToAction) to include values like ADD_TO_CART, APPLY_NOW, BOOK_NOW, ORDER_NOW, INSTALL_MOBILE_APP, USE_APP (plus others).
POST /v1/ads/conversions: consent now affects Meta too — if adUserData or adPersonalization is DENIED, events are sent with Meta Limited Data Use (LDU); GRANTED (or omitted) uses default processing.

View documentation
Meta ads now support Reach & Frequency (RESERVED) buying via new R&F prediction + reservation endpoints.

You can request a quote (no spend, no entities created), reserve it to lock price/inventory, then create an ad using the reserved prediction.

New endpoints:
POST /v1/ads/rf-predictions (create quote; provide date range + exactly one of budgetAmount or reach)
GET /v1/ads/rf-predictions/{predictionId}
POST /v1/ads/rf-predictions/{predictionId}/reserve (returns a NEW RESERVED predictionId + expiresAt)
DELETE /v1/ads/rf-predictions/{predictionId} (cancel reservation)

POST /v1/ads/create adds:
buyingType: AUCTION | RESERVED
rfPredictionId (required when buyingType=RESERVED)

Notes: RESERVED uses the single-ad shape only (no creatives[], adSetId, existingCampaignId, or dynamicCreative). Budget/schedule/pricing come from the reservation; bid fields are ignored.

View documentation
SMS now supports alphanumeric sender IDs (e.g. ZERNIO) for one-way international texting.

Create/manage sender IDs via:
GET /v1/sms/sender-ids (includes workspace daily budget: budget.cap, budget.usedToday, budget.level, budget.pendingRequest)
POST /v1/sms/sender-ids with senderId (3–11 chars; letters/digits/spaces; at least one letter)
DELETE /v1/sms/sender-ids/{id}
POST /v1/sms/sender-ids/limit-request with requestedCap + reason

Sending: POST /v1/sms/messages now accepts from as either an SMS-enabled number or an approved sender ID.

Notes for sender IDs: text-only (no MMS), recipients can’t reply, and sends to US/CA/PR are blocked.

New responses to handle on POST /v1/sms/messages:
403 (gate: registration/MMS not supported/alpha to US-CA-PR)
429 (alphanumeric daily cap reached; code alpha_daily_limit_reached; resets midnight UTC)
404 now covers “no SMS-enabled number or sender ID matches from”.

View documentation
Meta Ads: new endpoints for campaign/creative management, duplication, and library access.

You can now create a standalone campaign shell, duplicate ad sets/ads via Meta native copy, manage creatives separately from ads, and query labels/images/creative library + budget schedules.

New endpoints:
• Create campaign (ODAX shell): POST /v1/ads/campaigns with goal (engagement, traffic, awareness, video_views, lead_generation, lead_conversion, job_applicants, conversions, app_promotion, catalog_sales), optional CBO via budgetAmount + budgetType (daily|lifetime), status (ACTIVE|PAUSED)
• Duplicate ad set: POST /v1/ads/ad-sets/{adSetId}/duplicate with deepCopy, campaignId, statusOption (ACTIVE|PAUSED|INHERITED_FROM_SOURCE), syncAfter
• Duplicate ad: POST /v1/ads/{adId}/duplicate with adSetId, statusOption (ACTIVE|PAUSED|INHERITED_FROM_SOURCE), syncAfter
• Creative library + CRUD: GET /v1/ads/creatives, POST /v1/ads/creatives (use imageUrl or imageHash or carouselCards), GET /v1/ads/creatives/{creativeId}, PUT /v1/ads/creatives/{creativeId} (rename via name), DELETE /v1/ads/creatives/{creativeId}
• Libraries/metadata: GET /v1/ads/images, GET /v1/ads/labels
• Budget schedules: GET /v1/ads/high-demand-periods (exactly one of campaignId or adSetId)

Audience updates expanded:
PUT /v1/ads/audiences/{audienceId} now supports updating platform audiences’ name/description (Meta only). spec is still allowed only for saved_targeting; sending spec for a platform audience returns 400. Non-Meta platform audience updates return 501.

View documentation
WhatsApp inbound attachments can now be downloaded via GET /v1/whatsapp/media/{mediaId}.

This streams the binary for a WhatsApp attachment referenced by attachments[].url in message.received webhooks and List messages.

Call it with:
mediaId (path) from attachments[].payload.id
accountId (query) = the WhatsApp account that received the media
Authorization: Bearer <your API key> (required; otherwise 401)

Important behavior:
• Download on receipt: WhatsApp media expires on Meta’s side (typically ~7 days). After expiry this endpoint returns 400 permanently (do not retry).

Removed endpoints:
GET /v1/sms/sender-ids, POST /v1/sms/sender-ids, POST /v1/sms/sender-ids/limit-request, DELETE /v1/sms/sender-ids/{id}
POST /v1/ads/campaigns
POST /v1/ads/ad-sets/{adSetId}/duplicate
POST /v1/ads/{adId}/duplicate
GET /v1/ads/labels
GET /v1/ads/high-demand-periods
GET/POST/GET/PUT/DELETE /v1/ads/creatives (and /v1/ads/creatives/{creativeId})
GET /v1/ads/images

Breaking change (SMS): POST /v1/sms/messages no longer supports alphanumeric sender IDs in from (now requires an SMS-enabled number).

View documentation
Discord: new member lookup + search endpoints, and guild member listing now fails fast when the Server Members Intent is missing.

You can now fetch a single member or prefix-search members without the privileged intent (useful when full listing is blocked).

New endpoints:
GET /v1/discord/guilds/{guildId}/members/{userId} (accountId)
GET /v1/discord/guilds/{guildId}/members/search (accountId, query, optional limit) — query is prefix-only

Breaking change:
GET /v1/discord/guilds/{guildId}/members now returns 403 if the Server Members Intent is not enabled (previously Discord could return an empty array).

SMS: alphanumeric Sender IDs are now supported.

Create and manage branded one-way SMS sender IDs (3–11 chars; letters/digits/spaces; at least one letter) and view the workspace-wide daily cap.

New endpoints:
GET /v1/sms/sender-ids (returns senderIds + budget with cap/usedToday/level/pendingRequest)
POST /v1/sms/sender-ids (senderId)
DELETE /v1/sms/sender-ids/{id}
POST /v1/sms/sender-ids/limit-request (requestedCap, reason)

Ads (Meta): new campaign/creative utilities + validate-only dry runs.

You can now create campaign shells, manage the creative library, duplicate ad sets/ads, and run a Meta validation pass without creating anything.

New endpoints:
POST /v1/ads/campaigns (standalone campaign)
POST /v1/ads/creatives, GET /v1/ads/creatives, GET /v1/ads/creatives/{creativeId}, PUT /v1/ads/creatives/{creativeId}, DELETE /v1/ads/creatives/{creativeId}
GET /v1/ads/images, GET /v1/ads/labels, GET /v1/ads/businesses, GET /v1/ads/high-demand-periods
POST /v1/ads/ad-sets/{adSetId}/duplicate, POST /v1/ads/{adId}/duplicate

New option on POST /v1/ads/create:
validateOnly: true (Meta only; single standalone shape only) — returns 200 with validation results instead of creating entities.

View documentation
Meta ads now support additional promoted-object fields, and some payloads are validated more strictly.

In POST /v1/ads/create, promotedObject adds:
offlineConversionDataSetId
whatsappPhoneNumber

In PUT /v1/ads/ad-sets/{adSetId}, platformSpecificData.promotedObject adds the same fields and now rejects unknown keys (additionalProperties: false), returning 400.

In POST /v1/ads/boost and POST /v1/ads/create, Meta adds specialAdCategoryCountry (array of 2-letter ISO codes). It requires specialAdCategories to be set (400 otherwise).

GET /v1/ads/audiences and POST /v1/ads/audiences add a new audience type value: meta_engagement.

View documentation
Meta ads updates:

You can now pass additional Meta promoted object fields, and some objects are now strictly validated (unknown keys will 400).

PUT /v1/ads/ad-sets/{adSetId}platformSpecificData.promotedObject now supports:
offlineConversionDataSetId, whatsappPhoneNumber
(unknown keys rejected; additionalProperties: false)

POST /v1/ads/createpromotedObject now supports:
offlineConversionDataSetId, whatsappPhoneNumber
(unknown keys rejected; additionalProperties: false)

POST /v1/ads/boost and POST /v1/ads/create now accept specialAdCategoryCountry (Meta only):
array of 2-letter ISO country codes; requires specialAdCategories to be set.

GET /v1/ads/audiences and POST /v1/ads/audiences add audience type value meta_engagement (Meta-only engagement audiences).

View documentation
Profile create/update now return 409 Conflict when the profile name is already taken.

This lets clients distinguish name collisions from generic validation errors and handle retries/renames cleanly.

New response:
POST /v1/profiles409 (code: profile_name_conflict)
PUT /v1/profiles/{profileId}409 (code: profile_name_conflict)

Several Ads read endpoints now also document 400 Bad Request for invalid query input:
GET /v1/ads400
GET /v1/ads/catalogs400
GET /v1/ads/catalogs/{catalogId}/product-sets400
GET /v1/ads/conversions/quality400

View documentation
WhatsApp template creation now supports carousel and limited time offer components in components on POST /v1/whatsapp/templates.

This lets you build richer MARKETING templates (multi-card carousels and offer labels/countdowns) using the same template creation endpoint.

New component types:
type=carousel with cards (2–10), each card components can include type=header, type=body, type=buttons
type=limited_time_offer with limited_time_offer.text (<=16 chars) and optional limited_time_offer.has_expiration

Phone number purchase adds wantsWhatsapp on POST /v1/phone-numbers/purchase (used when connectWhatsapp=false) to ensure the assigned number is WhatsApp-eligible by swapping it during purchase if needed.

View documentation
YouTube analytics endpoints now support returning provisional (not-yet-finalized) days when you set an explicit endDate up to today.

By default, endDate still resolves to the newest fully finalized day (~3-day delay). If you request into the delay window, the response indicates which days may still change.

Applies to:
GET /v1/analytics/youtube/daily-views
GET /v1/analytics/youtube/video-retention
GET /v1/analytics/youtube/demographics

New response field:
provisionalSince — first date in the returned range whose numbers are provisional and may be revised by YouTube.

View documentation
2