Integration guide for partner systems — POS, ordering sites, aggregators and dispatch platforms. If you were given an access key, you are in the right place.
What it does: you send us an order with a single HTTP request and it appears instantly to our available couriers. We then push every status change back to you, until the order is delivered.
What it does not do: it does not read menus and it does not process payments. The order arrives fully formed from your system.
Field names are in Romanian and stay that way — linii,
zona, metodaPlata, and so on. This page is translated; the API is not.
Copy the field names exactly as written here.
Each location has its own key, sent in the X-API-Key header on every request.
Keys look like lxk_ followed by 48 hex characters, and are issued by our dispatch team.
Keep the key server-side, never in a web page. If it ends up in front-end code, anyone can read it and place orders in your name. Call us from your backend.
POST https://europe-west1-lexina-delivery.cloudfunctions.net/apiComanda
# curl example
curl -X POST https://europe-west1-lexina-delivery.cloudfunctions.net/apiComanda \
-H "X-API-Key: lxk_your_key" \
-H "Content-Type: application/json" \
-d '{
"idExtern": "ORD-10432",
"sursa": "glovo",
"zona": "Brașov",
"client": {
"nume": "Maria Popescu",
"telefon": "0722123456",
"adresa": "Str. Lungă 24, bl. 3, ap. 12",
"lat": 45.6579,
"lng": 25.6012
},
"linii": [
{ "nume": "Pizza Diavola", "pret": 42.00, "cantitate": 2 },
{ "nume": "Coca-Cola 0.5", "pret": 9.00, "cantitate": 1 }
],
"taxaLivrare": 9.00,
"metodaPlata": "cash",
"observatii": "Intercom is broken, please call on arrival",
"esteGata": false
}'
| Field | Description |
|---|---|
| client.nume required | Customer name, at least 3 characters. |
| client.telefon required | Romanian number, 10 digits, starting with 07, 02 or 03. Non-digits are stripped before validation. |
| client.adresa required | Street, number and any detail that helps. At least 8 characters — the courier has to find it. |
| client.lat client.lng | Optional WGS84 coordinates. If present, we match the delivery zone against our drawn zone boundaries instead of parsing the address text — the most reliable way to get the tariff right. We use them to pick the zone and do not store them. |
| linii | Order lines: nume, pret, cantitate. The order value is computed from these. Quantity is clamped to 1–50. The courier sees the lines on their phone and checks the bag against them. |
| valoareMancare | Alternative to linii if your system cannot send the lines. Total food value, as a number. |
| taxaLivrare | The delivery fee you charge the customer. It stays yours. |
| zona | Delivery locality name, e.g. Brașov, Săcele. Used when no coordinates are sent. If omitted, the location's default zone applies. |
| zonaId | Our internal zone id, if you have been given one. Overrides both of the above. |
| metodaPlata | cash or card. With card the courier collects nothing. |
| idExtern | Your own order reference. Strongly recommended — it is what makes retries safe. |
| sursa | Where the order came from: telefonic, site, glovo, wolt, bolt. Shows up in reports. |
| observatii | Free text for the courier. |
| esteGata | true if the food is already prepared. Couriers see the label and come straight over. |
HTTP 201
{
"comandaId": "aBcD1234...",
"status": "asteptare",
"zona": "Brașov",
"total": 102.00
}
Send idExtern and retries are safe. If an order with the same
idExtern already exists for your location, you get 200 with
"duplicat": true and the original comandaId — no second order
is created. Without idExtern, a retried request creates a duplicate order and a
second courier run.
| Code | Meaning |
|---|---|
| 401 | Missing or invalid key. |
| 400 | Validation failed. The body names the exact field. |
| 403 | Account deactivated. |
| 405 | Wrong method — use POST. |
| 500 | Our side. Retry in a few seconds. |
Error bodies look like { "eroare": "client.telefon invalid (10 cifre)." }.
The message is in Romanian; the HTTP code is what you should branch on.
GET .../apiStareComanda?comandaId=... or ?idExtern=..., same header.
{
"comandaId": "aBcD1234...",
"status": "spre_client",
"curier": "Andrei M.",
"esteGata": true,
"livratLa": null
}
Use this for reconciliation or spot checks. For live tracking, use webhooks below — polling gives you stale data and costs both of us requests.
| Status | Meaning |
|---|---|
| neconfirmat | Waiting for the location to confirm |
| asteptare | Looking for a courier |
| preluat | Picked up by a courier |
| la_restaurant | Courier is at the location |
| spre_client | On the way to the customer |
| livrat | Delivered |
| anulat | Cancelled |
| retur | Going back to the location |
| returnat | Returned to the location |
| de_ridicat | Waiting for customer pickup |
| livrare_restaurant | Delivered by the location's own driver |
Rather than you asking us what happened, we tell you. Give us an https://
endpoint and we POST to it on every status change, from "looking for a courier"
through to "delivered".
We configure the endpoint on our side — send it to us together with your key request. You
then receive a signing secret (prefixed lws_), shown once.
By default we notify only orders that arrived through this API. Orders typed into our own portal are not pushed to you unless you ask us to enable that.
POST https://your-system.com/lexina-status
Content-Type: application/json
User-Agent: LexinaDelivery-Webhook/1
X-Lexina-Eveniment: stare_comanda
X-Lexina-Semnatura: 9f2c... // HMAC-SHA256 of the raw body
{
"eveniment": "stare_comanda",
"comandaId": "aBcD1234...",
"idExtern": "ORD-8841",
"sursa": "glovo",
"status": "livrat",
"statusEticheta": "Livrată",
"restaurant": { "id": "rest_x", "nume": "Pizza Oscar" },
"curier": { "nume": "Andrei M.", "telefon": "07XXXXXXXX" },
"client": { "nume": "Ioana P.", "telefon": "07XXXXXXXX", "adresa": "Str. Lungă 12, Brașov" },
"zona": "Brașov oraș",
"sume": { "mancare": 84.5, "livrare": 15, "total": 99.5 },
"metodaPlata": "cash",
"incident": null,
"timp": {
"creata": "2026-09-25T17:02:11.000Z",
"confirmata": "2026-09-25T17:03:40.000Z",
"preluata": "2026-09-25T17:09:02.000Z",
"laClient": "2026-09-25T17:24:55.000Z",
"livrata": "2026-09-25T17:26:10.000Z"
},
"trimisLa": "2026-09-25T17:26:11.412Z"
}
curier is null until someone picks the order up. Each field inside
timp is null until that moment happens. statusEticheta is
the same status written in Romanian, ready to display. incident is non-null when
something went wrong in the field — customer unreachable, wrong address, missing items — with
tip, eticheta and rezolvat.
Anyone can POST to your endpoint. To know a message is really from us, compute
HMAC-SHA256 over the raw request body using your secret and compare it to the
X-Lexina-Semnatura header.
// Node.js const signature = crypto.createHmac("sha256", SECRET) .update(rawBody) // the exact bytes received, not re-serialised JSON .digest("hex"); if (signature !== req.headers["x-lexina-semnatura"]) return res.sendStatus(401); // PHP $signature = hash_hmac('sha256', $rawBody, $SECRET); if (!hash_equals($signature, $_SERVER['HTTP_X_LEXINA_SEMNATURA'])) { http_response_code(401); exit; }
Re-serialising the JSON before hashing is the usual reason a signature check fails — key order and whitespace change, and so does the hash.
200 as soon as you have the message. Process it afterwards.429 or 5xx we retry up to 3 times, after 2 and 4 seconds.
On 400–499 we stop: that means you rejected the request on purpose.comandaId + status.https. Private addresses
(localhost, 10.x, 192.168.x, .local) are rejected when saved.We can fire a test event at your endpoint from our admin panel — same structure, with a
test comandaId — so you can verify the integration before a real order exists.
We also keep a delivery log: if something never arrives, we can tell you exactly what your
server responded and how many attempts we made.
Worth knowing before you design around us:
idExtern. Network errors make you retry, and without it you risk a duplicate order and a second delivery fee.client.lat / client.lng when you have them. Zone and tariff then follow the map, not the spelling of the address.esteGata only when the food is genuinely ready. It is the signal couriers use to choose which order to take.Google Cloud, europe-west1 (Belgium). Typical round trip from Romania is a few
tens of milliseconds. No IP allowlisting is required on your side.