API documentation
Build integrations on top of your ETapri store. Sync orders to your ERP, push products from an external PIM, or receive real-time order events at your own endpoint.
Authentication
All requests require a per-store API key passed as a Bearer token. Generate one from your store's API keys page in the dashboard. Keys are shown once at creation — store them securely. Each key is scoped to a single store.
curl https://etapri.shop/api/public/v1/orders \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"Base URL: https://etapri.shop/api/public/v1. All endpoints return JSON. Use HTTPS only — calls over HTTP are rejected.
Rate limits
60 requests per minute, per API key. Every response includes an X-RateLimit-Remaining header. When exceeded, you get 429 Rate limit exceeded — wait at least 60 seconds before retrying.
Errors
All errors return JSON in the shape:
{ "error": "Invalid or missing API key" }400Invalid request (validation, bad JSON)401Missing or invalid API key404Resource not found429Rate limit exceeded500Server error — safe to retryOrders
/api/public/v1/ordersList orders for your store, most recent first.
Query params
status— filter by status (e.g.paid,shipped)from,to— ISO-8601 datetimeslimit— 1–100 (default 50),offset— 0–10000
curl "https://etapri.shop/api/public/v1/orders?status=paid&limit=20" \
-H "Authorization: Bearer $ETAPRI_KEY"/api/public/v1/orders/{orderNumber}Fetch a single order with its line items.
curl https://etapri.shop/api/public/v1/orders/ORD-20260522-A7K3X9 \
-H "Authorization: Bearer $ETAPRI_KEY"/api/public/v1/orders/{orderNumber}Update an order's status, tracking number, or notes. Status transitions to shipped / delivered / cancelled automatically stamp the corresponding timestamp and fire a webhook event.
Body (any of)
status— one ofpending_whatsapp,pending_payment,paid,confirmed,packed,shipped,delivered,cancelled,refundedtracking_number— string, max 120 charsnotes— string, max 2000 chars
curl -X PATCH https://etapri.shop/api/public/v1/orders/ORD-20260522-A7K3X9 \
-H "Authorization: Bearer $ETAPRI_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"shipped","tracking_number":"SMSA12345678"}'Products
/api/public/v1/productsList products in your store (excludes deleted). Returns all language variants (name_ar, name_en, name_zh).
Query params
status—draft,active, orarchivedlimit— 1–100,offset— 0–10000
curl "https://etapri.shop/api/public/v1/products?status=active" \
-H "Authorization: Bearer $ETAPRI_KEY"Webhooks
Register an HTTPS endpoint from your store's Webhooks page to receive real-time order events. Every delivery is signed with HMAC-SHA256 and retried with exponential backoff up to 6 times (1m → 5m → 30m → 2h → 6h → 24h) before being marked dead.
order.createdA new order was placed on the storefrontorder.paidPayment succeeded (MyFatoorah, manual mark-paid, or PATCH status)order.shippedStatus transitioned to shippedorder.deliveredStatus transitioned to deliveredorder.cancelledStatus transitioned to cancelledVerifying signatures
Each request includes an X-ETapri-Signature header in the form t=<unix_ts>, v1=<hex_hmac_sha256>. The signed string is t + "." + raw_body. Reject requests where t is older than ~5 minutes to prevent replay.
// Node.js / Express
import crypto from 'crypto';
app.post('/etapri-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.header('X-ETapri-Signature') || '';
const parts = Object.fromEntries(header.split(',').map(s => s.trim().split('=')));
const t = parts.t;
const v1 = parts.v1;
const body = req.body.toString('utf8');
const expected = crypto
.createHmac('sha256', process.env.ETAPRI_WEBHOOK_SECRET)
.update(`${t}.${body}`)
.digest('hex');
if (!v1 || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) {
return res.status(401).send('Stale timestamp');
}
const event = JSON.parse(body);
// event.type, event.data
res.status(200).send('ok');
});Payload shape
{
"type": "order.paid",
"id": "evt_...",
"created_at": "2026-05-22T10:32:18Z",
"data": {
"id": "...",
"order_number": "ORD-20260522-A7K3X9",
"status": "paid",
"total": 149.50,
"currency": "SAR",
"customer_name": "...",
"customer_email": "...",
"...": "full order object"
}
}Your endpoint should respond with a 2xx status within 10 seconds. Any other response (or timeout) marks the delivery as failed and schedules a retry. View all attempts in your dashboard.
Ready to build?
