Commerce API
Connect your own shop, booking or admissions system to the Sales agent.
On this page: What it is · Who does what · One order, call by call · What you build · Your options · Discovery profile · Operations · What every call carries · Signatures · Commit, quote and lookup · Examples · Status events · Your payment gateway · Errors · Connect it · Go-live checklist · Conventions
What it is
The Commerce API lets the AI Sales Agent work with your own shop, booking or admissions system: get a quote, and create the order, booking or application in your system the moment the customer confirms (the Created in our system completion mode). Your system stays the system of record: its prices, its stock, its order numbers and its payment gateway.
Unlike Central AI’s other APIs, your system implements this one and Central AI calls
it. Contract version: 1.3. Your system may declare any 1.x.
This page is for the developers of that system, for example the team behind a course platform that already sells with SSLCommerz or Stripe. A shop owner who only wants the agent to take orders does not need it: Handled in Central AI needs no code at all.
Start from working code. Central AI provides reference implementations of this contract in Node.js, plain PHP and a Laravel package, with the JSON schemas and conformance checks. Signing, verification and idempotency are done; you connect their few shop methods to your database. Ask your Central AI contact for the package.
Who does what
The Sales Agent (Central AI) does
- Talks to the customer on your website, Messenger, Instagram and WhatsApp.
- Finds your offerings, shows them as cards and builds the basket.
- Asks your system for the price (
quote.calculate) and shows that total, never its own. - Collects the details you ask for and the payment method your quote lists.
- Shows the whole request; only the customer confirms it, with a button or a code.
- Sends exactly one order (
commit.create) and, if the answer is lost, finds it (commit.lookup) instead of sending it twice. - Shows your payment page as Pay now, and tells the customer every status you send.
Your system does
- Publishes one discovery document: where your endpoints are, and your public signing key.
- Prices the basket with its own rules (
quote.calculate) and holds that price until it expires. - Creates the order once per
Idempotency-Keyand returns its reference (commit.create). - Finds an order by that key (
commit.lookup). - Takes the payment in its own gateway and returns the payment page (
continue_url). - Posts a signed status event when the order is accepted, paid, fulfilled or cancelled.
- Signs every response and event, and verifies every call from Central AI.
Your offerings reach Central AI separately. In this release the agent searches the
offerings you keep in Central AI, sent with the offerings feed of the
Knowledge Sync API, a CSV file or the
offerings screen. Give each one the id it has in your
system: that id is the external_ref every quote and order line carries, so your system knows which item
is meant. catalog.search, catalog.get, availability.check and
commit.get are part of the contract and listed in the connection test report, but Central AI does not
call them yet.
One order, call by call
- The customer asks in the chat (“Do you have a web development course?”). The agent searches your offerings in Central AI and shows cards. No call to your system.
- The customer chooses and asks for the total. Central AI calls
quote.calculatewith the basket; your answer is the price, fees, delivery, disclosures and the payment methods you accept. It is what the customer sees. - The agent collects the details you require (name, phone, address, your own fields) and the payment method, then shows the whole request with a code. No call to your system.
- The customer confirms. Central AI calls
commit.createonce, with anIdempotency-Key, your quote’s reference and version, the exact amount, the customer andattribution.operation_ref. You create the order and answer with its reference and statuses, plus thecontinue_urlof your payment page if the customer pays online. - If your answer is lost (timeout, 5xx), Central AI calls
commit.lookupwith the same key before anything else. It never creates a second order. - The customer pays on your gateway through the Pay now button.
- You post status events (accepted, paid, fulfilled, cancelled). Central AI verifies each one, updates the order and tells the customer in the chat.
What you build
| Piece | Needed for | Without it |
|---|---|---|
| Discovery document and your signing key | Everything | The connection cannot be published or tested. |
quote.calculate | Every order: the customer only ever confirms your total | The agent cannot propose an order in your system. |
commit.create and commit.lookup |
Creating the order, safely | The connection test fails: a lost answer could become a second order. |
| Status events | Accepted, paid, fulfilled and cancelled reaching the customer | Orders stay at the status your commit.create answer gave. |
continue_url in the commit answer | Customers paying online in your gateway | The customer is not given a payment page in the chat. |
| Offerings feed (Knowledge Sync API) with your ids | The agent finding and showing your items | The agent has nothing to offer. |
Your options
| Integration | Status |
|---|---|
| Commerce API (your own system) | available |
| Handled in Central AI (no connection needed) | available |
| WooCommerce | coming soon |
| Shopify | coming soon |
WooCommerce and Shopify are coming soon. Until then a WooCommerce or Shopify shop can take orders in the chat (Handled in Central AI), hand the basket to its own checkout and follow the order live (Live checkout on your site), send customers to its own pages (On our page), or connect through the Commerce API.
Discovery profile
Your system publishes a discovery document: a JSON file that says which contract version it speaks, which operations
it supports and at which paths, how long it keeps idempotency keys, the offering kinds and currencies it handles, and its
public signing keys. The reference implementations serve it at /.well-known/central-ai-commerce under your
base address, for example https://yourshop.com/.well-known/central-ai-commerce. You give Central AI that
address as the profile address.
- Every endpoint it names must be
https://, on the same host as your base address. - It must keep idempotency keys for at least 7 days.
- Its
keyshold public keys only. - Central AI fetches it without following redirects.
Example discovery document
{
"contract": "central-ai-commerce",
"version": "1.2",
"system": {
"name": "DIU Admissions Portal",
"vendor": "DIU ICT Division",
"software_version": "3.2.0",
"timezone": "Asia/Dhaka"
},
"capabilities": [
{
"name": "catalog.search",
"version": "1.0"
},
{
"name": "catalog.get",
"version": "1.0"
},
{
"name": "availability.check",
"version": "1.0"
},
{
"name": "quote.calculate",
"version": "1.0",
"quote_modes": [
"estimate",
"binding"
]
},
{
"name": "commit.create",
"version": "1.0"
},
{
"name": "commit.lookup",
"version": "1.0"
},
{
"name": "commit.get",
"version": "1.0"
},
{
"name": "events",
"version": "1.0"
}
],
"endpoints": {
"base_url": "https://admissions.diu.example/api/central-ai",
"catalog_search": {
"method": "POST",
"url": "https://admissions.diu.example/api/central-ai/catalog/search"
},
"catalog_get": {
"method": "GET",
"url": "https://admissions.diu.example/api/central-ai/catalog/{offering_ref}"
},
"availability_check": {
"method": "POST",
"url": "https://admissions.diu.example/api/central-ai/availability/check"
},
"quote_calculate": {
"method": "POST",
"url": "https://admissions.diu.example/api/central-ai/quotes"
},
"commit_create": {
"method": "POST",
"url": "https://admissions.diu.example/api/central-ai/commitments"
},
"commit_lookup": {
"method": "POST",
"url": "https://admissions.diu.example/api/central-ai/commitments/lookup"
},
"commit_get": {
"method": "GET",
"url": "https://admissions.diu.example/api/central-ai/commitments/{reference}"
}
},
"events": {
"supported": true,
"signature_algorithms": [
"ecdsa-p256-sha256"
],
"event_types": [
"commitment.created",
"commitment.accepted",
"commitment.rejected",
"commitment.canceled",
"commitment.updated",
"payment.updated"
],
"delivery_url_registration": "configured_by_tenant"
},
"idempotency": {
"retention_days": 30
},
"offering_kinds": [
"course_intake"
],
"currencies": [
"BDT"
],
"checkout_modes": [
"connector_write"
],
"guest_checkout": true,
"updated_at": "2026-09-01T06:00:00Z",
"keys": {
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "Jj1vO3UwxbB1GKTPEW7huAKKG_xLJj1SEYccYc4nGTY",
"y": "ekSfe2231HejJvRPACbLoVkXjsNrnjO-gzaIlfyULGY",
"kid": "diu-2026-09",
"use": "sig",
"alg": "ES256"
}
]
}
}Operations
The operations the connection test checks for:
catalog.search, catalog.get, availability.check, quote.calculate, commit.create, commit.lookup, commit.get, events.
Created in our system cannot work without
commit.create and commit.lookup.
| Operation | Method | Reference path | What |
|---|---|---|---|
catalog.search | POST | /catalog/search | Search offerings. |
catalog.get | GET | /catalog/{offering_ref} | One offering, re-checked live. |
availability.check | POST | /availability/check | Stock, seats or slots per line. |
quote.calculate | POST | /quotes | Totals for a selection. Required before any binding commit. |
commit.create | POST | /commitments | Create the order, booking or application. Idempotency-Key required. |
commit.lookup | POST | /commitments/lookup | Find a commitment by the original Idempotency-Key. |
commit.get | GET | /commitments/{reference} | Current statuses by your reference. |
The paths are the reference implementations’; yours are whatever your discovery document declares.
events is the other direction: your system sends status events to Central AI.
What every call from Central AI carries
Accept:application/jsonAuthorization:Bearer <the key your system issued for Central AI>Idempotency-Key: on every POST; onlycommit.createstores and replays itRequest-Id: one per attempt; echo it in errors ascorrelation_idCentral-AI-Contract-Version:1.3Content-Type:application/json, with a bodyUCP-Agent: names Central AI’s platform profileContent-Digest: SHA-256 of the body, with a bodySignature-Input: the request signature (below)Signature: the request signature (below)
Signatures
Every call in both directions is signed with RFC 9421 HTTP Message Signatures, algorithm ecdsa-p256-sha256,
with an RFC 9530 Content-Digest of the body.
- Verify Central AI’s requests with the public key in
keys[]of our platform profile athttp://centralai.daffodil-bd.com/.well-known/ucp. - Sign every response and every status event with your key, published in your discovery document. Central AI pins your keys when you publish the connection, and believes nothing that does not verify.
- A signature older than 300 seconds, or more than 60 seconds in the future, is refused.
Signing is where most first attempts fail. The reference implementations sign and verify for you, and ship the contract’s signature test vectors: requests, responses and events Central AI accepts, and tampered ones it refuses. Run them before you connect.
Commit, quote and lookup
- Quote (
quote.calculate) comes before any binding commit. For an order created in your system, the totals the customer sees are your quote’s, checked by Central AI. - Commit (
commit.create) carries anIdempotency-Key. The same key with the same body replays your original answer (Idempotent-Replayed: true); the same key with a different body is 409idempotency_conflict; a key still running is 409idempotency_in_flightwithRetry-After. A changed price is thequote_mismatchoutcome (HTTP 200, no commitment, the current quote), never a silent re-price. - Lookup (
commit.lookup) finds a commitment by the originalIdempotency-Key, so an answer lost on the network is recovered without creating a second order. Central AI never retries with a new key. - Test order. The connection test sends one clearly marked test order (
"test": true) and looks it up. Never fulfil it.
Examples
These are the contract’s own examples, validated against its JSON schemas, from a sample admissions portal whose applicants pay by bank deposit. The payment gateway section has a card-and-bKash example.
quote.calculate: the request Central AI sends
{
"selection": {
"ref": "sel_diu_4Hn8",
"revision": 2,
"fingerprint": "c029b155b21205f7f8917b1d8cc2ce86cc654cf45cfb0145b8abd5f507479faf",
"lines": [
{
"line_ref": "line_1",
"offering_ref": "off_diu_pdds",
"external_ref": "PDDS",
"title": "Professional Diploma in Data Science",
"quantity": 1,
"cohort_ref": "coh_diu_pdds_2027_01",
"unit_price": {
"amount": "45000.00",
"currency": "BDT"
}
}
]
},
"currency": "BDT",
"buyer": {
"payment_method_code": "bank_deposit"
},
"requested_mode": "binding"
}quote.calculate: your answer
{
"quote": {
"schema_version": "1.0",
"quote_ref": "quote_diu_88213",
"version": 1,
"selection_ref": "sel_diu_4Hn8",
"selection_revision": 2,
"selection_fingerprint": "c029b155b21205f7f8917b1d8cc2ce86cc654cf45cfb0145b8abd5f507479faf",
"currency": "BDT",
"mode": "binding",
"items": [
{
"line_ref": "line_1",
"offering_ref": "off_diu_pdds",
"external_ref": "PDDS",
"title": "Professional Diploma in Data Science",
"variant_label": "January 2027 intake",
"quantity": 1,
"unit_price": {
"amount": "45000.00",
"currency": "BDT"
},
"amount": {
"amount": "45000.00",
"currency": "BDT"
}
}
],
"fees": [],
"discounts": [],
"subtotal": {
"amount": "45000.00",
"currency": "BDT"
},
"total": {
"amount": "45000.00",
"currency": "BDT"
},
"payment_methods": [
{
"code": "bank_deposit",
"label": "Bank deposit to the DIU account",
"collected_offline": true
}
],
"expires_at": "2026-09-15T11:35:02Z",
"disclosures": [
"Tuition of ৳45,000.00 is payable by bank deposit within 14 days of acceptance.",
"DIU holds this amount until the quote expires; submitting after that needs a new quote."
],
"calculated_at": "2026-09-15T11:05:02Z"
}
}commit.create: the request Central AI sends
{
"kind": "enrollment",
"quote_ref": "quote_diu_88213",
"quote_version": 1,
"amount": {
"amount": "45000.00",
"currency": "BDT"
},
"selection_fingerprint": "c029b155b21205f7f8917b1d8cc2ce86cc654cf45cfb0145b8abd5f507479faf",
"terms_hash": "43815c8cb05660a58b85530a1301ad220d2a51bc1ac0c08af9c26fdb007c6b4c",
"selection": {
"ref": "sel_diu_4Hn8",
"revision": 2,
"lines": [
{
"line_ref": "line_1",
"offering_ref": "off_diu_pdds",
"external_ref": "PDDS",
"title": "Professional Diploma in Data Science",
"quantity": 1,
"cohort_ref": "coh_diu_pdds_2027_01",
"unit_price": {
"amount": "45000.00",
"currency": "BDT"
}
}
]
},
"customer": {
"name": "Nusrat Jahan",
"phone": "+8801900000031",
"email": "[email protected]",
"fields": {
"highest_degree": "BSc in Computer Science",
"graduation_year": "2024"
}
},
"payment_method_code": "bank_deposit",
"completion": {
"mode": "connector_write"
},
"channel": "web_widget",
"attribution": {
"operation_ref": "op_01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"commitment_ref": "cmt_diu_ad311"
}
}commit.create: your answer when the order is created (201)
{
"idempotency_key": "ca-op-01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"replayed": false,
"commitment": {
"reference": "AD-311",
"kind": "enrollment",
"statuses": {
"acceptance": "pending",
"payment": "unpaid",
"fulfilment": "not_started"
},
"terms_version": 1,
"amounts": {
"total": {
"amount": "45000.00",
"currency": "BDT"
},
"paid": {
"amount": "0.00",
"currency": "BDT"
},
"due": {
"amount": "45000.00",
"currency": "BDT"
}
},
"payment": {
"code": "bank_deposit",
"label": "Bank deposit to the DIU account",
"collected_offline": true
},
"provider_status": {
"application_status": "submitted",
"fee_status": "unpaid"
},
"created_at": "2026-09-15T11:07:31Z",
"updated_at": "2026-09-15T11:07:31Z",
"note": "Upload your graduation certificate on the admissions portal before 15 December 2026."
},
"attribution": {
"operation_ref": "op_01J8ZR7D5W3N8P1K6T2Y4M9Q0A"
}
}commit.create: your answer when the price changed (quote_mismatch, 200)
{
"idempotency_key": "ca-op-01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"replayed": false,
"quote": {
"schema_version": "1.0",
"quote_ref": "quote_diu_88213",
"version": 2,
"selection_ref": "sel_diu_4Hn8",
"selection_revision": 2,
"selection_fingerprint": "c029b155b21205f7f8917b1d8cc2ce86cc654cf45cfb0145b8abd5f507479faf",
"currency": "BDT",
"mode": "binding",
"items": [
{
"line_ref": "line_1",
"offering_ref": "off_diu_pdds",
"external_ref": "PDDS",
"title": "Professional Diploma in Data Science",
"variant_label": "January 2027 intake",
"quantity": 1,
"unit_price": {
"amount": "47000.00",
"currency": "BDT"
},
"amount": {
"amount": "47000.00",
"currency": "BDT"
}
}
],
"fees": [],
"discounts": [],
"subtotal": {
"amount": "47000.00",
"currency": "BDT"
},
"total": {
"amount": "47000.00",
"currency": "BDT"
},
"payment_methods": [
{
"code": "bank_deposit",
"label": "Bank deposit to the DIU account",
"collected_offline": true
}
],
"expires_at": "2026-09-15T11:37:40Z",
"disclosures": [
"Tuition for the January 2027 intake is now ৳47,000.00, payable by bank deposit within 14 days of acceptance.",
"DIU holds this amount until the quote expires; submitting after that needs a new quote."
],
"calculated_at": "2026-09-15T11:07:40Z"
},
"messages": [
{
"type": "error",
"code": "quote_mismatch",
"severity": "recoverable",
"content": "The tuition for this intake changed after you reviewed it, so nothing was submitted. Please review the updated amount.",
"path": "$.amount",
"mismatch": [
"amount",
"quote_version"
]
}
]
}commit.lookup: the request
{
"idempotency_key": "ca-op-01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"operation_ref": "op_01J8ZR7D5W3N8P1K6T2Y4M9Q0A"
}commit.lookup: found
{
"idempotency_key": "ca-op-01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"found": true,
"searched_at": "2026-09-15T11:08:05Z",
"commitment": {
"reference": "AD-311",
"kind": "enrollment",
"statuses": {
"acceptance": "pending",
"payment": "unpaid",
"fulfilment": "not_started"
},
"terms_version": 1,
"amounts": {
"total": {
"amount": "45000.00",
"currency": "BDT"
},
"paid": {
"amount": "0.00",
"currency": "BDT"
},
"due": {
"amount": "45000.00",
"currency": "BDT"
}
},
"provider_status": {
"application_status": "submitted",
"fee_status": "unpaid"
},
"created_at": "2026-09-15T11:07:31Z",
"updated_at": "2026-09-15T11:07:31Z"
},
"attribution": {
"operation_ref": "op_01J8ZR7D5W3N8P1K6T2Y4M9Q0A"
},
"retention_days": 30
}commit.lookup: never received (Central AI may send it again under the same key)
{
"idempotency_key": "ca-op-01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"found": false,
"searched_at": "2026-09-15T11:08:05Z",
"retention_expired": false,
"retention_days": 30
}catalog.search and availability.check (in the contract, not called yet)
{
"query": "data science diploma",
"kind": "course_intake",
"available_only": true,
"from_date": "2026-12-01",
"locale": "en",
"cursor": null,
"limit": 10
}
{
"items": [
{
"schema_version": "1.0",
"ref": "off_diu_pdds",
"external_ref": "PDDS",
"connector": "commerce_api",
"kind": "course_intake",
"title": "Professional Diploma in Data Science",
"subtitle": "January 2027 intake",
"description": "A one-year evening programme covering Python, statistics, machine learning and a capstone project.",
"category": "Professional diplomas",
"tags": [
"data science",
"python",
"machine learning"
],
"availability_mode": "seats",
"availability": {
"status": "seats_available",
"seats_available": 12,
"seats_total": 40,
"checked_at": "2026-09-15T11:00:05Z",
"display": "12 of 40 seats left"
},
"selection_schema": {
"cohorts": [
{
"ref": "coh_diu_pdds_2027_01",
"external_ref": "PDDS-2027-JAN",
"label": "January 2027 intake",
"starts_on": "2027-01-10",
"ends_on": "2027-12-16",
"application_deadline": "2026-12-15",
"seats_total": 40,
"seats_available": 12
}
],
"quantity": {
"min": 1,
"max": 1
}
},
"required_fields": [
{
"key": "name",
"label": "Full name as on your certificate",
"group": "learner",
"input": "text",
"required": true
},
{
"key": "phone",
"label": "Phone number",
"group": "contact",
"input": "phone",
"required": true
},
{
"key": "email",
"label": "Email",
"group": "contact",
"input": "email",
"required": true
},
{
"key": "highest_degree",
"label": "Highest degree",
"group": "learner",
"input": "text",
"required": true
},
{
"key": "graduation_year",
"label": "Graduation year",
"group": "learner",
"input": "number",
"required": true
}
],
"quote_required": false,
"price": {
"amount": "45000.00",
"currency": "BDT"
},
"price_label": "tuition, full programme",
"fulfilment_kind": "attendance",
"images": [
"https://admissions.diu.example/media/pdds-cover.jpg"
],
"page_url": "https://admissions.diu.example/programmes/pdds",
"disclosures": [
"Tuition of ৳45,000.00 is payable by bank deposit within 14 days of acceptance.",
"Seat numbers are a snapshot; DIU confirms the seat when it accepts the application."
],
"freshness_at": "2026-09-15T11:00:05Z"
}
],
"next_cursor": null,
"total_estimate": 1,
"freshness_at": "2026-09-15T11:00:05Z"
}
{
"lines": [
{
"line_ref": "line_1",
"offering_ref": "off_diu_pdds",
"external_ref": "PDDS",
"title": "Professional Diploma in Data Science",
"quantity": 1,
"cohort_ref": "coh_diu_pdds_2027_01"
}
]
}
{
"results": [
{
"line_ref": "line_1",
"available": true,
"availability_mode": "seats",
"seats_available": 12,
"current_price": {
"amount": "45000.00",
"currency": "BDT"
}
}
],
"checked_at": "2026-09-15T11:03:20Z"
}
Status events
When an order changes (accepted, paid, fulfilled, cancelled), your system posts a signed event to Central AI. Central AI’s endpoints for your system:
| Method | Path | What |
|---|---|---|
| GET | /.well-known/ucp | Central AI's UCP platform profile. keys[] holds the public key our requests are signed with. |
| POST | /webhooks/commerce/{connection_ref}/ | Where your system posts signed status events. The URL is shown on your connection. |
| POST | /webhooks/commerce/ | The webhook_url in our platform profile. Routed by the event's idempotency_key. |
Event types: commitment.accepted, commitment.canceled, commitment.created, commitment.rejected, commitment.updated, fulfilment.updated, payment.updated.
Events carry Webhook-Id (the event id, stable across retries) and Webhook-Timestamp, both signed.
A redelivered event is recognised and not applied twice, and an event older than the last one applied changes nothing.
- An event moves the three statuses (acceptance, payment, fulfilment) and the amount paid. It never changes the price, the items, the customer or the payment page.
- The customer is told in the chat when an order is accepted, rejected or cancelled, paid, refunded or failed, and when it is fulfilled.
Example event: an application accepted
{
"event_id": "evt_diu_5501",
"delivery_id": "dlv_diu_5501_1",
"type": "commitment.accepted",
"occurred_at": "2026-09-15T13:40:00Z",
"reference": "AD-311",
"idempotency_key": "ca-op-01J8ZR7D5W3N8P1K6T2Y4M9Q0A",
"attribution": {
"operation_ref": "op_01J8ZR7D5W3N8P1K6T2Y4M9Q0A"
},
"statuses": {
"acceptance": "accepted",
"payment": "unpaid",
"fulfilment": "not_started"
},
"previous_statuses": {
"acceptance": "pending",
"payment": "unpaid",
"fulfilment": "not_started"
},
"commitment": {
"reference": "AD-311",
"kind": "enrollment",
"statuses": {
"acceptance": "accepted",
"payment": "unpaid",
"fulfilment": "not_started"
},
"terms_version": 1,
"amounts": {
"total": {
"amount": "45000.00",
"currency": "BDT"
},
"paid": {
"amount": "0.00",
"currency": "BDT"
},
"due": {
"amount": "45000.00",
"currency": "BDT"
}
},
"payment": {
"code": "bank_deposit",
"label": "Bank deposit to the DIU account",
"collected_offline": true
},
"provider_status": {
"application_status": "accepted",
"fee_status": "unpaid"
},
"created_at": "2026-09-15T11:07:31Z",
"updated_at": "2026-09-15T13:40:00Z",
"note": "Upload your graduation certificate on the admissions portal before 15 December 2026."
},
"contract_version": "1.0"
}Taking payment with your own gateway
If your system already takes payment online (SSLCommerz, Stripe, bKash or Nagad checkout, or any other gateway), the customer pays there. Central AI never sees card details and never holds money.
- In your
quote.calculateanswer, list the payment methods your system takes, with"collected_offline": falsefor an online gateway (for example{"code": "sslcommerz", "label": "Card, bKash or Nagad (SSLCommerz)", "collected_offline": false}). The agent offers exactly these. - When
commit.createcreates the order, start the payment in your gateway as you do on your own checkout (an SSLCommerz session, a Stripe Checkout Session) and return its page in the commitment ascontinue_url(https), in that same answer. The customer’s order card shows Pay now, opening that page, and says Waiting for your payment. - When your gateway confirms the payment (its IPN or webhook to your system), post a status event with
statuses.paymentset topaid(andcommitment.amounts.paid). The customer is told in the chat, and the order shows Paid. A failed or cancelled payment isfailed, and the order card says so.
The payment page is taken only from your signed commit.create answer. A
status event can never set or change it, so a forged or replayed event cannot send a customer to another page.
Example: a quote offering SSLCommerz and Stripe
{
"quote": {
"schema_version": "1.0",
"quote_ref": "quote_goedu_7710",
"version": 1,
"selection_ref": "sel_goedu_2Kp4",
"selection_revision": 1,
"selection_fingerprint": "9a1f6c2d4b8e0f3a5c7d9e1b3f5a7c9e1d3b5f7a9c1e3d5b7f9a1c3e5d7b9f1a",
"currency": "BDT",
"mode": "binding",
"items": [
{
"line_ref": "line_1",
"offering_ref": "off_goedu_webdev",
"external_ref": "WEB-101",
"title": "Full-Stack Web Development",
"variant_label": "November 2026 batch",
"quantity": 1,
"unit_price": {
"amount": "12500.00",
"currency": "BDT"
},
"amount": {
"amount": "12500.00",
"currency": "BDT"
}
}
],
"fees": [],
"discounts": [],
"subtotal": {
"amount": "12500.00",
"currency": "BDT"
},
"total": {
"amount": "12500.00",
"currency": "BDT"
},
"payment_methods": [
{
"code": "sslcommerz",
"label": "Card, bKash or Nagad (SSLCommerz)",
"collected_offline": false
},
{
"code": "stripe",
"label": "International card (Stripe)",
"collected_offline": false
}
],
"expires_at": "2026-10-01T10:30:00Z",
"disclosures": [
"The seat is held for you for 30 minutes after you confirm, while you pay."
],
"calculated_at": "2026-10-01T10:00:00Z"
}
}Example: the order created, with its payment page (continue_url)
{
"idempotency_key": "ca-op-01K2GEDU7M3N8P1K6T2Y4M9Q0B",
"replayed": false,
"commitment": {
"reference": "ENR-2041",
"kind": "enrollment",
"statuses": {
"acceptance": "accepted",
"payment": "unpaid",
"fulfilment": "not_started"
},
"terms_version": 1,
"amounts": {
"total": {
"amount": "12500.00",
"currency": "BDT"
},
"paid": {
"amount": "0.00",
"currency": "BDT"
},
"due": {
"amount": "12500.00",
"currency": "BDT"
}
},
"payment": {
"code": "sslcommerz",
"label": "Card, bKash or Nagad (SSLCommerz)",
"collected_offline": false
},
"continue_url": "https://pay.goedu.example/checkout/ENR-2041",
"continue_url_expires_at": "2026-10-01T10:37:31Z",
"created_at": "2026-10-01T10:07:31Z",
"updated_at": "2026-10-01T10:07:31Z",
"note": "Your seat is held for 30 minutes while you pay."
},
"attribution": {
"operation_ref": "op_01K2GEDU7M3N8P1K6T2Y4M9Q0B"
}
}Example: the event that says it is paid
{
"event_id": "evt_goedu_9120",
"delivery_id": "dlv_goedu_9120_1",
"type": "payment.updated",
"occurred_at": "2026-10-01T10:12:04Z",
"reference": "ENR-2041",
"idempotency_key": "ca-op-01K2GEDU7M3N8P1K6T2Y4M9Q0B",
"attribution": {
"operation_ref": "op_01K2GEDU7M3N8P1K6T2Y4M9Q0B"
},
"statuses": {
"acceptance": "accepted",
"payment": "paid",
"fulfilment": "not_started"
},
"previous_statuses": {
"acceptance": "accepted",
"payment": "unpaid",
"fulfilment": "not_started"
},
"commitment": {
"reference": "ENR-2041",
"kind": "enrollment",
"statuses": {
"acceptance": "accepted",
"payment": "paid",
"fulfilment": "not_started"
},
"terms_version": 1,
"amounts": {
"total": {
"amount": "12500.00",
"currency": "BDT"
},
"paid": {
"amount": "12500.00",
"currency": "BDT"
},
"due": {
"amount": "0.00",
"currency": "BDT"
}
},
"payment": {
"code": "sslcommerz",
"label": "Card, bKash or Nagad (SSLCommerz)",
"collected_offline": false,
"reference": "SSLCZ-8F3K2Q",
"paid_at": "2026-10-01T10:12:00Z"
},
"created_at": "2026-10-01T10:07:31Z",
"updated_at": "2026-10-01T10:12:04Z",
"note": "Payment received. Class links arrive by email before the batch starts."
},
"contract_version": "1.3"
}Without a Commerce API connection you have three simpler options: Live checkout on your site, where the chat fills your cart, your checkout takes the payment and one signed webhook tells the chat; On our page, so the agent helps the customer choose and the card’s button opens your own checkout (where your gateway already is); or use Handled in Central AI with the Online payment method and your payment page link, and record the payment when it arrives. See How customers pay.
Errors
Refuse with the error.v1 envelope and the right category: it decides what Central AI does next,
and what the customer is told.
| Category | What Central AI does |
|---|---|
validation | The request was malformed or failed your checks. Nothing was created. |
authentication | The signature or the key did not verify. Nothing was created. |
authorization | The customer must finish directly with you (send a continue_url). |
unsupported_capability | You do not offer this operation. |
version_conflict | You do not speak the contract version Central AI sent. |
price_changed | The price moved: Central AI quotes again and asks the customer. |
out_of_stock | Sold out, full or taken: the customer is told and offered something else. |
hold_expired | A held seat or slot lapsed: Central AI quotes again. |
rate_limited | Too many calls (HTTP 429). On an order Central AI runs commit.lookup before anything else, so the order is never sent twice. |
unavailable_read | You could not answer a read just now: the agent says it cannot confirm it yet. |
definite_write_rejection | You refused the order and created nothing. A corrected order may follow under a new key. |
uncertain_write | You cannot say whether it was created: Central AI runs commit.lookup before anything else. |
Business refusal codes the agent explains to the customer:
hold_expired, insufficient_quantity, out_of_stock, price_changed, quote_mismatch, seats_full, slot_taken, sold_out, unavailable.
Protocol error codes (HTTP status, category, retryable)
| Code | HTTP | Category | Retry |
|---|---|---|---|
idempotency_conflict | 409 | definite_write_rejection | no |
idempotency_in_flight | 409 | uncertain_write | yes |
storage_unavailable | 503 | uncertain_write | yes |
complete_in_progress | 409 | uncertain_write | yes |
requires_escalation | 409 | authorization | no |
version_unsupported | 400 | version_conflict | no |
key_rotated | 401 | authentication | yes |
unknown_kid | 401 | authentication | yes |
idempotency_key_expired | 409 | definite_write_rejection | no |
signature_missing | 401 | authentication | no |
signature_invalid | 401 | authentication | no |
key_not_found | 401 | authentication | yes |
digest_mismatch | 400 | validation | no |
algorithm_unsupported | 400 | validation | no |
invalid_profile_url | 400 | validation | no |
profile_unreachable | 424 | unavailable_read | yes |
profile_not_trusted | 403 | authorization | no |
Connect it
- On AI Sales Agent, turn on Advanced in section 3; in Connection to your system (company admins), choose My own website, app or booking system (Commerce API).
- Enter the profile address (https) and the key your system issued for Central AI. The key is stored encrypted and never shown again. Press Save connection.
- Press Publish connection revision. Central AI reads and freezes your profile and pins its keys.
- Press Test connection. It re-reads the profile, sends one test order and looks it up, then shows a report. Orders are sent only while the last test passed.
- In section 3, set the kinds your system handles to Created in our system, and publish the settings.
Go-live checklist
- Your offerings are in Central AI with the
idthey have in your system. quote.calculateanswers with your real prices, delivery and the payment methods you accept.- The same
Idempotency-Keyand body replays your first answer; your keys are kept at least 7 days. - Every response and event is signed with the key in your discovery document; the signature test vectors pass.
- An online payment returns
continue_url, and your gateway’s confirmation posts apaidevent. - Test connection passed, the kinds are set to Created in our system, and one real order from the Playground reached your system and came back as events.
Conventions
- Money is
{"amount": "1250.00", "currency": "BDT"}: an exact decimal string and a currency code, never a JSON number. - Times are UTC ISO 8601 ending in
Z; dates areYYYY-MM-DD. - Links are absolute
https://addresses only. - Errors use the
error.v1envelope:code,category,safe_message,retryable,retry_after_seconds,operation_ref,correlation_id.
Signed-in administrators see every header, status and error code on the API reference.
Signed in? Your own keys, endpoint addresses and the full error tables are
on the API reference inside your dashboard. These public pages never show
anyone’s key: examples use placeholders such as YOUR_EXTERNAL_API_KEY.