Sales API
REST · JSON v1.0 17 October 2019

Sales API

Record e-commerce orders and attribute revenue to calls, agents, and marketing sources for complete ROI tracking.

Introduction #

The Optico Sales API (Customer Order API) records e-commerce orders and maps them to calls for conversion tracking. Your call center can then attribute revenue and conversions to specific calls, agents, keywords, and marketing sources, so you know what each call is worth.

Base URL https://www.optico.fr

Transport & Conventions

MethodAll endpoints use POST
Content-Typeapplication/x-www-form-urlencoded
Response formatapplication/json
Timeout5 seconds recommended

Getting Started #

The Sales API is the final step in the Optico call center integration. It connects your e-commerce order management system with the call tracking platform to close the attribution loop between marketing spend and revenue.

Call Tracking API tracks visitors and issues visit_id values via the optico_visit_id cookie.
Cart API records live cart contents, visible to agents in real time during calls.
This API Sales API records confirmed orders and maps them to calls, enabling conversion rate and ROI reporting per keyword, source, agent, and campaign.
Prerequisites:
  • A domain with the Call Center feature enabled in Optico.
  • A Customer API key, available from domain settings in the Optico backend.
  • Order statuses configured in Optico's call center settings (some statuses marked as "is_sale" trigger conversion tracking).

Authentication #

Every request must include your key as a POST field. This is the Customer API key for your domain, the same key used by the Cart API.

Example
key=cust_b7e2c8a14f9dcdef01234567

Errors #

Response envelope

Every request returns 200 OK with a JSON envelope. Branch on the status field rather than the HTTP status code.

Success

json
{ "status": "success" }

Error

json
{ "status": "error",
  "message": "Invalid api key" }

Common error messages

MessageCauseFix
Invalid api keyThe key is missing, revoked, or not registered for the calling domain.Check the Customer API key in your domain settings.
Missing required parameterOne of id, status, or key is absent or empty.Log the request payload and confirm the required fields are present.
Unknown statusThe submitted status is not declared in your Optico call center settings.Declare the status under Call Center > Statuses, then retry. See Order Status Configuration.
Invalid products formatThe products field is not valid JSON.JSON-encode the product array before sending. See Products object.

Idempotency

The endpoint is idempotent on your id: re-submitting the same order id updates the existing record rather than creating a duplicate. Submit on order creation and on every status change.

Retries & timeouts

Use a 5-second client timeout. Network timeouts and HTTP 5xx responses are safe to retry with exponential backoff (1s, 2s, 4s) because the endpoint is idempotent. Do not retry on a JSON {"status":"error"} body. Fix the payload and resubmit.

Rate limits

No fixed public rate limit is enforced for normal order traffic. For a bulk backfill (migrations, historical imports) contact Optico support so the channel can be sized for your account.

Endpoints #

EndpointMethodPurpose
/api/customer-orderPOSTCreate or update an order record, linked to a call or visitor session.

POST /api/customer-order #

POST/api/customer-order

Creates or updates an order in Optico. If an order with the same id already exists for the domain, it is updated, making this endpoint idempotent. Submit on order creation and on every status change.

Parameters

ParameterTypeDescription
keystringRequiredCustomer API key for the domain.
idstringRequiredExternal order ID from your e-commerce system. Used to match subsequent updates to the same order.
statusstringRequiredOrder status string. Must match a status configured in Optico's call center settings. Determines whether the order counts as a sale. See Order Status Configuration.
cart_idstringOptionalExternal cart ID linking this order to a previously submitted cart (from the Cart API).
visit_idintegerOptionalOptico visit ID from the optico_visit_id cookie. Links the order to the visitor session.
call_idintegerOptionalOptico call ID. Directly associates the order with a specific call record.
agentstringOptionalCall center agent username who processed this order.
currencystringOptionalISO 4217 currency code (e.g. EUR, USD, GBP). Defaults to domain currency.
productsJSON stringOptionalJSON-encoded array of product objects. See Products object.

Example request

