Send from Adobe Journey Optimizer¶
An Adobe Journey Optimizer (AJO) journey can send an Outreach to the profile it is handling, at any step, and branch on the result. You configure two AJO custom actions: a send action that asks your agent to send one Outreach to the profile, and a status action that reads back whether it went out. Each send is an ordinary send to one person, with the same consent, STOP and duplicate protection as any other. See Send to one person.
The send goes to the profile's mobile number on RCS. That number is the person's channel identity: the send reaches whoever holds it in Anychat, and creates a Person to hold it the first time. The AJO profile id and email never find anyone.
This document describes the AJO side of the setup. The fields and answers of both actions are in the API reference.
Before you begin¶
- Write the Outreach the journey sends, with the inputs its opener needs, such as a check-in date. Each Outreach gets its own send action.
- Connect an RCS channel to the agent. Until it is launched, add the phones you test with to its early-access list. See Early access and launch.
- You need permission in Journey Optimizer to configure custom actions, and to create journeys.
Create an API key for AJO¶
- Open Workspace · API Keys and click Create API Key.
- Name it after the journey or the AJO sandbox it serves.
- Under Scopes, choose Adobe Journey Optimizer and nothing else. A key with only this scope can send and check outreach through these two actions, and it is refused everywhere else in the API.
- Copy the key. You paste it into both actions.
Generate the action definition¶
Anychat generates what you enter in AJO for each Outreach: the action names, URLs, header, the payloads to paste, and how to mark every field.
The URL needs three ids. Open the agent's Settings · API page, which
lists the organization id, the agent id and every Outreach's id, each
with a copy button. An Outreach's id is also at the top of its own page.
An Outreach id is often a short name such as reservation, not a
random string.
Fetch the definition with the key you just created:
curl -s https://api.anychat.ai/v1/orgs/{org}/agents/{agent}/integrations/ajo/outreach/{outreachId}/action-definition \
-H "Authorization: Bearer $ANYCHAT_API_KEY"
send and status hold one action each, and runbook lists the setup
and branching steps in order. The definition is generated from the
Outreach, so its inputs are exactly the ones the Outreach needs. The
steps below say where each part goes. See
The action definition
for every field.
Configure the send action¶
Create a custom action in Journey Optimizer (Adobe's guide: Configure a custom action).
- Name it
send.name, for exampleanychat_arrival_info. The name is how the journey reads the response, as@action{anychat_arrival_info.outcome}. -
Set the URL to
send.url, your agent's send path for the Outreach: -
Set the method to POST.
- Add a constant header
Authorizationwith the valueBearer <your API key>. -
Paste
send.requestas the request payload. It has one entry underinputsfor each of the Outreach's inputs, like this:{ "profile": { "phone": "", "channel": "rcs", "id": "", "firstName": "", "lastName": "", "email": "" }, "profileUpdate": "fill", "consent": { "sms": "", "evidence": "" }, "journey": { "versionId": "", "nodeId": "", "instanceId": "" }, "inputs": { "checkInDate": "", "marina": "" }, "emulator": { "personaId": "" }, "dryRun": false } -
Mark each field as
send.fieldssays:Field Mark as profile.channelConstant, rcsprofileUpdateConstant, fill: a send fills in only the profile fields Anychat doesn't have yet. Setoverwritewhen AJO is the source of truth for names and emailemulator.personaIdConstant, empty. See Rehearse without a phone dryRunConstant, falseEverything else Variable. Tick Is optional on every field except profile.phoneand the inputs the opener needs -
Paste
send.responseas the response payload: -
Tick Define a failure response payload and paste
send.errorResponse:
Once a journey that uses the action is live, AJO lets you change only the action's name, description, URL and authentication. The payload is frozen. Anychat keeps both actions compatible for as long as a journey calls them.
Configure the status action¶
Create a second custom action, status.name (anychat_send_status).
One status action serves every Outreach on the agent, so create it once.
- Set the URL to
status.url,https://api.anychat.ai/v1/orgs/{org}/agents/{agent}/integrations/ajo/sends. - Set the method to GET, and add the same
Authorizationheader. -
Paste
status.responseas the response payload: -
Tick Define a failure response payload and paste the same
{ "code": "", "title": "", "detail": "" }example.
In the journey, the status action is given the send's id in its
Path, status.path (@action{anychat_arrival_info.sendId}), so it calls
…/sends/<sendId>. If you prefer, add a variable query parameter
sendId to the action instead; the endpoint accepts either.
Add the actions to a journey¶
- Add the send action where the journey should send.
-
Map its variable fields:
Field Map to profile.phoneThe profile's mobile number, such as mobilePhone.number. It must be in E.164 form (+19285551234), or the send answers400profile.idJourney Properties › profileIdjourney.versionIdJourney Properties › journeyVersionUIDjourney.nodeIdJourney Properties › currentNodeIdjourney.instanceIdJourney Properties › instanceUIDconsent.smsThe profile's consents.marketing.sms.valinputs.*The event or profile fields that hold each value Pick the Journey Properties from the expression editor rather than typing them. The three journey fields make each send happen once per step per profile: if AJO retries the call, the retry is recognized and nothing is sent twice. Without them, a profile gets this Outreach at most once a day.
profile.idserves only that daily fallback, and isn't stored. -
Tick Add an alternative path in case of a timeout or an error. A profile whose call fails without this path leaves the journey.
- Leave the journey's timeout for external calls at 30 seconds. AJO retries a failed call within that time, but it doesn't retry a call that runs past the timeout.
Branch on the outcome¶
Every outcome of the send action arrives on the success path, so branch
on @action{anychat_arrival_info.outcome}:
| Outcome | What to do |
|---|---|
queued or duplicate |
The send is under way. Wait, then check it with the status action |
refused |
Don't reach the person by another route. reason says why: the number replied STOP, consent.sms was n, the person's consent is recorded as denied, or an input is missing |
skipped |
A dry run; nothing was sent |
Treat any reason your journey doesn't recognize as a refusal. The
error path is for calls that failed outright: a wrong key or URL, a
disabled Outreach (404), a malformed payload or a phone number not
in E.164 form (400), or the API
being unavailable. After an error or a timeout, the send might still
have been accepted, so check before reaching the person another way.
For the status action, wait, then read it and branch:
reachableisfalse: the person's phone can't receive RCS. Reach them on another channel.finalisfalse: the send is still queued or being retried. Wait and read it again. A temporary failure is retried for about 30 minutes before the send is marked failed, andnextAttemptAtsays when the next attempt is due.stateissent: the message went out.deliveredandreadare best-effort:falsedoesn't mean it failed.stateisfailedandreasonisbinding_error: the agent's RCS channel is misconfigured. Route it to the error branch and tell whoever manages the agent. The person is still reachable.
Test the journey¶
Rehearse without a phone¶
Copy the send action and set its emulator.personaId constant to a
persona's id, then leave the profile fields
unmapped. A persona's id is at the top of its page under Test ·
Personas. The whole send runs, and the opener lands in that persona's
emulator session, where you can reply to it.
Nothing reaches a phone. The persona's own consent state applies, so
you can rehearse a refusal with a persona that has opted out.
Send to your own phone¶
To see the real message on a real phone, call the send action yourself
with your own number in profile.phone and no emulator block. Your phone
must be on the RCS channel's
early-access list until the channel is
launched.
curl -s -X POST https://api.anychat.ai/v1/orgs/{org}/agents/{agent}/integrations/ajo/outreach/{outreachId}/sends \
-H "Authorization: Bearer $ANYCHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profile": { "phone": "+15551234567", "firstName": "Your name" },
"consent": { "sms": "y" },
"journey": { "versionId": "test", "nodeId": "send-1", "instanceId": "run-1" },
"inputs": { "checkInDate": "2026-10-14" }
}'
Then read the outcome with the status action. To send again, change
journey.instanceId; the same three journey values answer
duplicate and send nothing.
This is real data
A send to your own phone is a real send on the live agent, not a
rehearsal. It reaches the Person who holds your number on RCS, or
creates one, keeps the inputs on that record, and starts a real
conversation that is listed, counted and billed like any other. If
you reply STOP, your number is refused from then on. Use an obvious
test name so you can find the record afterwards, and delete it on
the People page when you are done. To try a journey with no
real data at all, rehearse with a
persona.
Check the wiring¶
Set dryRun to true in a copy of the action to check that a real
profile resolves, that its consent allows the send, and that every
input is mapped. It answers skipped or the refusal the real send
would get, and nothing is written.
Test in AJO¶
AJO's test mode calls both actions for real, so test with profiles whose phones are on the channel's early-access list. Test mode shortens wait nodes, so the status action runs sooner than it would live and can read an earlier state. AJO's Dry Run skips custom actions entirely.
How many sends a key can make¶
A key can call the send action 12,000 times a minute (200 a second), in bursts of up to 1,000. This budget is the send action's own; the key's other sends through the API don't use it.
A journey triggered one event at a time, such as a booking or a
check-in, never comes close. A journey that reads a whole audience can
release more profiles at once than a burst allows. For that journey,
turn on AJO's throttling for the endpoint: its lowest rate, 200 calls a
second, is exactly this limit, so every profile gets through. Without
throttling, calls over the limit are answered 429, AJO retries them
only within its timeout, and the rest take the error path.
Rotate the key¶
AJO keeps an action's authentication editable after go-live. Create a
new key with the Adobe Journey Optimizer scope, update the
Authorization header on both actions, then delete the old key on
Workspace · API Keys. See Manage access.
What's next¶
- Send to one person: the send both actions make.
- Monitor your agent: each AJO send is a row on Monitor · Sends.
- Adobe Journey Optimizer in the Agent API