{"openapi":"3.0.3","info":{"title":"Kurir.Express API","version":"1.0.0","description":"Two APIs, one set of rules.\n\n**Partner API** (`/v1/partner/*`, key prefix `kek_`) — place and track deliveries from your own system:\ne-commerce back office, warehouse software, restaurant POS.\n\n**Operator API** (`/v1/operator/*`, key prefix `kok_`) — run your own courier company from your own dispatch\nsoftware: see the offers and the open pool, answer them for a named courier, move orders through their\nlifecycle, confirm delivery, report positions and read the ledger. Everything behind it is the same machinery\nthe Kurir.Express courier app uses — the API is a second transport for the same offers, not a second dispatch.\nAn offer answered here carries the same `offer_id` the app would have shown, and whoever answers second gets a 409.\nPositions you report are what keeps a courier visible on the customer's map and findable by dispatch, so a\ncourier you stop reporting for falls asleep on the same timeout as one whose phone went dark.\n\n**Authentication.** Every request carries `Authorization: Bearer <api key>`. Keys are issued by Kurir.Express\nstaff in the admin console; the secret is shown once, at creation, and stored only as a hash.\nA revoked key stops working on the very next request. A key of the wrong kind gets `403` — merchant keys have no\naccess to `/v1/operator/*`, operator keys have none to `/v1/partner/*`. An operator key is bound to one company\n(country + tax id) and can see and act for that company's activated couriers only; anyone else's courier or\norder answers `404`, never `403`: we do not confirm that they exist.\n\n**Rate limit.** Requests are counted per key in a sliding one-minute window. The default is a platform setting\n(60/min at the time of writing) and can be raised per key. Over the limit you get `429` with a `Retry-After` header.\n\n**Idempotency.** Send `Idempotency-Key` on every creating call. A repeat with the same key and the same body\nreturns the stored response instead of creating a second delivery.\n\n**Money.** All amounts are integers in the minor unit of the order currency (cents for EUR). The platform does not\nprocess card payments: you settle with the courier directly, exactly as a private customer would.\n\n**Pricing and bidding.** Services the platform prices itself (documents, parcel) are quoted through\n`POST /v1/partner/quotes`, and the signed `quote_token` must be passed to order creation. Everything else — pallets,\ntrucks, moves, and any cross-border pair — has no platform price: `POST /v1/partner/quotes` answers\n`422 SERVICE_NOT_QUOTABLE`, the order is created without a token, and couriers name the price. Either watch the\n`bid.received` webhook and accept a bid, or set `auto_accept_max_price_minor` and let the first bid at or below\nyour ceiling win automatically.\n\n**Webhooks.** Configure endpoints through your Kurir.Express contact. Each delivery carries\n`X-Kurir-Signature: t=<unix>,v1=<hex hmac-sha256(secret, t + \".\" + body)>`, `X-Kurir-Event` and `X-Kurir-Delivery`.\nVerify the signature and reject timestamps older than five minutes. Any 2xx counts as delivered; failures are retried\non a schedule (1, 5, 30, 120, 480 minutes by default) and then marked dead. Polling the order endpoints is always a\nvalid alternative to webhooks.\n\nMerchant keys can subscribe to: `order.status`, `courier.assigned`, `bid.received`, `order.delivered`, `order.failed`, `order.cancelled`.\nOperator keys can subscribe to: `offer.new`, `offer.result`, `order.update`, `order.cancelled_by_client`, `balance.low`.\n`offer.new` and `offer.result` are the same frames the courier app receives, and `balance.low` fires when a\ncommission charge takes a courier below the country minimum — below it, dispatch stops offering them work.","contact":{"name":"Kurir.Express","url":"https://kurir.express"}},"servers":[{"url":"https://api.kurir.express","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Quotes","description":"Price a delivery before ordering it."},{"name":"Orders","description":"Create, list, inspect and cancel deliveries."},{"name":"Bidding","description":"Couriers name a price; you accept one."},{"name":"Tracking","description":"Live status, courier and position."},{"name":"Fleet","description":"Operator API: the couriers registered under your company."},{"name":"Offers","description":"Operator API: answer offers and take orders from the open pool."},{"name":"Fleet orders","description":"Operator API: the orders your couriers are holding."},{"name":"Telemetry","description":"Operator API: report courier positions."},{"name":"Ledger","description":"Operator API: commission, cash liabilities and top-ups."}],"paths":{"/v1/operator/couriers":{"get":{"tags":["Fleet"],"summary":"List your couriers","description":"Every active courier registered on the platform under your company tax id, with the vehicle, the online toggle, the last known position and the orders they are currently holding. Couriers who have not been activated by the platform are not listed: you cannot act for them either.","operationId":"operatorListCouriers","responses":{"200":{"description":"Your fleet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorCouriers"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl https://api.kurir.express/v1/operator/couriers -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/offers":{"get":{"tags":["Offers"],"summary":"Live offers and the open pool","description":"Two lists. `offers` are live, addressed offers your couriers are being asked to answer right now — the very same offers the courier app would show, with the remaining `ttl_ms`, not a fresh countdown. `pool` is the open showcase in each courier's country and dispatch radius, with `courier_ids` telling you which of your couriers can take each order. Answering an offer is a decision on a timer; taking from the pool is not.","operationId":"operatorListOffers","responses":{"200":{"description":"Live offers and the pool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorOffers"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl https://api.kurir.express/v1/operator/offers -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/offers/{id}/accept":{"post":{"tags":["Offers"],"summary":"Accept an offer for one of your couriers","description":"Takes the order at the offered price, exactly as the courier tapping \"Accept\" would. The offer is one and the same object on both transports: if the courier answered from the app a moment earlier, you get 409 — and so would they, had you been first.","operationId":"operatorAcceptOffer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id, exactly as it was delivered to the courier (webhook `offer.new`, or GET /v1/operator/offers)."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorOfferAnswer"}}}},"responses":{"200":{"description":"The order is now assigned to your courier.","content":{"application/json":{"schema":{"type":"object","properties":{"offer_id":{"type":"string"},"order_id":{"type":"string"},"outcome":{"type":"string","example":"WON"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The offer is gone, belongs to another courier, or the courier cannot take it (balance, COD cap, KYC).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/offers/OFFER_ID/accept -H 'Content-Type: application/json' -d '{\"courier_id\":\"COURIER_ID\"}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/offers/{id}/decline":{"post":{"tags":["Offers"],"summary":"Decline an offer","description":"The next candidate is offered the order on the same dispatch tick. Declining counts against the courier's acceptance rate exactly as it does in the app — the API is a second transport, not a second rulebook.","operationId":"operatorDeclineOffer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id, exactly as it was delivered to the courier (webhook `offer.new`, or GET /v1/operator/offers)."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorOfferAnswer"}}}},"responses":{"200":{"description":"Declined.","content":{"application/json":{"schema":{"type":"object","properties":{"offer_id":{"type":"string"},"order_id":{"type":"string"},"outcome":{"type":"string","example":"DECLINED"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The offer is gone or belongs to another courier.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/offers/OFFER_ID/decline -H 'Content-Type: application/json' -d '{\"courier_id\":\"COURIER_ID\"}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/offers/{id}/counter":{"post":{"tags":["Offers"],"summary":"Name your own price for an offer","description":"Same rule as in the app: a price at or below the platform price assigns the order to your courier immediately, a higher one goes to the customer as a bid. Services without a platform price (pallets, trucks, moves) and any cross-border pair are priced this way only.","operationId":"operatorCounterOffer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id, exactly as it was delivered to the courier (webhook `offer.new`, or GET /v1/operator/offers)."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorCounterRequest"}}}},"responses":{"200":{"description":"Bid placed (or the order assigned outright).","content":{"application/json":{"schema":{"type":"object","properties":{"offer_id":{"type":"string"},"order_id":{"type":"string"},"bid_id":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The offer is gone, does not allow counters, or the courier cannot take the order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/offers/OFFER_ID/counter -H 'Content-Type: application/json' -d '{\"courier_id\":\"COURIER_ID\",\"price_minor\":4500,\"eta_pickup_min\":25}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/pool/{orderId}/claim":{"post":{"tags":["Offers"],"summary":"Take an order from the open pool","description":"Assigns a pool order to your courier at the platform price, the same way the courier would from the showcase. The race is settled by the database, so two operators claiming the same order end with exactly one winner and one 409.","operationId":"operatorClaimFromPool","parameters":[{"name":"orderId","in":"path","required":true,"schema":{"type":"string"},"description":"Order id from the `pool` list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorOfferAnswer"}}}},"responses":{"200":{"description":"Taken.","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company, or no such order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already taken, reserved by a live bid, or the courier cannot take it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/pool/ORDER_ID/claim -H 'Content-Type: application/json' -d '{\"courier_id\":\"COURIER_ID\"}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/orders":{"get":{"tags":["Fleet orders"],"summary":"Orders your couriers are holding","description":"Newest first, across the whole company. Page with `cursor` from `next_cursor`; a null `next_cursor` means the last page. `cross_border` and `dropoff_country_code` are here because a dispatcher decides who to send before the courier ever sees the order.","operationId":"operatorListOrders","parameters":[{"name":"status","in":"query","schema":{"type":"string"},"description":"Filter by order status."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":50}}],"responses":{"200":{"description":"A page of orders.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorOrders"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl 'https://api.kurir.express/v1/operator/orders?status=PICKED_UP' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/orders/{id}":{"get":{"tags":["Fleet orders"],"summary":"Get one order","description":"An order held by one of your couriers. An order held by someone else answers 404, not 403: we do not confirm that another company's order exists.","operationId":"operatorGetOrder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."}],"responses":{"200":{"description":"The order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorOrder"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such order among your couriers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl https://api.kurir.express/v1/operator/orders/ORDER_ID -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/orders/{id}/status":{"post":{"tags":["Fleet orders"],"summary":"Move an order through its lifecycle","description":"The same state machine, the same guards and the same side effects as the courier app: illegal transitions answer 409, FAILED requires a reason, PICKED_UP sends the recipient their delivery PIN by SMS. Delivery itself has its own endpoint (see /pod) because it needs proof.","operationId":"operatorSetOrderStatus","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorStatusRequest"}}}},"responses":{"200":{"description":"Moved.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"from":{"type":"string"}}}}}},"400":{"description":"A guard refused: missing failure reason, missing coordinates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company, or the order is not theirs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Illegal transition for the current status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/orders/ORDER_ID/status -H 'Content-Type: application/json' -d '{\"courier_id\":\"COURIER_ID\",\"to\":\"PICKED_UP\",\"lat\":42.4304,\"lng\":19.2594}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/orders/{id}/pod":{"post":{"tags":["Fleet orders"],"summary":"Confirm delivery","description":"Proof of delivery: either the four-digit `pin` the recipient received by SMS, or `photo_upload_id` — the key of a photo uploaded through POST /v1/uploads. Coordinates are optional: the last position you reported for that courier is used, and the country's geofence radius is checked against it exactly as it is for the app. Delivery is where the platform commission is charged.","operationId":"operatorConfirmDelivery","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorPodRequest"}}}},"responses":{"200":{"description":"Delivered.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","example":"DELIVERED"},"from":{"type":"string"}}}}}},"400":{"description":"Wrong PIN, foreign photo key, or the courier is outside the delivery geofence.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company, or the order is not theirs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The order is not at the dropoff point yet, or is already closed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/orders/ORDER_ID/pod -H 'Content-Type: application/json' -d '{\"courier_id\":\"COURIER_ID\",\"pin\":\"1234\"}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/locations":{"post":{"tags":["Telemetry"],"summary":"Report courier positions","description":"A batch of track points. Every point takes the same path as a position frame from the app: it keeps the courier present for dispatch, feeds the live map the customer watches, and refreshes \"alive\". This is also what puts a courier online in the first place — a courier you stop reporting for falls asleep on the same timeout as one whose phone went dark. The batch size limit is a platform setting (200 at the time of writing) and is reported in the 422 body when exceeded.","operationId":"operatorReportLocations","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorLocationsRequest"}}}},"responses":{"200":{"description":"Accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"integer"},"couriers":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A courier in the batch is not yours; the whole batch is rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Batch larger than the configured maximum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/operator/locations -H 'Content-Type: application/json' -d '{\"locations\":[{\"courier_id\":\"COURIER_ID\",\"lat\":42.4304,\"lng\":19.2594,\"ts\":1788643648000}]}' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/operator/ledger":{"get":{"tags":["Ledger"],"summary":"Read your couriers' ledger","description":"Platform commission charged on delivery, cash-on-delivery liabilities, top-ups and adjustments, newest first. Read-only: money is moved by people in the console, not by an integration. A positive amount grows the courier's position, a negative one shrinks it.","operationId":"operatorReadLedger","parameters":[{"name":"courier_id","in":"query","schema":{"type":"string"},"description":"One courier; omit for the whole company."},{"name":"before","in":"query","schema":{"type":"string"},"description":"Cursor: `next_before` from the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","maximum":200,"default":50}}],"responses":{"200":{"description":"A page of ledger entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorLedger"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an operator key, or the key carries no company scope (country + tax id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such courier in your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl 'https://api.kurir.express/v1/operator/ledger?limit=20' -H 'Authorization: Bearer kok_YOUR_KEY'"}},"/v1/partner/quotes":{"post":{"tags":["Quotes"],"summary":"Quote a delivery","description":"Returns a price and a signed `quote_token` valid for a few minutes. Services without a platform price (and any cross-border pair) answer `422 SERVICE_NOT_QUOTABLE` with `details.quoting = \"bids\"` — create the order without a token and let couriers bid.","operationId":"partnerCreateQuote","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"}}}},"responses":{"200":{"description":"Price and signed token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed, or the service is not quotable (SERVICE_NOT_QUOTABLE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/partner/quotes \\\n  -H 'Authorization: Bearer kek_YOUR_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"service\":\"EXPRESS\",\"delivery_service\":\"parcel\",\"from\":{\"lat\":42.4304,\"lng\":19.2594},\"to\":{\"lat\":42.4425,\"lng\":19.2762},\"parcel\":{\"weight_kg\":2,\"fragile\":false},\"payment_methods\":[\"cash\"]}'"}},"/v1/partner/orders":{"post":{"tags":["Orders"],"summary":"Create an order","description":"Creates a normal Kurir.Express delivery owned by the account behind your key. Pass `quote_token` for a quoted service, or omit it and pass `delivery_service` for bidding. `external_ref` is your own order number: it is required and must be unique per key.","operationId":"partnerCreateOrder","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerCreateOrderRequest"}}}},"responses":{"201":{"description":"Order created and dispatched to couriers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"external_ref already used by this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed (a missing `external_ref` lands here), or IDEMPOTENCY_MISMATCH.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/partner/orders \\\n  -H 'Authorization: Bearer kek_YOUR_KEY' \\\n  -H 'Idempotency-Key: shop-order-1042' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"external_ref\":\"1042\",\"quote_token\":\"<from /v1/partner/quotes>\",\"pickup\":{\"location\":{\"lat\":42.4304,\"lng\":19.2594},\"contact\":{\"name\":\"Shop\",\"phone\":\"+38269000003\"}},\"dropoff\":{\"location\":{\"lat\":42.4425,\"lng\":19.2762},\"contact\":{\"name\":\"Ana\",\"phone\":\"+38269000004\"}},\"parcel\":{\"weight_kg\":2,\"fragile\":false},\"payment_methods\":[\"cash\"]}'"},"get":{"tags":["Orders"],"summary":"List your orders","description":"Newest first. Only orders created through this key are listed. Page with `cursor` from `next_cursor`; a null `next_cursor` means the last page.","operationId":"partnerListOrders","parameters":[{"name":"external_ref","in":"query","schema":{"type":"string"},"description":"Exact match on your own order number."},{"name":"status","in":"query","schema":{"type":"string"},"description":"Filter by order status."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":50}}],"responses":{"200":{"description":"A page of orders.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl 'https://api.kurir.express/v1/partner/orders?status=SEARCHING' -H 'Authorization: Bearer kek_YOUR_KEY'"}},"/v1/partner/orders/batch":{"post":{"tags":["Orders"],"summary":"Create several orders at once","description":"Best-effort batch: each element succeeds or fails on its own, and one bad address does not cancel the other nineteen deliveries. The response mirrors the request order. The maximum batch size is a platform setting (50 at the time of writing) and is reported in the 422 body when exceeded. Best-effort covers business errors only: a malformed element — one missing the required `external_ref`, say — rejects the whole request with 422, because the request itself did not parse.","operationId":"partnerCreateOrdersBatch","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Repeat-safe token chosen by you. Replaying the same key with the same body returns the stored response (header `Idempotent-Replay: true`); the same key with a different body is rejected with 422 IDEMPOTENCY_MISMATCH."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/PartnerCreateOrderRequest"}}}}}}},"responses":{"200":{"description":"Per-element outcome.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"external_ref":{"type":"string"},"ok":{"type":"boolean"},"order":{"$ref":"#/components/schemas/Order"},"error":{"$ref":"#/components/schemas/Error"}}}},"created":{"type":"integer"},"failed":{"type":"integer"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Batch larger than the configured maximum, or validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/partner/orders/batch -H 'Authorization: Bearer kek_YOUR_KEY' -H 'Content-Type: application/json' -d '{\"orders\":[…]}'"}},"/v1/partner/orders/{id}":{"get":{"tags":["Orders"],"summary":"Get one order","description":"Full card of your order, including the courier once assigned and a freshly signed `pod_photo_url` (valid for 15 minutes) once the delivery is photographed. Someone else's order answers 404, not 403.","operationId":"partnerGetOrder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."}],"responses":{"200":{"description":"The order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such order for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl https://api.kurir.express/v1/partner/orders/ORDER_ID -H 'Authorization: Bearer kek_YOUR_KEY'"}},"/v1/partner/orders/{id}/cancel":{"post":{"tags":["Orders"],"summary":"Cancel an order","description":"Allowed while the order has not been handed over. The state machine decides: a delivered order answers 409 ILLEGAL_TRANSITION.","operationId":"partnerCancelOrder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":300}}}}}},"responses":{"200":{"description":"Cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"cancel_reason":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such order for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The order can no longer be cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/partner/orders/ORDER_ID/cancel -H 'Authorization: Bearer kek_YOUR_KEY'"}},"/v1/partner/orders/{id}/bids":{"get":{"tags":["Bidding"],"summary":"List open bids","description":"Courier offers for an order that has no platform price. Cheapest first; expired bids are not shown.","operationId":"partnerListBids","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."}],"responses":{"200":{"description":"Open bids.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"order_price_cents":{"type":"integer","nullable":true},"currency":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such order for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl https://api.kurir.express/v1/partner/orders/ORDER_ID/bids -H 'Authorization: Bearer kek_YOUR_KEY'"}},"/v1/partner/orders/{id}/bids/{bidId}/accept":{"post":{"tags":["Bidding"],"summary":"Accept a bid","description":"Assigns the courier who made this bid; the bid price becomes the order price. Losing the race to another courier answers 409 OFFER_LOST, an expired bid 409 OFFER_EXPIRED.","operationId":"partnerAcceptBid","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."},{"name":"bidId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Courier assigned.","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"bid_id":{"type":"string"},"price_cents":{"type":"integer"},"eta_pickup_min":{"type":"integer"},"status":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such order or bid for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The bid is no longer acceptable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl -X POST https://api.kurir.express/v1/partner/orders/ORDER_ID/bids/BID_ID/accept -H 'Authorization: Bearer kek_YOUR_KEY'"}},"/v1/partner/orders/{id}/track":{"get":{"tags":["Tracking"],"summary":"Track an order","description":"Status, courier (with phone while the order is live), live position while the courier physically holds the parcel, ETAs and a short public tracking link you can forward to the recipient.","operationId":"partnerTrackOrder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Platform order id returned by POST /v1/partner/orders."}],"responses":{"200":{"description":"Tracking snapshot.","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"external_ref":{"type":"string"},"public_code":{"type":"string"},"status":{"type":"string"},"courier":{"type":"object","nullable":true,"additionalProperties":true},"location":{"type":"object","nullable":true,"properties":{"lat":{"type":"number"},"lng":{"type":"number"}}},"eta":{"type":"object","additionalProperties":true},"track_url":{"type":"string","nullable":true,"example":"https://kurir.cc/Ab3d"}}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such order for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-curl":"curl https://api.kurir.express/v1/partner/orders/ORDER_ID/track -H 'Authorization: Bearer kek_YOUR_KEY'"}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","description":"Your API key, issued by Kurir.Express. Example: `Authorization: Bearer kek_…`."}},"schemas":{"Error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"VALIDATION"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}},"Order":{"type":"object","description":"An order as the platform sees it. Same shape the mobile app receives.","properties":{"id":{"type":"string"},"public_code":{"type":"string","example":"KE-4H7K-2M"},"external_ref":{"type":"string","description":"Your own order number. Required on create, unique per API key."},"status":{"type":"string","example":"SEARCHING"},"delivery_service":{"type":"string","example":"parcel"},"price_cents":{"type":"integer","description":"Minor units of `currency`. Zero means \"not priced yet\" (bidding)."},"currency":{"type":"string","example":"EUR"},"courier":{"type":"object","nullable":true,"additionalProperties":true},"auto_accept_max_price_minor":{"type":"integer","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"QuoteRequest":{"type":"object","properties":{"service":{"type":"string","enum":["EXPRESS","STANDARD"]},"delivery_service":{"type":"string","enum":["documents","parcel","pallet","van","freight","container","moving","car_transport"]},"from":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]},"to":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]},"parcel":{"type":"object","properties":{"weight_kg":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":100},"dims_cm":{"type":"object","properties":{"l":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":300},"w":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":300},"h":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":300}},"required":["l","w","h"]},"description":{"type":"string","maxLength":500},"value_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"fragile":{"default":false,"type":"boolean"}},"required":["weight_kg"]},"cod_cents":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"payment_methods":{"minItems":1,"type":"array","items":{"type":"string","enum":["cash","card","transfer","qr"]}},"scheduled_for":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["service","from","to","parcel","payment_methods"]},"QuoteResponse":{"type":"object","properties":{"quote_token":{"type":"string"},"price_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"payout_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","enum":["EUR","RSD","BAM","MKD","ALL"]},"routed_km":{"type":"number","minimum":0},"min_vehicle":{"type":"string","enum":["bike","scooter","car","van"]},"breakdown":{"type":"object","properties":{"base_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"distance_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"weight_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"options_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"cod_fee_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"vehicle_multiplier":{"type":"number"},"surge":{"type":"number","minimum":1,"maximum":2},"vehicle":{"type":"string","enum":["bike","scooter","car","van"]},"vehicle_uplift_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"surge_uplift_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"peak_applied":{"type":"boolean"},"night_applied":{"type":"boolean"},"weather_applied":{"type":"boolean"},"min_fare_applied":{"type":"boolean"},"min_fare_uplift_cents":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["base_cents","distance_cents","weight_cents","options_cents","cod_fee_cents","vehicle_multiplier","surge"],"additionalProperties":false},"expires_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["DROPOFF_COUNTRY_UNSERVED"]},"country":{"nullable":true,"type":"string"},"message":{"type":"string"}},"required":["code","country","message"],"additionalProperties":false}}},"required":["quote_token","price_cents","payout_cents","currency","routed_km","min_vehicle","breakdown","expires_at"],"additionalProperties":false},"PartnerCreateOrderRequest":{"type":"object","properties":{"quote_token":{"type":"string"},"delivery_service":{"type":"string","enum":["documents","parcel","pallet","van","freight","container","moving","car_transport"]},"pickup":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]},"label":{"type":"string","maxLength":200},"notes":{"type":"string","maxLength":500},"saved_address_id":{"type":"string","minLength":10,"maxLength":40},"contact":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"phone":{"type":"string"}},"required":["phone"]}},"required":["location","contact"]},"dropoff":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]},"label":{"type":"string","maxLength":200},"notes":{"type":"string","maxLength":500},"saved_address_id":{"type":"string","minLength":10,"maxLength":40},"contact":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"phone":{"type":"string"}},"required":["name","phone"]}},"required":["location","contact"]},"parcel":{"type":"object","properties":{"weight_kg":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":100},"dims_cm":{"type":"object","properties":{"l":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":300},"w":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":300},"h":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":300}},"required":["l","w","h"]},"description":{"type":"string","maxLength":500},"value_cents":{"type":"integer","minimum":0,"maximum":9007199254740991},"fragile":{"default":false,"type":"boolean"}},"required":["weight_kg"]},"cod_cents":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"payment_methods":{"minItems":1,"type":"array","items":{"type":"string","enum":["cash","card","transfer","qr"]}},"client_notes":{"type":"string","maxLength":500},"scheduled_pickup_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"scheduled_dropoff_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"external_ref":{"type":"string","minLength":1,"maxLength":64},"auto_accept_max_price_minor":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":9007199254740991}},"required":["pickup","dropoff","payment_methods","external_ref"],"description":"Exactly one of `quote_token` (quoted services) or `delivery_service` (bidding) is required — a rule that JSON Schema cannot express, so it is enforced by the server and stated here."},"WebhookEvent":{"type":"object","description":"Body of every webhook delivery. Which events an endpoint may subscribe to depends on the key: merchant keys get order.status, courier.assigned, bid.received, order.delivered, order.failed, order.cancelled; operator keys get offer.new, offer.result, order.update, order.cancelled_by_client, balance.low.","properties":{"event":{"type":"string","enum":["order.status","courier.assigned","bid.received","order.delivered","order.failed","order.cancelled","offer.new","offer.result","order.update","order.cancelled_by_client","balance.low"]},"occurred_at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}},"OperatorCouriers":{"type":"object","properties":{"couriers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"nullable":true,"type":"string"},"phone":{"nullable":true,"type":"string"},"vehicle":{"type":"string"},"status":{"type":"string"},"online":{"type":"boolean"},"location":{"nullable":true,"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"active_orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"public_code":{"type":"string"}},"required":["id","status","public_code"],"additionalProperties":false}}},"required":["id","name","phone","vehicle","status","online","location","active_orders"],"additionalProperties":false}}},"required":["couriers"],"additionalProperties":false},"OperatorOffers":{"type":"object","properties":{"offers":{"type":"array","items":{"type":"object","properties":{"offer_id":{"type":"string"},"courier_id":{"type":"string"},"order_id":{"type":"string"},"public_code":{"nullable":true,"type":"string"},"ttl_ms":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"allow_counter":{"type":"boolean"},"price_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"payout_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"cod_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"nullable":true,"type":"string"},"pickup":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff_country_code":{"nullable":true,"type":"string"},"cross_border":{"type":"boolean"}},"required":["offer_id","courier_id","order_id","public_code","ttl_ms","allow_counter","price_minor","payout_minor","cod_minor","currency","pickup","dropoff","dropoff_country_code","cross_border"],"additionalProperties":false}},"pool":{"type":"array","items":{"type":"object","properties":{"order_id":{"type":"string"},"public_code":{"type":"string"},"service":{"type":"string"},"price_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"cod_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string"},"pickup":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff_country_code":{"nullable":true,"type":"string"},"cross_border":{"type":"boolean"},"created_at":{"type":"string"},"courier_ids":{"type":"array","items":{"type":"string"}}},"required":["order_id","public_code","service","price_minor","cod_minor","currency","pickup","dropoff","dropoff_country_code","cross_border","created_at","courier_ids"],"additionalProperties":false}}},"required":["offers","pool"],"additionalProperties":false},"OperatorOrder":{"type":"object","properties":{"id":{"type":"string"},"public_code":{"type":"string"},"courier_id":{"type":"string"},"status":{"type":"string"},"payout_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"cod_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string"},"pickup":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff_country_code":{"nullable":true,"type":"string"},"cross_border":{"type":"boolean"},"recipient":{"type":"object","properties":{"name":{"nullable":true,"type":"string"},"phone":{"nullable":true,"type":"string"}},"required":["name","phone"],"additionalProperties":false},"created_at":{"type":"string"},"assigned_at":{"nullable":true,"type":"string"},"delivered_at":{"nullable":true,"type":"string"}},"required":["id","public_code","courier_id","status","payout_minor","cod_minor","currency","pickup","dropoff","dropoff_country_code","cross_border","recipient","created_at","assigned_at","delivered_at"],"additionalProperties":false},"OperatorOrders":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"public_code":{"type":"string"},"courier_id":{"type":"string"},"status":{"type":"string"},"payout_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"cod_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string"},"pickup":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff":{"type":"object","properties":{"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"label":{"nullable":true,"type":"string"},"city":{"nullable":true,"type":"string"}},"required":["location","label","city"],"additionalProperties":false},"dropoff_country_code":{"nullable":true,"type":"string"},"cross_border":{"type":"boolean"},"recipient":{"type":"object","properties":{"name":{"nullable":true,"type":"string"},"phone":{"nullable":true,"type":"string"}},"required":["name","phone"],"additionalProperties":false},"created_at":{"type":"string"},"assigned_at":{"nullable":true,"type":"string"},"delivered_at":{"nullable":true,"type":"string"}},"required":["id","public_code","courier_id","status","payout_minor","cod_minor","currency","pickup","dropoff","dropoff_country_code","cross_border","recipient","created_at","assigned_at","delivered_at"],"additionalProperties":false}},"next_cursor":{"nullable":true,"type":"string"}},"required":["items","next_cursor"],"additionalProperties":false},"OperatorLedger":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"courier_id":{"type":"string"},"txn_id":{"type":"string"},"kind":{"type":"string"},"order_id":{"nullable":true,"type":"string"},"account":{"type":"string"},"amount_minor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"created_at":{"type":"string"}},"required":["courier_id","txn_id","kind","order_id","account","amount_minor","currency","created_at"],"additionalProperties":false}},"next_before":{"nullable":true,"type":"string"}},"required":["items","next_before"],"additionalProperties":false},"OperatorOfferAnswer":{"type":"object","properties":{"courier_id":{"type":"string","minLength":1,"maxLength":64},"reason":{"type":"string","maxLength":100}},"required":["courier_id"]},"OperatorCounterRequest":{"type":"object","properties":{"courier_id":{"type":"string","minLength":1,"maxLength":64},"price_minor":{"type":"integer","minimum":0,"maximum":9007199254740991},"eta_pickup_min":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":20160}},"required":["courier_id","price_minor","eta_pickup_min"]},"OperatorStatusRequest":{"type":"object","properties":{"courier_id":{"type":"string","minLength":1,"maxLength":64},"to":{"type":"string","minLength":1,"maxLength":32},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"accuracy_m":{"type":"number","minimum":0},"failure_reason":{"type":"string","minLength":1,"maxLength":300},"note":{"type":"string","maxLength":300}},"required":["courier_id","to"]},"OperatorPodRequest":{"type":"object","properties":{"courier_id":{"type":"string","minLength":1,"maxLength":64},"pin":{"type":"string","pattern":"^\\d{4}$"},"photo_upload_id":{"type":"string","minLength":1,"maxLength":300},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"note":{"type":"string","maxLength":300}},"required":["courier_id"],"description":"Exactly one of `pin` or `photo_upload_id` is required — a rule JSON Schema cannot express, so it is enforced by the server and stated here."},"OperatorLocationsRequest":{"type":"object","properties":{"locations":{"minItems":1,"type":"array","items":{"type":"object","properties":{"courier_id":{"type":"string","minLength":1,"maxLength":64},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"acc":{"type":"number","minimum":0},"spd":{"type":"number","minimum":0},"hdg":{"type":"number","minimum":0,"maximum":360},"ts":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":9007199254740991}},"required":["courier_id","lat","lng","ts"]}}},"required":["locations"]}}}}