For developers
Tajer Al Fareej API and webhooks
Connect a Business shop to its own systems: read orders and products, set stock, and hear about orders the moment they happen.
Getting started
- The shop owner opens Settings → Developers in their back office (Business plan).
- For the API: they make a key, tick what it may do, and give it to you. It is shown once.
- For webhooks: they add your https address and the events, and give you the signing secret.
API
Send the key in every request as Authorization: Bearer tjr_live_… . Answers are JSON.
https://tajeralfareej.com/api/v1/open
| Request | Key needs | What it does |
|---|---|---|
GET /orders?since=<ISO time>&limit=<1-100> | orders:read | With since: orders placed after that moment, oldest first (page forward with the last created_at). Without: the newest. |
GET /orders/<id> | orders:read | One order. |
GET /products | products:read | Every product: name in English and Arabic, price, stock (null = unlimited), active. |
PATCH /products/<id>/stock | products:write | Body {"stock": 4}, or {"stock": null} for unlimited. Customers waiting for a sold-out product are told when it is back. |
Amounts are whole numbers in the smallest unit of the order’s currency: 1.250 BHD is 1250, 12.50 SAR is 1250.
401: no key, or a revoked one. 403 missing_scope: the key may not do this. 403 business_only: the shop is no longer on Business. 404: not in this shop.
curl https://tajeralfareej.com/api/v1/open/orders?limit=10 \
-H "Authorization: Bearer tjr_live_…"
curl -X PATCH https://tajeralfareej.com/api/v1/open/products/<id>/stock \
-H "Authorization: Bearer tjr_live_…" \
-H "Content-Type: application/json" \
-d '{"stock": 4}'An order
{
"id": "6f1c…", "number": 12,
"status": "new | confirmed | ready | delivered | cancelled",
"payment_status": "unpaid | claimed | paid",
"payment_method": "benefitpay", "fulfillment": "delivery | pickup",
"customer": { "name": "Maha", "phone": "97339001122" },
"address": "Villa 4, Road 12, Riffa", "note": null, "table_number": null,
"scheduled_for": null, "created_at": "2026-10-16T10:00:00.000Z",
"currency": "BHD",
"amounts": { "subtotal": 7000, "delivery_fee": 1000, "discount": 0, "tip": 0, "vat": 0, "total": 8000 },
"items": [{ "name": "Saffron luqaimat", "quantity": 2, "unit_price": 3500, "options": [] }]
}Webhooks
Events: order.created, order.status_changed, order.paid (and ping from Send a test). Each one is POSTed as JSON to the address the shop added.
POST <your address>
X-Tajer-Event: order.paid
X-Tajer-Delivery: 2b7e…
X-Tajer-Timestamp: 1792090000
X-Tajer-Signature: sha256=5d41…
{ "id": "2b7e…", "type": "order.paid", "created_at": "…", "data": { "order": { … } } }Check the signature
X-Tajer-Signature is sha256= and the hex HMAC-SHA256 of "<X-Tajer-Timestamp>.<raw body>" with the webhook’s secret.
import { createHmac, timingSafeEqual } from 'node:crypto';
const signed = `${req.headers['x-tajer-timestamp']}.${rawBody}`;
const expected = 'sha256=' + createHmac('sha256', SECRET).update(signed).digest('hex');
const ok = expected.length === req.headers['x-tajer-signature'].length
&& timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-tajer-signature']));
// Also refuse timestamps older than 5 minutes, and ignore a X-Tajer-Delivery you already handled.Answers and retries
Answer with any 2xx within 5 seconds. Otherwise the event is sent again after 1, 5, 30, 120, 360, 720 and 1440 minutes, then dropped. After 15 failures in a row the webhook is switched off until the shop turns it back on. Redirects are not followed; the address must be a public https host name.
No code? Use Make or Zapier
Create a scenario that starts with a custom webhook, paste its address into Settings → Developers → Webhooks, tick the events, and send each order to a Google Sheet, Slack, Telegram or email.