Developers
API and webhooks
Connect your ERP, warehouse or automation tools to your store: read orders, update stock, and receive events as they happen.
https://yaliko.com/api/v1
Authentication
Create a key in Settings → Developers (owner only). Send it in the Authorization: Bearer header. A "Read" key reads; a "Read and write" key can also change orders and products. Keep it on your server.
Authorization: Bearer yaliko_live_…Limits
120 requests per minute per key. Past that the API answers 429: wait a moment and retry.
Pagination
Lists return { data, next_cursor }, newest first. Pass limit (1 to 100, default 50) and cursor=next_cursor for the next page. next_cursor is null on the last page.
Errors
An error returns { error: { code, message } } with the HTTP status: 400 invalid body, 401 missing or revoked key, 403 read-only key, 404 not found in your store, 422 invalid field, 429 too many requests.
Amounts are whole numbers in the store's currency (currency). Dates are ISO 8601, UTC.
Endpoints
GET /store | The key's store: name, currency, language. Handy to test a key. | read |
GET /orders | Orders, newest first. Filters: status, created_after, created_before. | read |
GET /orders/{id} | One order with its items, customer and shipping. | read |
PATCH /orders/{id} | Change status (PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELED), carrier, tracking_number, tracking_url. Same effects as in the admin: restock, customer update, loyalty points. | write |
GET /products | Products with their variants. Filter: q (in the name). | read |
GET /products/{id} | One product. | read |
PATCH /products/{id} | Update price, compare_at_price, stock and variants: [{ id, price, stock }]. Customers waiting are told when it's back in stock. | write |
GET /customers | Customers. Filters: email, phone. | read |
GET /customers/{id} | One customer. | read |
Example: list the orders to prepare
curl https://yaliko.com/api/v1/orders?status=PENDING&limit=2 \
-H "Authorization: Bearer yaliko_live_…"{
"data": [
{
"id": "cmuo2k1x40001…",
"reference": "40001ABC",
"status": "PENDING",
"payment": { "mode": "COD", "status": "PENDING", "refunded": 0 },
"total": 730,
"currency": "MAD",
"customer": { "id": "cmung…", "name": "Sara Alaoui", "phone": "212612345678", "email": null },
"shipping": { "address": "12 rue …", "city": "Casablanca", "carrier": null, "tracking_number": null },
"items": [{ "product_id": "cmunc…", "name": "Théière", "quantity": 1, "unit_price": 590 }],
"created_at": "2026-09-30T10:12:00.000Z"
}
],
"next_cursor": "cmuo2k1x40001…"
}Example: mark an order shipped
curl -X PATCH https://yaliko.com/api/v1/orders/cmuo2k1x40001… \
-H "Authorization: Bearer yaliko_live_…" \
-H "Content-Type: application/json" \
-d '{ "status": "SHIPPED", "carrier": "Amana", "tracking_number": "RR123456789MA" }'Webhooks
Add an https URL in Settings → Developers and pick the events. We send a signed JSON POST for each event. Answer 2xx within 10 seconds and do the heavy work afterwards.
Events
order.createdAn order is placed (storefront, confirmed card payment, or created in the admin).order.updatedAn order's status changes.customer.createdA customer creates an account.
POST /webhooks/yaliko
Yaliko-Event: order.updated
Yaliko-Delivery: cmup…
Yaliko-Signature: t=1790745600,v1=5f2b…
{
"id": "evt_…",
"type": "order.updated",
"created_at": "2026-09-30T10:20:00.000Z",
"data": { "id": "cmuo2k1x40001…", "status": "SHIPPED", … }
}Verify the signature
The Yaliko-Signature header holds t (a timestamp) and v1 (HMAC-SHA256 of "t.body" with the webhook's secret). Compute it on the raw body and reject timestamps older than 5 minutes.
import crypto from "node:crypto";
// Express: app.post("/webhooks/yaliko", express.raw({ type: "application/json" }), handler)
function isFromYaliko(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
const a = Buffer.from(expected), b = Buffer.from(parts.v1 ?? "");
return fresh && a.length === b.length && crypto.timingSafeEqual(a, b);
}Retries
If your URL doesn't answer 2xx, we retry after 1 min, 5 min, 30 min, 2 h and 12 h. The delivery history and a Resend button are in the settings. The same event can arrive twice: deduplicate on the event id.