Get credentials
Pre-release. This API is in active development and is not yet open to external partners. Endpoints and events marked Planned are published for review and are not available yet. Nothing here is billable or rate-limited yet.
Partner API · v1 · Jobs & Packages

Ship every package with Atasuai.

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.

Pre-release — not serving yet OAuth 2.0 REST · JSON Sandbox included
Integration model

Everyone shares one shipping API; carrier handoff unlocks on demand.

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 Jobs, fulfill Packages

All partners

Accept pickup jobs, pick up the whole batch, update each Package status, and submit proof of delivery. Scope deliveries:read · deliveries:write

Tracking & labels (read-only)

All partners

Every Package comes with a tracking number and label, read-only. Scope tracking:read

Self-service handoff → carrier

Optional capability

Reserve barcodes, print blank waybills, and generate a carrier handoff manifest (e.g. QazPost Form 103). Scope consolidation:write

One Job, many Packages

Two destinations for a Package

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.

destination: door

Door-to-door delivery (intra-city / inter-city)

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.

  • Delivered to the buyer's door (same city or another city)
  • Status comes entirely from the rider's per-item updates
  • Uses an internal tracking number AD-…, without consuming a carrier tracking number
  • Whether to collect cash on delivery (COD) is up to the seller
AD-4471-02 Internal tracking number
destination: carrier

Carrier handoff

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.

  • Delivered to the carrier's branch; you report status up to the handoff
  • After handoff, the carrier takes over tracking
  • Carrier tracking numbers and labels are issued per carrier_code
  • The handoff manifest (e.g. QazPost Form 103) is generated automatically or self-service
Tracking number TRK-4471902 Assigned by the carrier
The two resources you integrate with

Jobs and Packages

The 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.

Job · pickup task (Тапсырма)
// 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", "…" ]
}
Package · package (Посылка)
// 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
}
State machine

How status flows

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).

Job lifecycle
pending ──accept──▶ accepted
   │              │
   │           pickup (whole batch)
   │              ▼
   │         picked_up ──▶ completed
   │
   ├─(auto-reassign on timeout — planned, not enforced)─▶ expired
   └─(seller cancels)────▶ cancelled
Package · destination=door
pendingpicked_upin_transitout_for_deliveryverify // OTP verificationdeliveredfailed / returned
Package · destination=carrier
pendingpicked_uphanded_off  // Form 103 handoff
  ── carrier takes over ──in_transitdeliveredexception
Delivery verification

One-time code (OTP) sign-off Planned

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.

Delivery verification flow Planned
// ① 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" }
One-time code rules Planned
  • The code is 4–6 digits, valid for 5 minutes.
  • Resending a code for the same package is rate-limited to at least 60 seconds apart, up to 5 resends total.
  • A successful verification means delivered and serves as the proof of delivery (POD) for that item.
  • More than 5 consecutive wrong entries lock it; a new code must be sent.
  • The code is issued only to the recipient, and the API never returns it in plaintext — preventing wrongful collection and partner-side entry.
  • If the recipient can't receive the code, use the fallback sign-off (photo / signature) /packages/{id}/proof.
  • COD packages: collect payment first, then verify the code — confirmed in one step.
  • Applies only to door; for carrier, the last mile after handoff is the carrier's responsibility.
Integration rules

Rules (normative)

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.

  1. Today it's an open marketplace: every 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.
  2. A Job contains 1..N Packages; each has an independent destination (door / carrier) and an independent status. A single Job can mix both destinations.
  3. Pickup is at the Job level (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.
  4. Planned Delivery verification: the design is for door packages to be signed off with a one-time code — /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.
  5. Courier is optional: POST /jobs/{id}/courier is not required — you can proceed without assigning a courier (consistent with the console).
  6. carrier items need a handoff manifest: POST /jobs/{id}/handoff generates it (e.g. QazPost Form 103), and POST /jobs/{id}/form103 rebuilds it; consolidation:write allows self-service use.
  7. Tracking numbers: door uses the internal number AD-…; carrier issues a carrier tracking number from the centralized number pool per carrier_code.
  8. Least-privilege: credentials carry only the granted scopes and can access only this tenant's data; any over-reach (e.g. touching orders/inventory) returns 403.
  9. Write operations should carry an 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.
  10. Two kinds of integrators: sellers integrate to create Jobs (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.
  11. Environment isolation: open.atasuai.com (production); sandbox.open.atasuai.com Planned (certificate not yet ready, not serving externally). The key prefix encodes the environment (atk_test_ / atk_live_).
Quickstart

From getting credentials to your first call

Done in three steps. Machine-to-machine — no user login, no redirect flow.

STEP 01

Get your credentials

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.

STEP 02

Exchange for an access token

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"
STEP 03

Accept a Job (Тапсырма)

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)"
Built on predictable foundations

Core concepts

Every resource follows the same conventions — learn one endpoint and you know them all.

OAuth 2.0 and scopes

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.

Idempotency Planned

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.

Signed webhooks

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.

Standardized errors

RFC 7807 problem+json, with a stable error_code and a request_id for troubleshooting — parse once, apply everywhere.

Rate limiting

Planned. The gateway does not rate-limit today and returns no Retry-After / X-RateLimit-* headers. A per-tenant token bucket lands before launch.

Sandbox Planned

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.

Events, delivered to you

Webhook events

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.

Job lifecycle  ·  Atasuai → partner

PUSHjob.acceptedAgent accepted the job
PUSHjob.courier_assignedA courier was assigned
PUSHjob.picked_upThe whole batch was picked up
PUSHjob.completedThe job is complete
PUSHjob.cancelledCancelled by the seller
PUSHjob.dispatchedA new job is dispatched to you Planned
PUSHjob.updatedThe job changed before acceptance Planned
PUSHjob.expiredNot accepted in time, reassigned Planned

Package lifecycle  ·  per item / carrier callbacks  Planned

PKGpackage.picked_upPicked up
PKGpackage.handed_offHanded off to the carrier
PKGpackage.in_transitIn transit
PKGpackage.out_for_deliveryLast mile
PKGpackage.deliveredDelivered to the recipient
PKGpackage.exceptionStuck or returned
# Verify every push
X-Atasuai-Signature: sha256=<hex>  X-Atasuai-Timestamp: <unix>
HMAC_SHA256(secret, "{timestamp}.{raw_body}")  ·  reject if older than 5 minutes  ·  deduplicate by X-Atasuai-Event-Id
API reference

API reference

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.

MethodEndpointScope
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}/declinedeliveries: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) Plannedjobs:write
POST/delivery/v1/jobs/{id}/cancel (seller cancels) Plannedjobs:write
Packages · /delivery/v1
GET/delivery/v1/jobs/{id}/packagesdeliveries: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) Planneddeliveries:write
POST/delivery/v1/packages/{id}/delivery-code (send one-time code) Planneddeliveries:write
POST/delivery/v1/packages/{id}/verify (verify code and sign off) Planneddeliveries:write
POST/delivery/v1/packages/{id}/proof (fallback sign-off / COD) Planneddeliveries:write
GET/delivery/v1/packages/{id}/label Plannedtracking:read
GET/delivery/v1/tracking/{tracking_number} Plannedtracking:read
POST/delivery/v1/packages/{id}/location (not enabled) Planneddeliveries:write
Webhook · /delivery/v1
POST/delivery/v1/webhook-subscriptionswebhooks:manage

Pre-release: try it against production, sandbox coming soon.

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.