1. Overview
The Conversational Agent Interface (CAI) is the OMB Cloud AES standard for integrating an external conversational agent provider into a customer’s digital channels. It covers inbound web forms, web chat and messaging channels, and the handling of the resulting conversation through to a booked appointment or a recorded outcome.
The division of work is deliberate and narrow. The Provider supplies the conversational intelligence. AES supplies the flow of contacts, the routing, and the permanent record. Everything a customer sees, reports on, and acts upon continues to live in AES.
The company implementing this interface is referred to throughout as the Provider. Each Provider is issued a provider_code and a set of credentials at onboarding.
This specification is versioned and shared across all Providers. Environment-specific values — provider code, catalog, credentials, authorised addresses — are issued separately in a private annex.
2. Roles and responsibilities
| Responsibility | AES | Provider |
|---|---|---|
| Capture of the contact | Yes | — |
| Resolution of the destination unit | Yes | — |
| Selection of the origin number or identity | — | Yes |
| Conversation with the contact | — | Yes |
| Closing the appointment | — | Yes |
| Recording and retention of the conversation | Yes | — |
| Commercial follow-up thereafter | Yes | — |
2.1 Interfaces
| Id | Direction | Method | Purpose |
|---|---|---|---|
A | AES → Provider | POST | Delivery of contact jobs |
B | Provider → AES | POST | Return of conversation, appointments and outcomes |
Both directions are push. Neither party polls the other, and no read endpoint is exposed under this interface. This keeps latency low, removes the need for scheduled synchronisation, and means a Provider integration has exactly two moving parts.
3. Lifecycle
1. Contact Submits a form or writes on a digital channel.
2. AES Creates the record, resolves the destination unit and
assigns a lead_id that accompanies the relationship.
3. AES → Prov. [Interface A] Delivers the contact job with the unit
and the context of the request.
4. Provider Selects the origin number for that unit and starts
the conversation.
5. Prov. → AES [Interface B] Returns the conversation as it happens,
and the result: appointment booked or reason closed.
6. AES Records both against the lead, stamped with the
provider_code. The customer continues follow-up.
The destination unit is resolved at the moment of capture, where the landing page, the campaign and the requested location are known. It travels in the branch_code field of every job, so a Provider never has to maintain or update routing logic as a customer opens new locations.
4. Interface A — Contact jobs
POST {provider_endpoint}/contact-jobs
Content-Type: application/json
X-CAI-Source: aes
X-CAI-Signature: sha256=<hmac_hex>
X-CAI-Timestamp: 1787923271
AES signs its outbound requests with the same scheme described in section 6, using the opposite secret of the pair. The Provider should verify them exactly as AES verifies the Provider’s: same algorithm, same 300 second window, comparison in constant time.
AES delivers each contact the Provider is expected to handle, at the moment of capture.
4.1 Request body
{
"lead_id": "AES-38-104772",
"event_id": "job_9f2c1a8e4b",
"branch_code": "ACME-NORTH",
"city": "Monterrey",
"contact": {
"name": "Maria Fernanda Rios",
"phone_e164": "+5218112345678",
"email": "mfrios@example.com",
"language": "es-MX"
},
"origin": {
"channel": "landing_form",
"source": "example.com/north/service",
"campaign": "spring-north",
"captured_at": "2026-08-27T14:02:11-06:00"
},
"brief": {
"intent": "book_appointment",
"notes": "Requested an evening slot."
},
"callback_url": "https://omb.cloud/app/api/cai_events.php"
}
4.2 Fields
| Field | Type | Req. | Description |
|---|---|---|---|
lead_id | string | Yes | Identifier of the contact in AES. Returned unmodified on every Interface B event. This is what keeps the conversation bound to the record. |
event_id | string | Yes | Unique per job. Enables safe retries. A repeated value must be ignored. |
branch_code | string | Yes | Destination unit. Determines the origin number. Catalog issued per deployment. |
city | string | No | Human-readable reference, for reporting and conversation context. |
contact.name | string | Yes | Name as declared by the contact. |
contact.phone_e164 | string | Yes | E.164 format. Primary contact key on both platforms. |
contact.email | string | No | Present when supplied by the contact. |
contact.language | string | No | Preferred language. Defaults to the environment locale. |
origin | object | No | Capture provenance, so the conversation opens in context. |
brief.intent | enum | No | Detected intent. See Annex A. |
brief.notes | string | No | What the contact asked for, summarised by AES. |
callback_url | string | Yes | Destination for Interface B events. |
4.3 Expected response
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"provider_job_id": "prv_77219",
"assigned_number_e164": "+528112345678"
}
Reporting the assigned number lets AES attribute inbound messages from that contact correctly, and maintain a single conversation if the contact later returns through another channel.
5. Interface B — Conversation events
POST https://omb.cloud/app/api/cai_events.php
Content-Type: application/json
X-CAI-Provider: {provider_code}
X-CAI-Signature: sha256=<hmac_hex>
X-CAI-Timestamp: 1787923271
A single endpoint receives everything the Provider returns. It is designed for real-time writes, signed and idempotent, so a Provider can send and retry without risk of duplication.
5.1 conversation.message
One event per message, in both directions, as it happens. The full record is what allows the customer to see the agent’s work as it happened and to attribute the resulting appointments precisely.
{
"event": "conversation.message",
"event_id": "evt_4b81c07f",
"lead_id": "AES-38-104772",
"provider_job_id": "prv_77219",
"channel": "whatsapp",
"from_number_e164": "+528112345678",
"direction": "outbound",
"author": "agent",
"text": "Good afternoon Maria Fernanda, I am writing from...",
"occurred_at": "2026-08-27T14:04:39-06:00"
}
Event fields. event and event_id are required on every event; the rest depend on the type:
| Field | Presence | Description |
|---|---|---|
event | Required | Event type |
event_id | Required | Unique event identifier, up to 120 characters |
lead_id | Optional | The identifier delivered in the assignment, unmodified |
provider_job_id | Optional | The Provider’s own identifier |
channel | Optional | Message channel; see A.6 |
from_number_e164 | Optional | Origin number in E.164 |
direction | Optional | inbound or outbound |
author | Optional | Who wrote it; see A.3 |
text | Optional | Message text |
occurred_at | Optional | When it happened, ISO 8601 with offset |
5.2 Appointment events
Sent on booking, rescheduling or cancellation. AES records the appointment and reflects it on the corresponding unit’s board.
{
"event": "appointment.booked",
"event_id": "evt_4b93a112",
"lead_id": "AES-38-104772",
"branch_code": "ACME-NORTH",
"scheduled_at": "2026-08-29T11:30:00-06:00",
"service": "first_visit",
"notes": "Prefers mornings.",
"occurred_at": "2026-08-27T14:11:02-06:00"
}
Accepted values for event: appointment.booked, appointment.rescheduled, appointment.cancelled.
5.3 job.closed
Sent when handling ends without an appointment. It lets the customer resume through other means and prevents duplicate outreach to the same contact.
{
"event": "job.closed",
"event_id": "evt_4ba7d290",
"lead_id": "AES-38-104772",
"outcome": "no_answer",
"attempts": 4,
"occurred_at": "2026-08-29T18:00:00-06:00"
}
5.4 Idempotency and retries
| Code | Meaning | Suggested action |
|---|---|---|
202 | Event accepted, or discarded as a duplicate | None |
400 | Invalid schema | Do not retry. Review the body |
401 | Invalid signature, outside the window, unrecognised provider, or unauthorised origin | Do not retry. Check credential, clock and registered origin |
413 | Body larger than 256 KB | Do not retry. Reduce the event |
429 | Request cap reached | Retry after the value of Retry-After |
5xx | Temporary unavailability | Retry with exponential backoff for up to 24 h |
Every event carries a unique event_id (up to 120 characters). AES discards repeats and answers 202 with {"ok": true, "duplicate": true}, so a retry never produces a duplicate record. In practice, any 2xx means accepted.
A lead_id AES does not recognise is not an error: the event is accepted with 202 and logged for reconciliation between both teams.
6. Authentication
Both directions are signed with HMAC-SHA256 over the request body, using an independent shared secret per direction. This is the same mechanism AES operates with its messaging and payment integrations.
signature = HMAC_SHA256(secret, timestamp + "." + raw_body)
header = "sha256=" + hex(signature)
6.1 Worked example
Verify your implementation against these exact values before writing any integration code.
secret cai_test_5f3a9c21b7e04d8a
timestamp 1787923271
body {"event":"conversation.message","event_id":"evt_4b81c07f","lead_id":"AES-38-104772"}
signature = HMAC_SHA256(secret, timestamp + "." + body)
X-CAI-Signature: sha256=a893b6460bbb5063910f16ed0b8bbaa44204ea83d9a0ceaa6ac539e0d7bd9f1a
The signed string is the timestamp, a literal dot, and the raw body exactly as transmitted: no re-serialisation, no whitespace changes, no key reordering. That is where most implementations lose time.
| Element | Definition |
|---|---|
| Validity window | 300 seconds, to limit replay exposure. |
| Credential | Issued per Provider and per environment. Identified by the X-CAI-Provider header. |
| Source addresses | The Provider supplies its egress IP addresses; AES registers them as authorised origins. |
| Rotation | Coordinated between both teams, with an overlap window so service is not interrupted. |
| Transport | TLS 1.2 or above in both directions. |
7. Environments and unit catalog
Each deployment has its own environment: a provider_code, a credential pair, and a catalog of branch_code values with their human-readable names. AES maintains the catalog and updates it as the customer opens new units. The Provider maps each code to its origin number.
Because routing travels with the job, a new unit requires no integration change on either side. The Provider adds one row to its mapping; nothing else moves.
The catalog, the credentials and the authorised addresses are issued in the private annex that accompanies this specification for each deployment.
Alongside the production credentials, a pair of test credentials is issued: they point to the same URLs and use the same signing scheme, but their data lands in an isolated test space. Everything described in this document can be exercised end to end with them before touching real data, including receiving a sample assignment emitted by AES.
8. Scope of version 1.0
The first version concentrates on what produces results from day one: reaching the contact, holding the conversation, and closing the appointment. Keeping it narrow allows both parties to reach production quickly and with low risk.
8.1 Included
- Real-time delivery of contacts from every digital channel.
- Routing by unit, resolved by AES and delivered with each job.
- Recording of the full conversation, in both directions.
- Appointments booked, rescheduled and cancelled.
- Outcomes with reason, to coordinate follow-up.
- Attribution of every result to the Provider’s code.
8.2 Planned for later versions
- Additional channels, as results are validated on those already in service.
- Availability by unit, so the agent can offer slots that are already confirmed.
- Post-appointment events, attendance and follow-up, to close the measurement loop.
- Extended reporting, based on what both teams identify as useful in operation.
8.3 Not part of this interface
CAI is a push interface in both directions and exposes no read endpoints. Operational figures a Provider needs for its own reporting are delivered by AES on an agreed schedule, as described in section 9.
In regulated sectors, records held in the customer’s operational system of record — clinical files, financial histories, case documents — remain outside this interface, since they play no part in booking an appointment. Where a specific data point is genuinely required for a conversation, it is assessed case by case with the customer.
9. Reporting and data protection
9.1 Reporting
AES delivers a periodic report of the Provider’s own operation: jobs received, time to first contact, conversations held, appointments generated and outcomes. Frequency and fields are agreed between both teams.
Because AES builds it, the report is computed on the same base the customer sees. Service measurement and customer measurement always agree, and there is no reconciliation of figures across platforms.
9.2 Personal data
The Provider acts as a data processor on the customer’s behalf: it uses the information for the purpose of this interface, does not transfer it to third parties, does not use it for any other purpose including model training, and deletes it at the end of the contractual relationship.
AES retains the complete record of every conversation as part of its custody obligations to the customer. This also guarantees service continuity in the event of an incident on either platform.
10. Service levels
Baseline targets. Adjusted per deployment against the Provider’s actual operating model.
| Item | Target |
|---|---|
| First contact | Within 5 minutes of receiving the job, during operating hours. |
| Message delivery | Within 60 seconds of each message occurring. |
| Appointment delivery | At the moment of confirmation with the contact. |
| Synchronous web chat reply | Under 5 seconds. AES maintains a continuity response so no contact is left unattended if the service is unavailable. |
| Retries | Exponential backoff up to 24 hours on either side. |
| Endpoint availability | 99.5% monthly, both directions. |
11. Becoming a Provider
- Confirm the schema in this specification.
- Supply the contact-jobs endpoint documentation and egress IP addresses.
- Supply the origin numbers or identities available per region.
- Exchange secrets in the test environment.
- Run end-to-end tests against a test environment issued by AES.
- Pilot on a single unit for two weeks.
- Roll out to the remaining units.
Piloting on one unit lets both teams tune script, timing and data quality at controlled volume before opening the rest.
12. Versioning
This document describes version 1.0. New fields may be added without notice and unrecognised fields should be ignored. No field is removed or changes meaning within the same major version. Scope extensions are agreed between both teams and produce a new version.
| Version | Date | Changes |
|---|---|---|
1.0 | 2026-08-27 | Initial published version. |
Annex A — Enumerations
A.1 origin.channel
landing_form | contact_form | webchat | whatsapp_button | phone | referral
A.2 brief.intent
book_appointment | pricing_information | service_information |
reschedule | follow_up | other
A.3 author
agent Provider conversational agent
contact The person being contacted
human Provider human operator
A.4 outcome
| Value | Meaning |
|---|---|
no_answer | No reply after the configured attempts |
not_interested | Declined |
wrong_number | The number does not belong to the contact |
callback_later | Asked to be contacted at another time |
opted_out | Asked not to be contacted again |
A.5 Formats
| Type | Format | Example |
|---|---|---|
| Telephone | E.164 | +5218112345678 |
| Date and time | ISO 8601 with offset | 2026-08-27T14:02:11-06:00 |
| Language | BCP 47 | es-MX |
| Encoding | UTF-8 | application/json |
A.6 channel and direction (Interface B)
channel: whatsapp | webchat | sms | phone | email
direction: inbound | outbound
Contact
For onboarding as a Provider, or questions about this specification, write to developers@omb.cloud.