External Agent is available on YCloud Pro plans and above.
Before you begin
Prepare:- A publicly reachable HTTPS endpoint that accepts JSON
POSTrequests. - A service that verifies webhook signatures, stores events, prevents duplicate processing, and runs your AI agent.
- A regular YCloud account API key, stored on your server. Developer App API keys are not supported by these Inbox endpoints.
- A WhatsApp business number connected to YCloud and a human team or agent to receive handoffs.
https://api.ycloud.com as the API base URL.
Connect your agent
1. Create an External Agent
- In the YCloud console, open AI Agent > AI Agent.
- Select Create Agent > External Agent.
- Enter a Name and your Webhook URL, such as
https://agent.example.com/webhooks/ycloud. - Select Save.
- Copy the generated Bot ID from the agent details. Use this value as
botIdin API requests; you do not need to supply an ID from your own AI system.

Create an External Agent with a name and a webhook URL. This example shows the form before saving.
X-API-Key authenticates your outbound REST requests. A Bot ID is an identifier, not a credential.
2. Assign a WhatsApp number
Open WhatsApp Manager > WhatsApp accounts, then open the business number’s settings and select Inbox > Assignment. Under Priority 3 Assign to, select AI Agent, then choose your agent from the External Agent section of the agent selector. Check the rule priority: assignment to the customer’s owner or the last handling agent can take precedence. See Conversation assignment rules. One External Agent can handle multiple numbers. Each number is associated with one bot at a time. Manage these associations in the number’s assignment settings.3. Process a conversation
- A customer sends a WhatsApp message to your business number.
- YCloud opens or continues an Inbox dialog and applies the number’s assignment rules.
- When your External Agent handles the dialog, YCloud delivers the applicable webhook events to its endpoint.
- Your service verifies and stores the event, returns
2xx, and processes the customer input asynchronously. - Your service calls the Inbox API to reply, hand off, or close the dialog.
- Your service tracks delivery through
whatsapp.message.updated.
Understand the identifiers
IDs are strings. Timestamps use UTC RFC 3339. Use
dialogId, not conversationId, in the dialog API paths.
Receive webhook events
All four event types arrive at the same webhook URL. Each dedicated External Agent delivery includesid, type, apiVersion, createTime, and externalBotContext, plus the corresponding business object.
Verify, store, and acknowledge
Verify theYCloud-Signature header using the endpoint’s signing secret and the raw HTTP request body, before parsing JSON. The signature format is:
2xx response promptly. Run AI inference and other slow work asynchronously. Non-2xx responses and timeouts can trigger a limited number of retries.
Deduplicate by (botId, event.id), within your YCloud account. An assignment change can notify both the outgoing and incoming agents; using only a global event ID can discard one agent’s notification. Keep processing state so a repeated event does not send a second reply.
Example: customer message
inboxMessage.inbound. Outbound creation events use inboxMessage.outbound instead. Retain unknown message types and fields for compatibility instead of treating them as text.
Decide whether to reply
externalBotContext is a snapshot taken when the notification is generated. Its botId identifies the receiving bot; assignee identifies the actual handler in that snapshot. These can differ after a handoff.
actionable=true means the receiving bot was handling an open dialog at that time. It can also be true on an outbound creation event or a delivery receipt.
Events can arrive more than once or out of order. There is no event sequence field. Group work by dialogId and avoid processing the same customer input twice. An initial assignment event should not independently trigger a second reply to the opening customer message.
What happens after a handoff or closure?
New customer messages and human replies are no longer delivered to the previous External Agent once the dialog is handled by a human, queued, unassigned, or closed. The previous agent still receives its applicable outgoing-assignment or closure notification. Creation notifications and delivery receipts for messages it already sent remain associated with that sending agent, even after a handoff or number reassignment. Previously generated notifications can arrive late. Cancel pending work when ownership changes or the dialog closes, and do not resume it solely because an old event hasactionable=true.
Ordinary webhook endpoints retain their existing subscription behavior and payload format. The dedicated External Agent delivery adds externalBotContext; do not require that field on ordinary deliveries of whatsapp.message.updated.
Use the Inbox API
SendX-API-Key on every request and Content-Type: application/json on POST requests. All examples below use placeholder IDs. Replace them with values from your agent and received events.
Successful responses return the business object directly, without a
data wrapper. Write operations check that the dialog is open and currently handled by the specified bot. YCloud determines the sender and customer from the dialog; do not submit tenantId, from, to, recipient, operatorId, or source to override them.
Get the current dialog
status, assignee, and canAct. The bot field can refer to the last associated external bot and is not proof of current ownership. canAct reflects the queried bot’s permission at request time; a later write still performs its own checks.
Retrieve conversation history
items and nextCursor. Each item includes an Inbox message id, direction, type, content, and createTime. For a text message, read content.text.body.
History includes customer-visible messages from the same conversation, potentially across previous dialogs. A message’s own dialogId can differ from the requested dialog or be absent in older history. Internal notes, private handoff summaries, and internal system messages are excluded.
Messages are returned in ascending message-ID order, from older to newer. Omit after on the first request; pass nextCursor unchanged as after on subsequent requests until it is null. The default limit is 50, with a range of 1–100. The handoff-target list uses the same pagination pattern.
Send a reply
botId and message are required. sourceEventId and replyToMessageId are optional. The reply reference is an Inbox message ID, such as inboxMessage.id; it is not a wamid.
status even when HTTP returns 200. accepted means the message entered the sending pipeline, not that it reached the customer. A 200 response can also report failed; channelMessageId may not yet be available.
Use whatsapp.message.updated to track subsequent states, including sent, delivered, read, failed, expired, or deleted. Correlate the receipt’s externalBotContext.inboxMessageId with the send response’s inboxMessageId. Inspect whatsappMessage.errorCode and errorMessage for failures.
Message types
Themessage object uses the standard WhatsApp message model: type plus the matching content field. Examples include text, image, video, audio, document, sticker, location, contacts, interactive, template, and reaction. Existing WhatsApp sending and template requirements still apply.
For example, replace the message object with:
id or link. For message-body structures, see Send a WhatsApp message. Send the reply through the Inbox endpoint above so it uses the dialog’s handler checks and Inbox context. Do not submit or rely on filterUnsubscribed or filterBlocked in this Inbox message request.
Customer responses can include interactive.button_reply, interactive.list_reply, interactive.nfm_reply, or button. A Flow response’s response_json is a JSON string. The inbound button type is not an outbound message type for this endpoint.
Hand off to a human
First list available teams or agents for the dialog’s business number:type=agent to list members instead. Each returned target supplies the id and type for the handoff request. An agent’s optional online field describes presence; it does not guarantee immediate assignment.
target with type (team or agent) and id. There is no default human fallback. Optional reason supports up to 256 characters; optional summary supports up to 4,000 characters and is not part of the customer-visible message history.
The response contains outcome and the updated dialog. Outcomes are assigned, queued, team_unassigned, or unassigned. Check the actual outcome instead of assuming a human has accepted the conversation.
A handoff keeps the same dialogId. Once your agent loses ownership, stop replying or trying to close that dialog.
Close a resolved dialog
dialog with status=closed and canAct=false. Your agent cannot continue sending or handing off that closed dialog. A subsequent valid customer message starts a new dialog and runs the number’s assignment rules again.
Handle errors and retries
Error responses use anerror object with status, code, message, and requestId. Keep the request ID when contacting YCloud support.
Monitor View delivery logs for webhook failures. Retain event IDs, dialog IDs, message IDs, request IDs, and processing outcomes. Webhook retries are finite, so use dialog and history queries to recover context when necessary.
Frequently asked questions
Can I connect an agent built with my own AI framework?
Yes. Your service must receive and verify YCloud webhooks and call the Inbox REST API. You control how your service generates responses, accesses knowledge, and calls its own tools.Will my agent receive all Inbox conversations?
No. Its dedicated endpoint receives events within its handling scope, along with relevant assignment and closure notifications and receipts for its own sent messages. New messages after a human handoff are not forwarded to the previous agent. Previously generated events may still arrive late.Can my agent use messages from earlier dialogs?
Yes. The history endpoint returns customer-visible history for the conversation, including earlier dialogs. Use each message’s owndialogId where available; do not assume every returned message belongs to the current service session.
What happens if I change the agent assigned to a number?
Open dialogs currently handled by a bot are reassigned asynchronously under the number’s routing behavior. The outgoing agent receivesassignmentRole=outgoing and should stop its work. The incoming agent receives reason=phone_binding_changed with assignmentRole=incoming; it should query the current dialog and history before continuing.
The dialog ID and history remain unchanged. Dialogs currently handled by a human are not transferred to the new bot by this number reassignment. After another bot replaces it, the old bot can no longer query that dialog through these endpoints.
Does my webhook’s response become the customer reply?
No. Return2xx to acknowledge event receipt, then send the customer reply through POST /v2/inbox/dialogs/{dialogId}/messages.
Why does my agent receive actionable=true for its own reply?
The field describes who handled the open dialog when the event was generated. Outbound creation events and delivery receipts can therefore have actionable=true. Trigger a normal AI response only for an inbound inbox.message.created event, and account for changes in live dialog ownership.
