A single set of APIs for Kazakhstan's Delivery Partners, with just two core resources — Job (the pickup task) and Package (each item within a Job). Accept jobs, deliver door-to-door (intra-city / inter-city), and hand packages off to partner carriers. Integrate with your own system, or use the delivery.atasuai.com console directly.
Every partner does the same thing: pick up, transport, deliver. Waybill records, labels, and carrier tracking numbers are all generated centrally by Atasuai — a rider with nothing but a phone can start today. Partners who can run their own carrier handoff can unlock it as an add-on capability.
Accept pickup jobs, pick up the whole batch, update each Package status, and submit proof of delivery. Scope deliveries:read · deliveries:write
Every Package comes with a tracking number and label, read-only. Scope tracking:read
Reserve barcodes, print blank waybills, and generate a carrier handoff manifest (e.g. QazPost Form 103). Scope consolidation:write
A seller bundles multiple packages into a single Job (Тапсырма), picks a pickup window, and publishes it; today it's an open marketplace — every online Agent can see pending Jobs, and whoever calls accept first wins (exclusive dispatch and the 10-minute reassignment timer are still Planned). Pickup is at the Job level (the rider takes the whole batch at once), while the destination is at the Package level — a single Job can mix both of the types below, and after pickup each item is routed by its own destination.
Runs on Atasuai's own delivery network. After pickup, the package goes straight to the buyer's door — intra-city or inter-city (depending on the Agent's service area), with no third-party carrier involved.
First-mile pickup. After pickup, the package is handed off to a branch of one of our integrated third-party carriers (carrier_code: qazpost / filp / …) — the carrier tracking number is issued from Atasuai's centralized number pool.
carrier_codeThe Delivery domain has only two core resources. A Job is a pickup task published by a seller and dispatched to a single Agent; a Package is each item within a Job, each with its own destination and status. Learn these two and you've mastered the entire delivery integration.
// Published by the seller; any online Agent can claim it (first to accept wins) { "id": "job_4471", "batch_no": "PB-4471", "status": "pending", "accept_deadline": "2026-07-22T09:18:32Z", // informational only, not enforced yet "seller": { "name": "Oscar ЖК" }, "pickup": { "address": "Алматы, Абай 150, оф.3", "window": { "from": "14:00", "to": "16:00" }, "pickup_by": "2026-07-22T16:00:00Z" }, "courier": null, // optional "totals": { "package_count": 6, "total_weight_kg": 6.5 }, "packages": [ "pkg_88213", "…" ] }
// Each item within a Job, with its own destination and status { "id": "pkg_88213", "job_id": "job_4471", "tracking_number": "AI556489715KZ", "destination": "carrier", // door | carrier "carrier_code": "qazpost", // when carrier "status": "pending", "recipient": { "name": "Елена", "phone": "+7 7•• •••" }, "weight_kg": 0.7, "cod": null }
Pickup is at the Job level (the whole batch is taken at once); delivery/handoff is at the Package level (updated item by item after pickup).
pending ──accept──▶ accepted │ │ │ pickup (whole batch) │ ▼ │ picked_up ──▶ completed │ ├─(auto-reassign on timeout — planned, not enforced)─▶ expired └─(seller cancels)────▶ cancelled
pending ▶ picked_up ▶ in_transit ▶ out_for_delivery ▶ verify // OTP verification ▶ delivered ✕ failed / returned
pending ▶ picked_up ▶ handed_off // Form 103 handoff ── carrier takes over ── ▶ in_transit ▶ delivered ✕ exception
Each door-to-door Package (destination=door) is designed to be delivered and confirmed individually — the recipient will confirm in person with a one-time code issued by the platform, preventing wrongful collection. Take AI0123423443KZ as an example. Anything marked Planned — endpoint, event, or rule — is not implemented yet and is shown for roadmap purposes only; the delivery-confirmation flow that actually works today is the out-for-delivery / deliver endpoints in the API reference below.
// ① The rider arrives at the door and requests a code for this package POST …/packages/pkg_88213/delivery-code → The platform sends an SMS to the recipient / a push to the buyer's app → The code goes only to the recipient and is never returned to the partner // ② The recipient reads out the code and the rider submits it for verification POST …/packages/pkg_88213/verify { "code": "4821" } → 200 { "status": "delivered", "delivered_at": "2026-07-22T15:12Z" }
delivered and serves as the proof of delivery (POD) for that item./packages/{id}/proof.These are hard contracts. Follow them when integrating with your own system; if you'd rather not build your own, use the delivery.atasuai.com console directly — the capabilities are identical.
pending Job is visible to all Agents (GET /jobs?status=pending), and whoever calls accept first wins — late callers get 409. accept_deadline is returned but not enforced; exclusive dispatch, the 10-minute timer, and auto-reassignment via job.expired are all Planned.destination (door / carrier) and an independent status. A single Job can mix both destinations.POST /jobs/{id}/pickup takes the whole batch); delivery/handoff is at the Package level, item by item: POST /packages/{id}/out-for-delivery → /deliver (failed attempts go through /delivery-failed, returns through /return); carrier handoff is POST /jobs/{id}/handoff. The generic POST /packages/{id}/status is not implemented yet, Planned./packages/{id}/delivery-code sends the code, /packages/{id}/verify verifies it as delivered; neither endpoint is implemented yet. Today's equivalent flow: POST /packages/{id}/out-for-delivery issues the code for door packages, and POST /packages/{id}/deliver requires that code (for door) to confirm delivery, with optional photo proof and recipient name.POST /jobs/{id}/courier is not required — you can proceed without assigning a courier (consistent with the console).POST /jobs/{id}/handoff generates it (e.g. QazPost Form 103), and POST /jobs/{id}/form103 rebuilds it; consolidation:write allows self-service use.carrier_code.Idempotency-Key (the header is accepted); however the Delivery API does not yet dedupe / replay idempotently, Planned — don't rely on it to prevent duplicate submissions. Errors use RFC 7807 problem+json; lists use cursor pagination; rate limiting is per-tenant.jobs:write) + check tracking (tracking:read); Agents integrate to accept and fulfill (deliveries:*, consolidation:write). Agent credentials are temporarily disabled (/oauth/token returns 503 for agent keys); seller credentials are unaffected.Done in three steps. Machine-to-machine — no user login, no redirect flow.
Obtain a client_id and client_secret from the partner console, or from Atasuai during onboarding. The secret is shown only once. Agent (delivery-partner) credentials are temporarily disabled (/oauth/token returns 503 for agent keys); seller credentials work normally.
Exchange your credentials for a scoped bearer token, valid for 15 minutes (900 seconds).
# POST /oauth/token curl -u $ID:$SECRET \ https://open.atasuai.com/oauth/token \ -d grant_type=client_credentials \ -d scope="deliveries:write"
Call the API with your token. Write operations require an Idempotency-Key.
# Accept a pending Job (first come, first served — first to accept wins) curl -X POST \ …/delivery/v1/jobs/{id}/accept \ -H "Authorization: Bearer $TOKEN" \ -H "Idempotency-Key: $(uuidgen)"
Every resource follows the same conventions — learn one endpoint and you know them all.
Client-credentials tokens carry a tenant and a set of scopes. You see only what you've been granted — deliveries:*, tracking:read, and so on.
Write operations should carry an Idempotency-Key — the header is accepted, but the Delivery API does not yet dedupe / replay it, so retries can create duplicate records; debounce on your own side for now.
Status changes are pushed proactively and signed with HMAC (sha256={ts}.{body}), with replay protection; retries follow 5s, 30s, 2m, 10m, 30m, 2h, 6h, 12h, 24h, 48h — 10 attempts over about 4 days.
RFC 7807 problem+json, with a stable error_code and a request_id for troubleshooting — parse once, apply everywhere.
Planned. The gateway does not rate-limit today and returns no Retry-After / X-RateLimit-* headers. A per-tenant token bucket lands before launch.
A fully isolated environment at sandbox.open.atasuai.com is coming soon (certificate not yet ready, not serving externally). Identical contract, test barcodes, zero real packages or money.
Subscribe once; you can also poll GET /delivery/v1/jobs?status=pending for the current pending list. Events marked Planned are not actually pushed yet.
Paths are split by domain and versioned. Endpoints marked Planned are not implemented yet and are shown for roadmap purposes only. See the docs site for the full interactive reference.
| Method | Endpoint | Scope |
|---|---|---|
| Jobs pickup tasks · /delivery/v1 | ||
| GET | /delivery/v1/jobs?status=pending (all pending jobs, visible to everyone) | deliveries:read |
| GET | /delivery/v1/jobs/{id} (with packages) | deliveries:read |
| POST | /delivery/v1/jobs/{id}/accept (first-come-first-served; returns 409 if already accepted) | deliveries:write |
| POST | /delivery/v1/jobs/{id}/decline | deliveries:write |
| POST | /delivery/v1/jobs/{id}/courier (optional) | deliveries:write |
| POST | /delivery/v1/jobs/{id}/pickup (pick up the whole batch) | deliveries:write |
| POST | /delivery/v1/jobs/{id}/complete (picked_up → completed) | deliveries:write |
| POST | /delivery/v1/jobs/{id}/handoff (Form 103 / handoff manifest) | consolidation:write |
| POST | /delivery/v1/jobs/{id}/form103 (rebuild the QazPost Form 103) | consolidation:write |
| POST | /delivery/v1/jobs (seller creates a job) Planned | jobs:write |
| POST | /delivery/v1/jobs/{id}/cancel (seller cancels) Planned | jobs:write |
| Packages · /delivery/v1 | ||
| GET | /delivery/v1/jobs/{id}/packages | deliveries:read |
| GET | /delivery/v1/packages/{id} | deliveries:read |
| GET | /delivery/v1/packages/{id}/delivery (last-mile state, never returns the code) | deliveries:read |
| POST | /delivery/v1/packages/{id}/out-for-delivery (start/retry last mile; issues the code for door) | deliveries:write |
| POST | /delivery/v1/packages/{id}/deliver (confirm delivery; door requires the code, optional photo/recipient name) | deliveries:write |
| POST | /delivery/v1/packages/{id}/delivery-failed (record a failed attempt, retryable) | deliveries:write |
| POST | /delivery/v1/packages/{id}/return (mark returned) | deliveries:write |
| POST | /delivery/v1/packages/{id}/status (per-item status) Planned | deliveries:write |
| POST | /delivery/v1/packages/{id}/delivery-code (send one-time code) Planned | deliveries:write |
| POST | /delivery/v1/packages/{id}/verify (verify code and sign off) Planned | deliveries:write |
| POST | /delivery/v1/packages/{id}/proof (fallback sign-off / COD) Planned | deliveries:write |
| GET | /delivery/v1/packages/{id}/label Planned | tracking:read |
| GET | /delivery/v1/tracking/{tracking_number} Planned | tracking:read |
| POST | /delivery/v1/packages/{id}/location (not enabled) Planned | deliveries:write |
| Webhook · /delivery/v1 | ||
| POST | /delivery/v1/webhook-subscriptions | webhooks:manage |
Create API credentials in your partner console, or have your Atasuai account manager provision them during onboarding (Agent credentials are temporarily disabled; seller credentials work normally). No system of your own? Run your entire fleet on the Atasuai-hosted console — same capabilities, nothing to build.