Skip to content

Integration quickstart

The integration API lives under /api/v1/integration/*, is versioned and does not change incompatibly within v1. The full reference — API интегратора in the sidebar — is built from the same specification the system itself runs on.

The company administrator creates a key on Access control → API keys: name, scopes, requests per minute (2000 by default). The key value is shown once.

Scope Grants
orders:write create/update orders, cancel, refuse, rebox, payment, mini-statuses, tags
orders:read pull orders with statuses
trips:read pull trips
vehicles:read read vehicles
couriers:write sync drivers

Send it with every request: Authorization: ApiKey <key>. Check it with GET /api/v1/integration/whoami.

POST /api/v1/integration/orders/sync is an upsert by externalId: resending the same externalId updates the order instead of creating a second one — retries are safe. Bulk: POST /api/v1/integration/orders/sync/bulk (per-item results and errors).

Validated at the door (400 with a field and a code otherwise): every line has requestedQty > 0 (orders.line.requestedQty.invalid), non-negative weight/volume (orders.line.measure.invalid), a productId and warehouseId that exist in your company and are not archived (orders.line.product.notFound, orders.line.warehouse.notFound, field lines[i].productId / lines[i].warehouseId), and at least one address with coordinates (orders.coordinates.required).

For an order to be plannable it needs address coordinates, a delivery window, and weight/volume on its lines. A line without dimensions is not treated as zero — the planner refuses with a reason code.

Re-sending and lines. While the order is not on a trip (New, InPlanning) and none of its lines has an outcome, a re-sync updates the lines: a line keeping its code keeps its id and takes the new quantity/weight/volume, a new code is added, a missing one is removed. Once the order is planned or has an outcome, a changed line answers 409 orders.lines.immutable — the correction is refused, not silently dropped. Re-sending a cancelled order brings it back: 200, outcome: "Restored", status New.

GET /api/v1/integration/orders?since=2026-09-03T00:00:00Z&limit=200
→ { "items": [ … ], "nextCursor": "eyJ…" }
GET /api/v1/integration/orders?cursor=eyJ…

The cursor is opaque; keep the last nextCursor and continue from it. null means you are caught up. Same for trips: GET /api/v1/integration/trips.

Order statuses: New → InPlanning → Planned → InProgress → FullyDelivered | PartiallyDelivered | Returned | Collected | PartiallyCollected | NotCollected | Refused | Cancelled → Closed. A Pickup or Return order ends Collected (everything collected), PartiallyCollected or NotCollected where a delivery ends FullyDelivered, PartiallyDelivered or Returned; a Rebox order uses the delivery statuses and is FullyDelivered only when the new item was handed over and the old one collected. The list can grow: treat a status you do not know as not final rather than as an error.

Every error is a Problem Details body whose type is a code from the error catalog; validation errors carry errors per field. Rate limit is per key per minute: 429, type: orders.rate_limited, Retry-After.