bash
curl -X POST https://www.optico.fr/api/customer-order \
  --max-time 5 \
  -d "key=cust_b7e2c8a14f9dcdef01234567" \
  -d "id=ORDER-5678" \
  -d "cart_id=CART-1234" \
  -d "visit_id=3617898c651df0f8617f70a0" \
  -d "status=confirmed" \
  -d "currency=EUR" \
  -d "agent=agent_john" \
  --data-urlencode 'products=[{"id":"PROD-001","name":"Blue Widget","quantity":2,"cost_per_unit":29.99},{"id":"PROD-007","name":"Red Gadget","quantity":1,"cost_per_unit":59.00}]'
$visitId = intval($_COOKIE['optico_visit_id'] ?? 0);

$params = [
    'key'      => 'cust_b7e2c8a14f9dcdef01234567',
    'id'       => 'ORDER-5678',
    'cart_id'  => 'CART-1234',
    'visit_id' => $visitId,
    'status'   => 'confirmed',
    'currency' => 'EUR',
    'agent'    => 'agent_john',
    'products' => json_encode([
        ['id' => 'PROD-001', 'name' => 'Blue Widget', 'quantity' => 2, 'cost_per_unit' => 29.99],
        ['id' => 'PROD-007', 'name' => 'Red Gadget',  'quantity' => 1, 'cost_per_unit' => 59.00],
    ]),
];

$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 products = [
  { id: 'PROD-001', name: 'Blue Widget', quantity: 2, cost_per_unit: 29.99 },
  { id: 'PROD-007', name: 'Red Gadget',  quantity: 1, cost_per_unit: 59.00 },
];

const body = new URLSearchParams({
  key:      'cust_b7e2c8a14f9dcdef01234567',
  id:       'ORDER-5678',
  cart_id:  'CART-1234',
  visit_id: visitId,
  status:   'confirmed',
  currency: 'EUR',
  agent:    'agent_john',
  products: JSON.stringify(products),
});

const res = await fetch('https://www.optico.fr/api/customer-order', {
  method: 'POST',
  body,
  signal: AbortSignal.timeout(5000),
});
const data = await res.json();

Products object #

The products parameter must be a JSON-encoded string containing an array of product objects.

FieldTypeDescription
idstringExternal product ID from your catalogue.
namestringProduct display name.
quantityintegerNumber of units ordered.
cost_per_unitfloatUnit price. Optico computes total_cost = sum(quantity × cost_per_unit).
detailsobjectKey-value pairs for any additional product attributes.
The total order value (used in Google Analytics e-commerce events) is computed automatically as the sum of quantity × cost_per_unit across all products. Always include accurate product costs for correct revenue reporting.

Order statuses #

The status field must match one of the statuses configured in your Optico account under Call Center > Statuses. Each status can optionally be flagged as is_sale.

Status typeExample valuesEffect in Optico
Sale statusconfirmed, paid, shippedOrder counts as a conversion. Google Analytics e-commerce event fired automatically. Revenue attributed to the call's keyword/source/agent.
Non-sale statuspending, cancelled, refundedOrder is saved and visible in reports but does not count as a conversion. No GA event fired.
The Google Analytics conversion event fires the first time an order transitions into a sale status (e.g. pendingconfirmed). Subsequent updates do not re-fire it.

Order lifecycle #

The following flow shows how the Sales API fits into a complete Optico call center integration:

1 · Page Load
Your sitecalls /ospView → Optico issues visitId → set optico_visit_id cookie
2 · Cart Activity
Visitoradds items to cart
Your sitePOSTs to /api/customer-cart (Cart API) with visit_id + products
3 · Call
Visitorcalls tracked number; Optico matches call to visit via visitId
Agentsees cart contents in real time via Agent API push
4 · Order Created
Your sitePOSTs to /api/customer-order with id, status=pending, cart_id, products
Optico{ "status": "success" }; order saved, not yet a sale
5 · Order Confirmed (Sale)
Your sitePOSTs to /api/customer-order with id, status=confirmed
Opticosaves order, fires Google Analytics e-commerce event, attributes revenue to call source
If neither visit_id nor call_id is provided, the order is saved but not attributed to any call or visitor session. Attribution, conversion rates, and Google Analytics events will be missing. Always include visit_id from the optico_visit_id cookie.