Developers · Integration API

Call a courier from your own software.

Connect your order, ERP or warehouse system straight to Courino: get the price, create the order and hear back through a signed webhook when it is delivered. In your courier company's panel the order looks just like one entered by hand.

Turkish version of the docs: API dokümanı (Türkçe)

REST + JSONOpenAPI 3Try it live in SwaggerHMAC-signed webhooksIdempotency-Key
What is ready?

Everything a courier integration needs

Every order task you do by hand in the portal can also be done through the API. The price comes from the same calculation as the price list your courier company set up for you.

REST + OpenAPI 3

JSON bodies and clear error codes (application/problem+json). Download the OpenAPI file and generate a client in your own language.

Try it live in Swagger

Paste your key into Authorize in the docs and try every endpoint from the browser with your real account. In English and Turkish.

Signed webhooks

Picked up, delivered, cancelled… every event arrives signed with X-KOS-Signature (HMAC-SHA256). If your endpoint is down it is retried; X-KOS-Delivery stays the same across retries.

Safe retries

Send an Idempotency-Key when creating and cancelling orders: a dropped connection never turns one request into two orders; the first response is returned.

Bulk orders

Up to 1000 rows in one request. Validate first (dryRun), then create; the same reference number never becomes a second order.

Live tracking link

Get the order's tracking link and send it to your recipient through your own channel. While the courier is on the way you can read the location from the API too.

Ready-made e-commerce connections

No code needed for Trendyol, Hepsiburada, Shopify, WooCommerce and others; connect them from My online store in the portal.

Separate, revocable keys

A separate key for each system (up to 5), with the last-used time shown. A key cannot touch the password, cards or account settings.

Code sample

Get a price, create the order, verify the event

Take the <district-id> and <delivery-type-id> values from the GET /me/order-options response. Amounts are always returned as strings ("185.00"), so no cents are lost.

bash
# Price quote: calculates only, saves nothing
curl https://client.courino.com/api/v1/pricing/quote \
  -H "Authorization: Bearer $COURINO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payer": "sender",
    "sender": {},
    "recipient": { "districtId": "<district-id>" },
    "deliveryTypeId": "<delivery-type-id>"
  }'

What comes back?

  • total: the total including VAT; lines: the breakdown (base, extra, waiting, VAT…).
  • The sender is always the customer account the key belongs to; sender can be left empty.
  • The order runs the same calculation again, so quote and order follow the same rule.
bash
# Create the order: on a network error, retry with the same Idempotency-Key
curl https://client.courino.com/api/v1/orders \
  -H "Authorization: Bearer $COURINO_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ORD-48213" \
  -d '{
    "payer": "sender",
    "sender": {},
    "recipient": {
      "name": "Jane Doe",
      "phone": "0532 123 45 67",
      "address": "Moda Cd. No:12 D:3",
      "districtId": "<district-id>"
    },
    "deliveryTypeId": "<delivery-type-id>",
    "reference": "ORD-48213"
  }'

What happens next?

  • 201 returns the order's id and number; the order lands on your courier company's dispatch screen.
  • Sending a different body with the same key returns 409 IDEMPOTENCY_MISMATCH. Keys are kept for 24 hours.
  • Read the status with GET /me/orders/{id} or listen for it with a webhook.
Node.js
import crypto from 'node:crypto'

// Use the raw body: app.post('/courino', express.raw({ type: '*/*' }), …)
function verify(req, secret) {           // secret: whsec_… (all of it)
  const sig = req.get('X-KOS-Signature')     // t=1761040000,v1=9f2c…
  const { t, v1 } = Object.fromEntries(sig.split(',').map((p) => p.split('=')))
  const mac = crypto.createHmac('sha256', secret)
    .update(`${t}.`).update(req.body).digest('hex')
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300
  return fresh && mac.length === v1?.length &&
    crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(v1))
}

The incoming event

  • Body: { id, type, occurredAt, data: { order } }; type e.g. order.delivered.
  • The same event may be retried: store the X-KOS-Delivery value and skip the second one.
  • Return 2xx. If you return 410 Gone, retries stop for that message.
Getting started

Your first order in three steps

The API works with your account in your courier company's Courino customer portal. No separate sign-up or contract is needed.

Create your key

  1. Log in to the customer portal.
  2. Open the My details › Integration (API keys) card.
  3. Give the key a name and press Create key; it is shown only once.
Step-by-step guide →

Try it in Swagger

  1. Open the API docs and paste the key into Authorize.
  2. Get district and delivery type IDs with GET /me/order-options.
  3. See the price with POST /pricing/quote.
Integration API article →

Create orders, listen for events

  1. Create the order with POST /orders.
  2. Add your URL on the Webhook (event notification) card in the portal.
  3. Verify the signature and write the order status into your system.
Adding a webhook →
At a glance

The most used endpoints

All paths are under https://client.courino.com/api/v1. The full list, fields and examples are in the docs.

GET/me/order-optionsDistricts and delivery types (districtId is required in addresses)
POST/pricing/quotePrice quote (saves nothing)
POST/ordersCreates an order · Idempotency-Key
POST/me/orders/batchBulk orders, up to 1000 rows
GET/me/ordersMy orders; search by reference, barcode and date
GET/me/orders/{id}Order details and status
PUT/me/orders/{id}Edits the order (while it is still in the pool)
POST/me/orders/{id}/cancelCancel · Idempotency-Key
GET/me/orders/{id}/trackingLive courier tracking
POST/me/orders/{id}/tracking-linkTracking link to send to the recipient
Rules and limits

No surprises: the limits are written down

120 / min

Requests per key

X-RateLimit-Limit, -Remaining and -Reset on every response; over the limit you get 429 with Retry-After.

5 + 5

Keys and webhooks

Up to 5 active API keys and 5 webhook subscriptions per account. The key and the signing secret are shown only once.

Password = reset

Account security

When the account password changes, all of that account's keys are revoked. A key you revoke stops working within 30 seconds.

Who it is for

If you are a courier company

Tell your big customer "we can connect to your system".

Grant integration permission to their account on the customer card; your customer creates their own key in the portal. Orders land in your panel as normal orders, priced from the customer's price list. If you suspect a key has leaked, revoke it from the customer card.

Register your company for free →
If you are a developer

If your courier company uses Courino, start now.

Ask your courier company to grant integration permission to your portal account; then create your key and follow the docs. If you get stuck, write to destek@courino.com.

Go to the API docs →

The docs are ready, try it out.

Open the Swagger docs, or download the OpenAPI file and load it into your own tool (Postman, Insomnia, code generators).