Meta Ads now supports Value Rule Sets (bid adjustments by audience segment) via new endpoints under
You can create/list/read/replace/delete value rule sets, then attach one to an ad set to increase/decrease bids for matching segments (rule order matters: first match wins).
New endpoints:
•
•
•
•
•
Attach/detach on ad sets (Meta only) via
• Attach/replace: send
• Detach: send
• Sending
Also supported on create (Meta only) via
• Attach to the new ad set with
•
Eligibility (Meta enforced): only ad sets on
View documentation
/v1/ads/value-rule-sets.You can create/list/read/replace/delete value rule sets, then attach one to an ad set to increase/decrease bids for matching segments (rule order matters: first match wins).
New endpoints:
•
GET /v1/ads/value-rule-sets•
POST /v1/ads/value-rule-sets•
GET /v1/ads/value-rule-sets/{valueRuleSetId}•
PUT /v1/ads/value-rule-sets/{valueRuleSetId} (full replace, not patch)•
DELETE /v1/ads/value-rule-sets/{valueRuleSetId}Attach/detach on ad sets (Meta only) via
PUT /v1/ads/ad-sets/{adSetId}:• Attach/replace: send
valueRuleSetId (optionally valueRulesApplied: true)• Detach: send
valueRulesApplied: false and omit valueRuleSetId• Sending
valueRulesApplied: false with valueRuleSetId returns 400 mutually_exclusive_fieldsAlso supported on create (Meta only) via
POST /v1/ads/create:• Attach to the new ad set with
valueRuleSetId (optional valueRulesApplied: true)•
valueRulesApplied: false is rejected on createEligibility (Meta enforced): only ad sets on
LOWEST_COST_WITHOUT_CAP or COST_CAP.View documentation
🔥1
POST
This lets you explicitly set the ad set
Set
View documentation
/v1/ads/boost now supports Meta-only optimization goal overrides via optimizationGoal.This lets you explicitly set the ad set
optimization_goal instead of relying on the default derived from goal, which can be useful when Meta requires a different optimization goal for the boost objective.Set
optimizationGoal to a Meta-compatible value for the objective derived from your goal (e.g. boost goal engagement maps to Meta objective OUTCOME_AWARENESS, so values like REACH, IMPRESSIONS, AD_RECALL_LIFT, or THRUPLAY-class are accepted; POST_ENGAGEMENT is rejected under that objective).View documentation
New endpoint
Use it to confirm a credential is valid before proceeding (e.g., when verifying an incoming token).
On
View documentation
GET /v1/auth/verify was added to validate a bearer credential (API key or OAuth access token) without calling a data endpoint.Use it to confirm a credential is valid before proceeding (e.g., when verifying an incoming token).
On
200 it returns valid, userId, authType (api_key | oauth | session), and scope (space-separated OAuth scopes; null for API keys). 401 if invalid.View documentation
Contacts listing now supports filtering by SocialAccount via
Use
New query param:
Also,
View documentation
accountId on GET /v1/contacts.Use
accountId to list contacts through their channel; when accountId is set, the profileId contact filter is not applied (a provided profileId is still access-checked and still scopes filters.tags).New query param:
accountIdAlso,
POST /v1/contacts 409 is now explicitly documented as: Duplicate channel. The platformIdentifier is already bound to a channel on this accountId.View documentation
OAuth connect now surfaces upstream token-exchange failures via a new
This helps distinguish platform-side rejections from internal errors; handle
Key response codes:
•
•
Lead form creation can now return
Key response code:
•
View documentation
502 response on POST /v1/connect/{platform}.This helps distinguish platform-side rejections from internal errors; handle
502 separately from 500 (the upstream 4xx is forwarded as platform_error).Key response codes:
•
502 - platform rejected token exchange (platform_error)•
500 - internal error while connecting the accountLead form creation can now return
422 on POST /v1/ads/lead-forms when Meta rejects the form (error code 3), typically because the Facebook Page hasn’t accepted the Lead Ads Terms.Key response code:
•
422 - Meta rejected lead form (often requires a Page admin to accept Lead Ads Terms)View documentation
Slack DMs are now supported in the Inbox API.
You can list eligible Slack workspace members (for a recipient picker) via
Key params:
•
•
Also updated:
View documentation
You can list eligible Slack workspace members (for a recipient picker) via
GET /v1/accounts/{accountId}/slack-members, then start a DM by passing the member id as participantId to POST /v1/inbox/conversations.Key params:
•
GET /v1/accounts/{accountId}/slack-members: query, limit•
POST /v1/inbox/conversations: participantId (Slack member id, e.g. U01ABCDEF)Also updated:
POST /v1/inbox/conversations now lists supported platforms as X/Twitter, Bluesky, Reddit, WhatsApp, SMS, and Slack.View documentation
❤1
WhatsApp now supports requesting a user’s contact info via interactive messages.
You can send a consent-based “share contact” prompt, and inbound replies include contact cards plus an origin flag so you can distinguish consented self-share vs address-book shares.
Send with
•
On
•
•
View documentation
You can send a consent-based “share contact” prompt, and inbound replies include contact cards plus an origin flag so you can distinguish consented self-share vs address-book shares.
Send with
interactive.type:•
request_contact_infoOn
message.received, check:•
metadata.contacts (array)•
metadata.contactsOrigin: contact_request | otherView documentation
🔥1
Non-draft updates to
If the resulting post violates platform rules (media requirements, platform-specific fields, etc.), the update will return
Also,
View documentation
PUT /v1/posts/{postId} now run the same per-platform validation as post creation.If the resulting post violates platform rules (media requirements, platform-specific fields, etc.), the update will return
400 instead of succeeding.Also,
PostUpdateResponse may now include warnings (array of strings).View documentation
👍1
Webhooks now support per-subscription event blocking via
This lets you prevent specific resource-group events (e.g. private messages) from ever being delivered to a webhook endpoint, even if those events are listed in
Use
• Create: include
• Update: sending
Restricted
New/expanded
•
•
•
Note: after updating a webhook denylist, already-queued events may still arrive for up to ~5 minutes.
View documentation
disabledResourceGroups on POST /v1/webhooks/settings and PUT /v1/webhooks/settings.This lets you prevent specific resource-group events (e.g. private messages) from ever being delivered to a webhook endpoint, even if those events are listed in
events. The same filtering applies to replay paths (test fire, redelivery, dead-letter requeue).Use
disabledResourceGroups (enum: publishing, engagement, messages, contacts, analytics, ads, telephony, accounts, billing, webhooks):• Create: include
disabledResourceGroups to opt out; omit or [] to receive everything in events• Update: sending
disabledResourceGroups replaces the denylist; send [] to clear; omit to leave unchangedRestricted
zrk_ keys: the key’s own disabled groups are always unioned into the subscription, so a restricted key can’t create or widen a subscription beyond itself.New/expanded
403 behavior (ResourceGroupForbidden) was added to:•
GET /v1/webhooks/settings•
DELETE /v1/webhooks/settings•
POST /v1/webhooks/test (note: webhook.test is in the webhooks group)Note: after updating a webhook denylist, already-queued events may still arrive for up to ~5 minutes.
View documentation
Meta multi-language ads now support per-locale destination URLs via
This lets you send users to different landing pages per language while keeping a single ad (shared social proof).
Set
View documentation
translations[].linkUrl on POST /v1/ads/create.This lets you send users to different landing pages per language while keeping a single ad (shared social proof).
Set
translations[].linkUrl to override the destination for that locale; when omitted it inherits the top-level linkUrl (which must be present if any locale uses translations[].linkUrl).View documentation
Incoming message.received webhooks now include quote-reply context via
This lets you correlate an inbound message that quotes/replies to an earlier message (WhatsApp/Instagram/Facebook Messenger) using the original message’s
New field:
•
Also clarified
• WhatsApp: pass
• Telegram: pass Telegram message ID
• Instagram: pass Meta
• Slack: threads the reply (uses
• Silently ignored on platforms without reply support (incl. Facebook Messenger)
View documentation
metadata.quotedMessageId.This lets you correlate an inbound message that quotes/replies to an earlier message (WhatsApp/Instagram/Facebook Messenger) using the original message’s
platformMessageId.New field:
•
metadata.quotedMessageId - platformMessageId of the message being quoted/replied toAlso clarified
POST /v1/inbox/conversations/{conversationId}/messages replyTo behavior:• WhatsApp: pass
wamid• Telegram: pass Telegram message ID
• Instagram: pass Meta
mid• Slack: threads the reply (uses
thread_ts)• Silently ignored on platforms without reply support (incl. Facebook Messenger)
View documentation
Meta ads creation now supports optimizing for pixel custom events via
Use this when you want
Set:
•
•
View documentation
promotedObject.customEventStr on POST /v1/ads/create.Use this when you want
goal=conversions (or lead_conversion) to optimize against a custom event name from Events Manager (instead of a standard event or a Custom Conversion).Set:
•
promotedObject.customEventType = OTHER•
promotedObject.customEventStr = <your_event_name>customEventStr is case-sensitive, and OTHER requires customEventStr (and vice versa).View documentation
LinkedIn connected accounts now include additional profile details in
This lets you read LinkedIn bio/headline and vanity slug info directly from the account object without extra lookups.
Key fields:
•
•
•
View documentation
SocialAccount.metadata.profileData (refreshed on each daily snapshot).This lets you read LinkedIn bio/headline and vanity slug info directly from the account object without extra lookups.
Key fields:
•
metadata.profileData.bio (nullable)•
metadata.profileData.extraData.vanityName (personal accounts)•
metadata.organizationInfo.vanityName (organization accounts)View documentation
Comment-to-DM automations now support more precise keyword matching and exclusions via
This lets you avoid accidental triggers (e.g., keyword
Use
•
New fields:
•
•
Available on
View documentation
matchMode=word, plus new fields excludeKeywords and typoTolerance.This lets you avoid accidental triggers (e.g., keyword
app no longer firing on happy) and optionally match close misspellings when using word-based matching.Use
matchMode:•
contains • word • exactNew fields:
•
excludeKeywords: string[] - comments matching these never trigger (compared using the same matchMode)•
typoTolerance: boolean - only with matchMode=wordAvailable on
POST /v1/comment-automations, PATCH /v1/comment-automations/{automationId}, and returned by GET endpoints.View documentation
Ads analytics now includes funnel step counts, an engagement breakdown, and cost per ThruPlay.
This makes it easier to report on Meta ads without parsing/deduping raw
New fields in
•
•
•
Also new in
•
View documentation
This makes it easier to report on Meta ads without parsing/deduping raw
actions keys (and avoids double-counting), and adds a direct cost metric for ThruPlays.New fields in
AdMetrics:•
costPerThruplay•
funnel (ref AdFunnelCounts): landingPageViews, contentViews, searches, wishlistAdds, cartAdds, checkoutsInitiated, paymentInfoAdds, purchases, leads, registrationsCompleted, appInstalls, messagingConversationsStarted, messagingFirstReplies•
engagementBreakdown (ref AdEngagementCounts): postEngagement, pageEngagement, reactions, comments, shares, saves, pageLikes, videoViews, linkClicksAlso new in
Ad:•
creativeType: carousel | video | document | image | nullView documentation
❤1
PATCH
You can switch an automation between comment-based and story-reply-based triggers; changing it will detach the automation from its currently bound post/story unless the same request sets a new binding.
Set
View documentation
/v1/comment-automations/{automationId} now accepts trigger to control what fires an automation.You can switch an automation between comment-based and story-reply-based triggers; changing it will detach the automation from its currently bound post/story unless the same request sets a new binding.
Set
trigger to: • comment • story_reply (Instagram only)View documentation
❤2
GET /v1/comment-automations/{automationId}/logs now returns non-matching comment diagnostics via a new misses object.Use
misses to see how many comments reached the automation but matched none of its keywords (and a few recent samples) to troubleshoot keyword/exclusion setups.New response fields:
•
misses.total•
misses.retentionDays•
misses.samples[]: commentText, commenterName, excludedBy, atRequest validation tightened:
•
limit now 1..200•
skip now >= 0• Invalid values may return
400 BadRequestView documentation
❤1
Instagram follow checks are now available via
This resolves the follow relationship (when Meta allows it) and returns
Key fields:
•
•
Comment-to-DM automations now support follower-based targeting + optional follow verification (Instagram only), and delayed sends.
New request fields on
•
•
•
•
Automation logs (
Webhook comment payloads now may include Instagram-only
View documentation
GET /v1/accounts/{accountId}/follow-status/{userId}.This resolves the follow relationship (when Meta allows it) and returns
isFollower (can be null when unknown) plus basic public counters; use refresh=true to bypass the short cache.Key fields:
•
isFollower: true | null (null = unknown, never “no”)•
unavailableReason: consent_required | dm_access_disabled | not_messageable | error | nullComment-to-DM automations now support follower-based targeting + optional follow verification (Instagram only), and delayed sends.
New request fields on
POST /v1/comment-automations and PATCH /v1/comment-automations/{automationId}:•
dmDelaySeconds (0–86400)•
commentReplyDelaySeconds (0–86400)•
audience (followerStatus: any | follower | non_follower; whenUnknown: send | skip | verify; optional minFollowerCount)•
followGate (message, buttonLabel, optional notFollowingMessage)Automation logs (
GET /v1/comment-automations/{automationId} and .../logs) add new status values pending and gated, plus fields like audienceOutcome (passed | blocked | gate_sent | gate_passed | gate_failed) and nextDueAt while queued.Webhook comment payloads now may include Instagram-only
comment.author.instagramProfile (best-effort) with isFollower/followerCount when available; absence means “unknown”.View documentation
Message reactions are now supported on Instagram, Facebook Messenger, and Slack via the existing reactions endpoints.
You can add/remove reactions across more inbox channels, and reaction webhooks now cover these platforms too.
Use:
•
•
Notes:
• Slack reactions require a Slack emoji name like
• Instagram/Messenger reactions are subject to Meta’s 24h messaging window
•
Comment-to-DM automations now support sending a Meta generic template (product card) as the first DM.
Set
•
•
Constraints:
•
• For
Also: for
View documentation
You can add/remove reactions across more inbox channels, and reaction webhooks now cover these platforms too.
Use:
•
POST /v1/inbox/conversations/{conversationId}/messages/{messageId}/reactions with emoji•
DELETE /v1/inbox/conversations/{conversationId}/messages/{messageId}/reactions with accountId (query)Notes:
• Slack reactions require a Slack emoji name like
:thumbsup: (unnamed Unicode emoji returns 400)• Instagram/Messenger reactions are subject to Meta’s 24h messaging window
•
reaction.received webhook now includes Slack/Instagram/Messenger (sender can be the business platform id; compare reaction.sender.id with conversation.participantId)Comment-to-DM automations now support sending a Meta generic template (product card) as the first DM.
Set
template on POST /v1/comment-automations / PATCH /v1/comment-automations/{automationId}:•
template.type: generic•
template.elements: 1–10 cards (each supports title, subtitle, imageUrl, buttons)Constraints:
•
template is mutually exclusive with buttons (sending both is a 400)• For
PATCH, pass template: null to clear the cardAlso: for
POST /v1/inbox/conversations/{conversationId}/messages on Instagram/Facebook, top-level buttons are now explicitly mutually exclusive with template (sending both returns 400).View documentation
PUT /v1/ads/campaigns/{campaignId} now supports Google campaigns (in addition to Meta) and enforces platform-level field support (unsupported fields return 400, not silently ignored).For Google, you can set campaign bidding via:
•
platform: google•
bidStrategy (Meta + Google)•
bidAmount (Google only; required for LOWEST_COST_WITH_BID_CAP and COST_CAP)•
roasAverageFloor (Google only; required for LOWEST_COST_WITH_MIN_ROAS)The
200 response now echoes back only the fields you sent, plus updated (and may include bidAmount/roasAverageFloor when provided).View documentation
New endpoint:
This re-homes the number and any associated accounts together (so you don’t split the number across profiles by moving only the social account).
Send
Response may include
View documentation
PATCH /v1/whatsapp/phone-numbers/{id}/profile to move a provisioned number to another profile.This re-homes the number and any associated accounts together (so you don’t split the number across profiles by moving only the social account).
Send
{ "profileId": "..." } where id is the phone number record id from GET /v1/phone-numbers (not an account id).Response may include
movedPlatforms with values phone, sms, whatsapp. Conflicts return 409 if the destination profile already has an account on any of those platforms.View documentation