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

  1. The shop owner opens Settings → Developers in their back office (Business plan).
  2. For the API: they make a key, tick what it may do, and give it to you. It is shown once.
  3. 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

RequestKey needsWhat it does
GET /orders?since=<ISO time>&limit=<1-100>orders:readWith since: orders placed after that moment, oldest first (page forward with the last created_at). Without: the newest.
GET /orders/<id>orders:readOne order.
GET /productsproducts:readEvery product: name in English and Arabic, price, stock (null = unlimited), active.
PATCH /products/<id>/stockproducts:writeBody {"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.