Request an offer¶
Your agent requests an offer when a conversation reaches a moment. Offer Manager evaluates the moment's rules and returns zero or one offer, rendered for the channel. This document describes how to make the request with the Fetch API, handle the response, and report what happens to the offer. To set up the moment and its offers, see Create a moment.
The example on this page is the resort concierge agent from Moments, offers, and rules, which offers guests a spa booking after they check in.
Before you begin¶
- Create a moment and an enabled rule with at least one offer.
- Get an API key. In the console, open the account menu and click API Keys. The page lists your org's keys, and Create API Key creates a new one. Only admins and owners see this page.
- Get the ID of the agent the moment belongs to. A
key from API Keys belongs to the whole org, so each request names its
agent in the
applicationparameter. A fetch key bound to the agent makes the parameter unnecessary. See Authentication. - Keep the key on your server. Send requests from your agent's backend, not from a customer's device.
Choose the render format¶
The format parameter sets how the offer is rendered. Choose the format for
the channel the conversation is on:
| Channel | format |
What you receive |
|---|---|---|
| RCS for Business, through Google | rcs-google |
A rich card with suggested actions, ready to send. |
| RCS, through a GSMA Universal Profile provider | rcs-gsma |
A rich card in the GSMA message format. |
| Facebook Messenger | fbm |
A generic template, with the offer's replies as quick replies. |
| SMS | sms |
Text followed by the offer's link. |
| Webchat | direqt |
A card as JSON (title, subtitle, image, actions) for your webchat to draw. This is the default. |
For every format, see Render formats.
When a conversation moves from RCS to SMS, request the same moment with
format=sms. The rules and offers stay the same.
Name the channel¶
Rules can be limited to channels, such as RCS only, and a rule limited to
channels matches only requests whose channel is known. The sms,
rcs-google, rcs-gsma, and fbm formats name their channel (fbm
names messenger). For every other format, send the channel in the
channel parameter: rcs, sms, webchat, messenger, or voice. A webchat request in the default format, for
example, sends channel=webchat.
A request that names no channel still matches rules with no channel limit, but never a rule limited to channels. The console's Attributes page shows how many of each moment's requests named no channel. See Channels.
Request the offer¶
Send a POST to the Fetch API with the agent's ID in application and the
moment's code in adUnit:
curl -X POST "https://ads.advertising.chat/v1/fetch/v2?key=YOUR_API_KEY&application=YOUR_AGENT_ID&adUnit=after-check-in&format=rcs-google" \
-H "Content-Type: application/json" \
-d '{
"subscriber": "guest-8f2c1d",
"attributes": { "tier": "gold", "checkInDate": "2026-11-02" },
"context": "Guest just checked in and asked what time the pool opens."
}'
The request body carries the following:
subscriber: an opaque identifier for the customer. It enforces frequency caps and the Show them in turn, in this order selection. Never use a phone number or email address.attributes: the keys and values your rules' audiences and exclusions compare. See Rule conditions.context: optional, a short summary of the conversation. It improves the fit of the offer and lets the appropriateness check withhold offers in sensitive moments. It is not stored.
Handle the response¶
A 200 response contains the offer:
{
"messageId": "direqt-6a3f…",
"format": "rcs-google",
"payload": { "contentMessage": { "richCard": { "…": "…" } } },
"properties": { "bookingType": "spa" },
"isTest": false
}
- Send
payloadto the customer through your messaging platform without changing it. Its links are click-tracking URLs, so taps are recorded automatically. - Keep
messageId. You use it to report what happens to the offer. - Read
propertiesfor the offer's custom properties. - If
isTestistrue, the rule is in test mode. Don't send the offer to a customer.
A 204 response means no offer fits this moment. Continue the conversation
without one. This is the most common response, and your agent must handle
it.
Report what happens¶
Report events for the offer with the messageId from the response, passed
as fetchEventId:
curl -X POST "https://ads.advertising.chat/v1/event?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"version": 2, "eventType": "deliver", "fetchEventId": "direqt-6a3f…"}'
Report send, deliver, and read as your messaging platform confirms
them, and conversion when the customer completes the offer, such as
booking the spa. For conversions that happen outside the conversation, such
as on a booking page, see Conversion tracking.
Report reply taps¶
An offer's replies, such as "Book it" and "Not now", come back to your agent
as the customer's next message, carrying the reply's postback data. Google's
RCS platform returns it as suggestionResponse.postbackData, and Messenger
as message.quick_reply.payload. Send it to the Interact API unchanged:
curl -X POST "https://ads.advertising.chat/v1/interact?key=YOUR_API_KEY&postbackData=direqt-6a3f…_Xk2a9-1"
With the Node SDK, call recordInteraction:
import { AdChat, isAdPostbackData } from '@advertising-chat/sdk';
const adchat = new AdChat({ apiKey: process.env.ADCHAT_API_KEY! });
// In your RCS webhook, for each message from the customer:
const postbackData = message.suggestionResponse?.postbackData;
if (isAdPostbackData(postbackData)) {
const { recorded } = await adchat.recordInteraction(postbackData);
// recorded is 'accepted' or 'declined' for a reply with a role.
}
For Messenger, messengerPostbackData(event) reads the postback data from a
webhook messaging event. A reply with an accept or decline
role records the customer's
response, which rules can use, for example to stop offering the spa to a
guest who said "Not now". Your agent's own replies carry their own payloads,
so report only an offer's, which isAdPostbackData recognizes.
Check why an offer did or didn't appear¶
To see the reasoning for a request, add test=1. A test request isn't
counted in reports, and its response lists why each rule was disqualified.
To get the reason for an empty response without a test, add debug=1. See
Request parameters.
What's next¶
- Review performance by offer, moment, and rule.
- Read every request parameter in the Fetch API reference.
- Read the event types and fields in the Events API reference.