Cart API
Send real-time cart and order data to Optico. Associate purchases with visitor sessions and call center interactions.
Introduction #
The Cart API pushes cart and order data to Optico in real time. Paired with the Optico Tracking service, it links every purchase to the visitor's session, source, keywords, and any calls they make. Agents see the caller's live cart, order history, and browsing journey inside the call center interface, and Optico ties the resulting revenue back to the marketing spend that produced it.
https://www.optico.fr
Transport & Conventions
| Method | All endpoints use POST |
| Content-Type | application/x-www-form-urlencoded |
| Response format | application/json |
| Parameter names | snake_case in requests, camelCase in responses |
| Timeout | 5 seconds recommended |
Authentication #
Every request must include your key as a POST field. The key is unique across all of your registered domains and is issued when your account is created on www.optico.fr.
key=b7e2c8a14f9d3650a1e7c4d8b2f6a395e
Errors #
Response envelope
Every request returns 200 OK with a JSON envelope. Branch on the status field rather than the HTTP status code.
Success
{ "status": "success" }
Error
{ "status": "error",
"message": "Invalid API key" }
Common error messages
| Message | Cause | Fix |
|---|---|---|
Invalid API key | The key is missing, revoked, or not registered for the calling domain. | Verify the key in your Optico account under Manage APIs. |
Missing required parameter | One or more required fields are absent or empty. | Log the submitted payload and compare it against the parameters table for the endpoint. |
Invalid products format | The products array could not be parsed. | Submit a valid array of product objects (see Products object). |
Unknown visit_id | The visit_id does not match any tracked visit. | Confirm the Optico Tracking cookie is set before posting cart/order data. |
Idempotency
Both endpoints are idempotent on your id field: re-submitting the same cart or order id updates the existing record instead of creating a duplicate. This is a deliberate design so your integration can safely retry on transient failures.
Retries & timeouts
Use a 5-second client timeout. A network timeout or an HTTP 5xx response is safe to retry with exponential backoff (for example 1s, 2s, 4s) because the endpoints are idempotent. Do not retry on a JSON {"status":"error"} body. The request was received and rejected; inspect the message and fix the payload.
Rate limits
No fixed public rate limit is enforced for normal traffic. Call the API on every cart and order change. If you plan a bulk backfill or expect sustained traffic above a few hundred requests per second, contact Optico in advance to size the channel for your account.
Endpoints #
| Endpoint | Method | Purpose |
|---|---|---|
/api/customer-cart | POST | Insert or update a shopping cart. Call on every cart change. |
/api/customer-order | POST | Insert or update an order. Call on every order creation and status change. |
POST /api/customer-cart #
Insert or update a shopping cart. Call this endpoint on every cart change.
Parameters
| Name | Type | Description | |
|---|---|---|---|
key | string | Required | Your API key (shared across all your domains): "b7e2c8a14f9d3650a1e7c4d8b2f6a395e" |
id | string | Required | Your cart id: "1" |
currency | string | Required | ISO 4217 currency code: "EUR" |
visit_id | string | Required | Visitor session id. See Integration for how to read it from cookies: "3617898c651df0f8617f70a0" |
products | array | Required | Cart items. See the Products object section for the object structure. |
is_logged_in | integer | Required | 1 if the buyer is authenticated, 0 otherwise. |
call_id | integer | Optional | Current call id when working alongside the Call Center API; links the cart to that call. |
agent | string | Optional | Current agent username when working alongside the Call Center API; links the cart to that agent. |
Example request
curl -X POST https://www.optico.fr/api/customer-cart \ --max-time 5 \ -d "key=b7e2c8a14f9d3650a1e7c4d8b2f6a395e" \ -d "id=1" \ -d "currency=EUR" \ -d "visit_id=3617898c651df0f8617f70a0" \ -d "is_logged_in=1" \ --data-urlencode 'products[0][id]=1' \ --data-urlencode 'products[0][name]=Product 1' \ --data-urlencode 'products[0][quantity]=2' \ --data-urlencode 'products[0][price]=29.99'
// Read visit ID from cookie (JS: optico_visitId / API: optico_visit_id) $visitId = $_COOKIE['optico_visit_id'] ?? ''; $params = [ 'key' => 'b7e2c8a14f9d3650a1e7c4d8b2f6a395e', 'id' => '1', 'currency' => 'EUR', 'visit_id' => $visitId, 'is_logged_in' => 1, 'products' => [[ 'id' => 1, 'name' => 'Product 1', 'quantity' => 2, 'price' => 29.99, 'details' => 'some product details', ]], ]; $ch = curl_init('https://www.optico.fr/api/customer-cart'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($params), CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, ]); $response = json_decode(curl_exec($ch), true); curl_close($ch);
// Node 18+ (built-in fetch). Read visit_id from your cookie store. const params = new URLSearchParams(); params.append('key', 'b7e2c8a14f9d3650a1e7c4d8b2f6a395e'); params.append('id', '1'); params.append('currency', 'EUR'); params.append('visit_id', visitId); params.append('is_logged_in', '1'); params.append('products[0][id]', '1'); params.append('products[0][name]', 'Product 1'); params.append('products[0][quantity]', '2'); params.append('products[0][price]', '29.99'); const res = await fetch('https://www.optico.fr/api/customer-cart', { method: 'POST', body: params, signal: AbortSignal.timeout(5000), }); const data = await res.json();
Response
Success
{ "status": "success" }
Error
{ "status": "error",
"message": "..." }
POST /api/customer-order #
Insert or update an order. Call this endpoint when an order is created and on every status change.
Parameters
| Name | Type | Description | |
|---|---|---|---|
key | string | Required | Your API key: "b7e2c8a14f9d3650a1e7c4d8b2f6a395e" |
id | string | Required | Your order id: "1" |
cart_id | string | Required | Id of the cart that produced this order: "1" |
currency | string | Required | ISO 4217 currency code: "EUR" |
visit_id | string | Required | Visitor session id. See Integration: "3617898c651df0f8617f70a0" |
products | array | Required | Order items. See the Products object section. |
status | string | Required | Current order status: "Completed". Use consistent spelling and language; the same values must be declared in Optico under Agents / Paramètres. |
call_id | integer | Optional | Current call id when working alongside the Call Center API. |
agent | string | Optional | Current agent username when working alongside the Call Center API. |
Example request
curl -X POST https://www.optico.fr/api/customer-order \ --max-time 5 \ -d "key=b7e2c8a14f9d3650a1e7c4d8b2f6a395e" \ -d "id=1" \ -d "cart_id=1" \ -d "currency=EUR" \ -d "visit_id=3617898c651df0f8617f70a0" \ -d "status=Completed" \ --data-urlencode 'products[0][id]=1' \ --data-urlencode 'products[0][name]=Product 1' \ --data-urlencode 'products[0][quantity]=2' \ --data-urlencode 'products[0][price]=29.99'
$visitId = $_COOKIE['optico_visit_id'] ?? ''; $params = [ 'key' => 'b7e2c8a14f9d3650a1e7c4d8b2f6a395e', 'id' => '1', 'cart_id' => '1', 'currency' => 'EUR', 'visit_id' => $visitId, 'status' => 'Completed', 'products' => [[ 'id' => 1, 'name' => 'Product 1', 'quantity' => 2, 'price' => 29.99, ]], ]; $ch = curl_init('https://www.optico.fr/api/customer-order'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($params), CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, ]); $response = json_decode(curl_exec($ch), true); curl_close($ch);
const params = new URLSearchParams(); params.append('key', 'b7e2c8a14f9d3650a1e7c4d8b2f6a395e'); params.append('id', '1'); params.append('cart_id', '1'); params.append('currency', 'EUR'); params.append('visit_id', visitId); params.append('status', 'Completed'); params.append('products[0][id]', '1'); params.append('products[0][name]', 'Product 1'); params.append('products[0][quantity]', '2'); params.append('products[0][price]', '29.99'); const res = await fetch('https://www.optico.fr/api/customer-order', { method: 'POST', body: params, signal: AbortSignal.timeout(5000), }); const data = await res.json();
Response
Success
{ "status": "success" }
Error
{ "status": "error",
"message": "..." }
Products object #
Each item in the products array is a product object with the following keys:
| Field | Type | Description | |
|---|---|---|---|
id | mixed | Required | Product id from your catalogue: 1 |
name | string | Required | Display name: "Product 1" |
quantity | integer | Required | Number of units: 2 |
price | float | Required | Unit price: 29.99 |
details | string or array | Optional | Free-form product information, displayed as-is in the agent dashboard. Can be a plain string or a nested array with any keys. |
Details field examples
Simple string
'details' => 'some product details'
Nested array
'details' => [ 'color' => 'blue', 'dimensions' => [ 'width' => '20cm', 'height' => '20cm', 'length' => '20cm' ] ]
Integration #
Getting the visit_id
The visit_id comes from the Optico Tracking service and identifies the visitor's session. Read it from the appropriate cookie depending on your tracking method:
| Tracking method | Cookie name | Example value |
|---|---|---|
| JS tracking | optico_visitId | 3617898c651df0f8617f70a0 |
| API tracking (using the Optico PHP example) | optico_visit_id | 3617898c651df0f8617f70a0 |
Integration flow
Connecting carts and orders to calls
When a visitor calls while the Call Center API is active, you may have access to the current call_id and the handling agent username. Pass these optional fields to directly associate the cart or order record with the specific call and agent; this enriches the call timeline visible to agents.