Alaamah One Developers
Getting started

Alaamah One exposes three integration surfaces. Store & System API: you add read-only endpoints to your store, POS, ERP or accounting system and we pull products, customers, orders, suppliers, invoices and more. Webhooks: your system pushes changes to us in real time. MCP server: AI assistants (Claude and any MCP client) act on an Alaamah One account with the owner's consent.

To connect, the account owner opens Connected accounts in Alaamah One and picks Stores → Custom store (API) or Systems → Custom system (API), then pastes your API base URL and API key. We refresh daily or whenever “Sync” is pressed.

Read-only — we never write to your system. One endpoint is enough to start; we re-check the missing ones on every sync, so they start working the day you publish them. Stores built on Salla or Zid, and Odoo, Daftra, Qoyod and Zoho Books, have built-in connectors — see Connection guides.

Endpoints

EndpointStatusWhat we do with it
GET /productsrequired*Items, images, prices and stock → Brand Library.
GET /customersrequired*Customers → Customers (name · phone · email · city).
GET /ordersoptionalOrders or invoices → purchase history: order count, spend and last order per customer.

* Any one of the three is enough to connect; all three is best.

Authentication

We send the key in both headers — read whichever you prefer:

Authorization: Bearer YOUR_API_KEY
X-API-Key: YOUR_API_KEY
  • HTTPS on a public host is required. Redirects (301/302) are not followed — give us the final URL.
  • The base URL is what /products, /customers and /orders are appended to, e.g. https://api.example.com/v1.
  • Use a dedicated read-only key that can be revoked at any time. Each key belongs to one account (company or branch) and returns only its data.

Pagination & response shape

Every endpoint accepts page (1-based) and per_page (we request 200; you may return fewer, e.g. 100, and say so in meta). JSON response:

{ "data": [ ... ], "meta": { "page": 1, "per_page": 200, "total": 1240, "last_page": 7 } }

We also accept "has_more": true|false instead of last_page, or a bare array (we stop at a shorter page). A missing endpoint should return 404. Our default pace is 60 requests per minute, and we honor 429 with Retry-After.

Store & System API

Products

GET {base}/products?page=1&per_page=200
FieldTypeDescription
id requiredstringYour stable item ID.
name requiredstringItem name.
images requiredstring[]https image URLs (first = main). Items without an image are skipped — the library is for design; we show the skipped count.
pricenumberRegular price.
sale_pricenumber|nullSale price, if any.
currencystringISO currency code, e.g. SAR.
skustringSKU.
codestringPublic item code (stored when there is no sku).
brandstringItem brand.
urlstringItem page URL, if any.
descriptionstringPlain-text description (no HTML; up to 2000 chars). The agent reads it to answer customer questions.
attributesobject[]Specifications: [{"name":"Thickness","value":"1.85 mm"}] — or an object {"Thickness":"1.85 mm"}. Up to 30.
categoriesstring[]Categories from broad to specific (stored alongside category).
unitstringSelling unit: piece, meter, carton…
categorystringCategory (string or array of strings).
stockint|nullQuantity on hand (null = not tracked).
in_stockboolAvailable or sold out — wins over stock when sent.
updated_atISO 8601Last modified.
{
  "data": [
    {
      "id": "1001",
      "code": "P-1001",
      "name": "Cordless Drill 18V",
      "brand": "Example Tools",
      "price": 349.00,
      "sale_price": 299.00,
      "currency": "SAR",
      "sku": "DRL-18V",
      "images": ["https://example.com/img/drill-1.jpg", "https://example.com/img/drill-2.jpg"],
      "url": "https://example.com/products/cordless-drill-18v",
      "category": "Power Tools",
      "categories": ["Power Tools", "Drills"],
      "description": "18V cordless drill with 2 batteries and a charger. Keyless chuck 13 mm.",
      "attributes": [{"name": "Voltage", "value": "18V"}, {"name": "Chuck", "value": "13 mm"}, {"name": "Weight", "value": "1.6 kg"}],
      "unit": "piece",
      "stock": 25,
      "in_stock": true,
      "updated_at": "2026-10-01T09:30:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 200, "total": 1240, "last_page": 7 }
}

Customers

GET {base}/customers?page=1&per_page=200&updated_since=2026-10-01T00:00:00Z

updated_since is optional: return customers whose details or orders changed since then (used by the daily sync; manual syncs request everything). If you don't support it, return everything.

FieldTypeDescription
id requiredstringYour stable customer ID.
namestringFull name.
phonestringMobile, preferably international +9665XXXXXXXX (local Saudi 05XXXXXXXX accepted).
emailstringEmail address.
citystringCity.
countrystringISO 2-letter country code, e.g. SA.
orders_countintNumber of completed orders (ignored when you publish /orders).
total_spentnumberLifetime spend (same).
currencystringSpend currency.
last_order_atISO 8601Date of the last order (same).
{
  "data": [
    {
      "id": "C-5521",
      "name": "Sara Ahmed",
      "phone": "+966500000000",
      "email": "sara@example.com",
      "city": "Riyadh",
      "country": "SA",
      "orders_count": 4,
      "total_spent": 1890.50,
      "currency": "SAR",
      "last_order_at": "2026-09-28T17:05:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 200, "total": 8312, "last_page": 42 }
}

Orders optional

GET {base}/orders?page=1&per_page=200

When published, we build each customer's purchase history from it (order count · spend · last order) and read it in full on every customer sync. An order without customer_id (a walk-in POS sale) is matched by the phone or email in customer; an order with neither only counts toward orders scanned.

FieldTypeDescription
id requiredstringOrder or invoice number.
customer_idstring|nullCustomer ID as in /customers.
customerobjectname · phone · email · city · country — for walk-in customers.
statusstringpaid · completed · processing count; cancelled · refunded · pending · failed · void · draft don't. Missing = paid.
totalnumberOrder total.
currencystringCurrency.
created_atISO 8601Order date.
{
  "data": [
    {
      "id": "INV-90017",
      "customer_id": "C-5521",
      "status": "paid",
      "total": 472.50,
      "currency": "SAR",
      "created_at": "2026-09-28T17:05:00Z"
    },
    {
      "id": "INV-90018",
      "customer_id": null,
      "customer": { "name": "Walk-in customer", "phone": "+966511111111", "email": null },
      "status": "paid",
      "total": 89.00,
      "currency": "SAR",
      "created_at": "2026-09-28T18:40:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 200, "has_more": false }
}
System API v2

Version 2 — data for AI agents optional additions

Version 2 is fully backward compatible with version 1: a system implementing v1 keeps working unchanged. Everything below is optional and lets your WhatsApp agents use real data: the sales agent shows items with prices and stock, the purchasing agent knows each item's suppliers and purchase prices, and the customer agent knows orders, invoices and payments (to notify customers about receipts, payments and overdue invoices — with approved templates only).

Every request carries the header X-Alaamah-Spec: 2. updated_since (ISO 8601) is accepted on every endpoint: used by the daily sync; manual syncs request everything.

Extra product fields /products

FieldTypeDescription
costnumberPurchase cost. Never shown to the sales agent — purchasing agent only.
barcodestringBarcode.
unitstringUnit (piece · carton · kg…).
name_enstringEnglish name.
low_stock_thresholdintReorder level.
supplier_idstringDefault supplier (as in /suppliers).
activeboolfalse = inactive.

Items without an image don't enter the Brand Library (it is for design), but they do enter the agents' catalog.

Detailed orders /orders

On top of v1 fields add: number · payment_status (unpaid · partial · paid · refunded) · subtotal · tax · discount · updated_at · items[] (product_id · sku · name · quantity · price · total). Status: pending · processing · completed · cancelled · refunded (paid accepted).

{
  "id": "SO-5531",
  "number": "SO-5531",
  "customer_id": "C-77",
  "customer": { "name": "Sara Ahmed", "phone": "+966500000001", "email": "sara@example.com" },
  "status": "processing",
  "payment_status": "unpaid",
  "currency": "SAR",
  "subtotal": 600.00, "tax": 90.00, "discount": 0, "total": 690.00,
  "created_at": "2026-10-03T12:10:00+03:00",
  "updated_at": "2026-10-03T12:15:00+03:00",
  "items": [
    { "product_id": "1001", "sku": "DRL-18V", "name": "Cordless Drill 18V", "quantity": 2, "price": 300.00, "total": 600.00 }
  ]
}

Suppliers GET /suppliers optional

FieldTypeDescription
id requiredstringStable supplier ID.
namestringSupplier or company name.
contact_name · phone · email · city · countrystringContact details.
tax_numberstringVAT number.
products[]arrayWhat they supply: product_id · sku · name · price (purchase price) · currency · min_qty · lead_time_days. The list you send is the truth: missing lines are removed on our side.
{
  "data": [
    {
      "id": "S-12",
      "name": "Example Trading Co.",
      "contact_name": "Khalid",
      "phone": "+966512345678",
      "email": "sales@example.com",
      "city": "Jeddah",
      "country": "SA",
      "tax_number": "300000000000003",
      "currency": "SAR",
      "updated_at": "2026-10-02T08:00:00Z",
      "products": [
        { "product_id": "1001", "sku": "DRL-18V", "name": "Cordless Drill 18V", "price": 210.00, "currency": "SAR", "min_qty": 10, "lead_time_days": 5 }
      ]
    }
  ],
  "meta": { "page": 1, "per_page": 200, "has_more": false }
}

Invoices GET /invoices optional

Status: draft · issued · partial · paid · overdue · void. We also mark an invoice overdue ourselves once due_at passes with an amount still due.

{
  "data": [
    {
      "id": "INV-2026-0091",
      "number": "INV-2026-0091",
      "order_id": "SO-5531",
      "customer_id": "C-77",
      "status": "partial",
      "currency": "SAR",
      "total": 690.00, "amount_paid": 200.00, "amount_due": 490.00,
      "issued_at": "2026-10-03", "due_at": "2026-10-17",
      "updated_at": "2026-10-05T09:00:00Z",
      "items": [ { "product_id": "1001", "name": "Cordless Drill 18V", "quantity": 2, "price": 300.00 } ]
    }
  ],
  "meta": { "page": 1, "per_page": 200, "last_page": 1 }
}

Payments GET /payments optional

Each payment links to its invoice (invoice_id) so we update paid and due amounts. Status: completed · pending · failed · refunded.

{
  "data": [
    {
      "id": "PAY-881",
      "invoice_id": "INV-2026-0091",
      "order_id": "SO-5531",
      "customer_id": "C-77",
      "amount": 200.00,
      "currency": "SAR",
      "method": "mada",
      "status": "completed",
      "paid_at": "2026-10-04T16:20:00+03:00"
    }
  ],
  "meta": { "page": 1, "per_page": 200, "has_more": false }
}
System API v3

Version 3 — full system data for internal agents optional additions

Version 3 is fully backward compatible with 1 and 2. It adds optional read endpoints for sales, purchases, inventory, people, finance and the audit log, read by the “agent team”: internal agents behind the customer-facing agent (for example a sales manager who approves discounts, or an auditor who reviews quotes before they are sent) and the account owner. Publish only what fits you; a missing endpoint returns 404 and is not an error.

We send X-Alaamah-Spec: 3 on these endpoints (and 2 elsewhere, as before). Read-only — we never write to your system.

Data classification: public and internal

public may be read by the customer-facing agent, limited to the customer it is talking to (catalog without cost · that customer's orders, invoices, quotes and returns). internal is for internal agents and the owner only: purchases, purchase prices, costs, margins, reps, finance, the audit log and all sales. Alaamah One enforces this itself: a customer-facing agent can never read an internal resource, even if someone enables it, and cost fields never reach it. Send complete data; we do the withholding.

Common shape

  • Every endpoint: GET {base}/{path}?page=1&per_page=200&updated_since=… with the same { "data": [...], "meta": {...} } envelope and pagination.
  • Optional filters we may send: from · to (document date) · branch_id · warehouse_id · customer_id · supplier_id · user_id · status. Ignore what you don't support.
  • A document (quote · purchase order · supplier invoice · goods receipt · return · transfer · adjustment · expense · supplier payment): id required · number · status · customer_id or supplier_id (plus customer/supplier with a name) · user_id or salesperson_id · branch_id · warehouse_id · currency · subtotal · discount · tax · total · amount_paid · amount_due · date · due_at · approved_at · approved_by · updated_at · items[].
  • A line: product_id · sku · name · quantity · unit · price · discount (amount) · tax (amount) · total · cost (internal). We keep up to 200 lines per document, stored compactly.
  • Documents, movements and the audit log are kept for 24 months by default; older rows are deleted.
{
  "data": [
    {
      "id": "PO-1042",
      "number": "PO-1042",
      "status": "approved",
      "supplier_id": "S-12",
      "supplier": { "name": "Example Trading Co." },
      "user_id": "U-7",
      "branch_id": "BR-1",
      "warehouse_id": "WH-1",
      "currency": "SAR",
      "subtotal": 4200.00, "discount": 200.00, "tax": 600.00, "total": 4600.00,
      "amount_paid": 0, "amount_due": 4600.00,
      "date": "2026-10-03T10:00:00+03:00",
      "due_at": "2026-11-02",
      "approved_at": "2026-10-03T12:30:00+03:00", "approved_by": "U-2",
      "updated_at": "2026-10-03T12:30:00+03:00",
      "items": [
        { "product_id": "1001", "sku": "DRL-18V", "name": "Cordless Drill 18V", "quantity": 20, "unit": "piece",
          "price": 210.00, "discount": 10.00, "tax": 30.00, "total": 4200.00, "cost": 210.00 }
      ]
    }
  ],
  "meta": { "page": 1, "per_page": 200, "has_more": false }
}

Endpoints

EndpointGroupClassContent
GET /quotationsSalespublicQuotes / estimates
GET /credit-notesSalespublicSales returns / credit notes
GET /receivablesSalesinternalReceivables aging
GET /purchase-requestsPurchasesinternalPurchase requests
GET /purchase-ordersPurchasesinternalPurchase orders
GET /purchase-invoicesPurchasesinternalSupplier (purchase) invoices
GET /goods-receiptsPurchasesinternalGoods receipts
GET /purchase-returnsPurchasesinternalPurchase returns / debit notes
GET /supplier-paymentsPurchasesinternalSupplier payments
GET /supplier-payment-requestsPurchasesinternalSupplier payment requests
GET /payablesPurchasesinternalPayables aging
GET /warehousesInventoryinternalWarehouses / branches
GET /stock-movementsInventoryinternalStock movements
GET /transfersInventoryinternalTransfers
GET /stock-adjustmentsInventoryinternalAdjustments / stock counts
GET /batchesInventoryinternalBatches / expiry
GET /usersPeople & performanceinternalSales reps / users
GET /targetsPeople & performanceinternalTargets & achievement
GET /commissionsPeople & performanceinternalCommissions
GET /expensesFinanceinternalExpenses
GET /cash-movementsFinanceinternalCash / bank movements (summary)
GET /daily-salesFinanceinternalDaily sales summary
GET /profitFinanceinternalProfit by item / category
GET /audit-logAuditinternalActivity / audit log

In v2, /orders and /invoices also accept salesperson_id (or rep_id) and branch_id, and their lines discount and tax. Customer payments and receipts stay on /payments.

Specific fields

EndpointFields
/quotationsvalid_until (or expires_at) · status: draft · sent · approved · rejected · expired · converted.
/credit-notes · /purchase-returnsinvoice_id or purchase_id (origin) · reason.
/purchase-requestsrequested_by · status: draft · submitted · approved · rejected · ordered.
/purchase-ordersexpected_at · approved_at · supplier_invoice_no · received_at (a full-lifecycle order up to invoicing is accepted).
/goods-receiptspurchase_id · received_by · received_at · lines with optional expiry_date and batch_no.
/supplier-payments · /supplier-payment-requestsamount (or total) · method · invoice_id/purchase_id · requested_by · approved_by.
/receivables · /payablesPer customer/supplier: customer_id/supplier_id · as_of · current · d1_30 · d31_60 · d61_90 · d90_plus · total (or amount_due) · overdue_amount · open_invoices. A snapshot: replaced in full on every sync.
/stock-movementsproduct_id · warehouse_id · type: sale · purchase · return_in · return_out · transfer_in · transfer_out · adjustment · count · production · other · signed quantity (or positive with direction: in · out) · unit_cost · document_type/document_id.
/warehousesname · type (warehouse · branch · store) · branch_id · city · active.
/transfers · /stock-adjustmentsfrom_warehouse_id · to_warehouse_id · adjustments/counts: type (adjustment · count) and signed line quantities.
/batchesnumber · product_id · warehouse_id · qty · expiry_date.
/users · /targets · /commissionsUser: name · role · branch_id · active. Target: user_id · metric · target · achieved · period_start · period_end. Commission: user_id · amount · sales_amount · period_start · period_end.
/expenses · /cash-movements · /daily-sales · /profitAn expense is a document with category. Cash: date · account_id · account_name · account_type (cash · bank) · inflow · outflow · balance. Daily: date · branch_id · orders_count · gross · discount · tax · returns · net. Profit (when your system computes it): dimension (item · category) · key · name · qty · revenue · cost · profit · margin · period.
{ "data": [ { "customer_id": "C-77", "name": "Sara Ahmed", "currency": "SAR", "as_of": "2026-10-07",
    "current": 1200.00, "d1_30": 490.00, "d31_60": 0, "d61_90": 0, "d90_plus": 300.00, "total": 1990.00,
    "rep_id": "U-7", "open_invoices": 3, "oldest_invoice_at": "2026-06-20" } ],
  "meta": { "page": 1, "per_page": 200, "last_page": 1 } }
{ "data": [ { "id": "MV-88120", "product_id": "1001", "sku": "DRL-18V", "warehouse_id": "WH-1", "type": "sale",
    "quantity": -2, "unit_cost": 210.00, "document_type": "invoice", "document_id": "INV-2026-0091", "user_id": "U-7",
    "date": "2026-10-03T12:12:00+03:00" } ],
  "meta": { "page": 1, "per_page": 200, "has_more": true } }

Audit log /audit-log

Every create, approve, edit or delete of a document: action (create · approve · edit · delete · cancel · post) · document_type · document_id · document_number · user_id · user_name · summary · at. We also accept event · subject_type · subject_id · description · created_at. Non-document events (vehicle tracking, sessions) are not stored — a subject_type filter helps.

{ "data": [ { "id": "AU-55012", "action": "approve", "document_type": "purchase_order", "document_id": "PO-1042",
    "document_number": "PO-1042", "user_id": "U-2", "user_name": "Finance Manager", "summary": "Approved 4,600.00 SAR",
    "at": "2026-10-03T12:30:00+03:00" } ],
  "meta": { "page": 1, "per_page": 200, "has_more": false } }

Built-in connector support

Based on each system's documented public API. “Custom system (API)” and Alaamah ERP support whatever they publish with this spec. After the first sync, the card under Systems shows what actually arrived.

EndpointOdooDaftraQoyodZoho Books
quotationssupportedsupportedsupportedsupported
credit-notessupportedsupportedsupportedsupported
receivablesnot supportednot supportednot supportednot supported
purchase-requestssupportednot supportednot supportednot supported
purchase-orderssupportednot supportedsupportedsupported
purchase-invoicessupportedsupportedsupportedsupported
goods-receiptssupportednot supportednot supportednot supported
purchase-returnssupportedsupportedsupportedsupported
supplier-paymentssupportednot supportedsupportedsupported
supplier-payment-requestsnot supportednot supportednot supportednot supported
payablesnot supportednot supportednot supportednot supported
warehousessupportedsupportedsupportedsupported
stock-movementssupportedsupportednot supportednot supported
transferssupportednot supportednot supportednot supported
stock-adjustmentssupportednot supportednot supportednot supported
batchessupportednot supportednot supportednot supported
userssupportedsupportednot supportedsupported
targetsnot supportednot supportednot supportednot supported
commissionsnot supportednot supportednot supportednot supported
expensessupportedsupportednot supportedsupported
cash-movementsnot supportednot supportednot supportednot supported
daily-salesnot supportednot supportednot supportednot supported
profitnot supportednot supportednot supportednot supported
audit-lognot supportednot supportednot supportednot supported
Webhooks

Webhooks from your system to Alaamah One optional

Instead of waiting for the daily sync, push events as they happen. The account owner enables them in Connected accounts → Systems → Webhooks and gets a URL and a secret unique to that connection (the secret is shown once and can be rotated).

TypedataWhat we do
order.created · order.updatedan order shaped like /ordersStore the order, its lines and status.
payment.receiveda payment shaped like /paymentsRecord it and update the invoice balance.
invoice.issued · invoice.overduean invoice shaped like /invoicesStore the invoice (overdue is marked overdue).
stock.low{product_id, sku, name, stock, threshold}Update stock immediately.
POST https://one.alaamah.com/webhook/systems/{hook_key}
Content-Type: application/json
X-Alaamah-Signature: t=1791012345,v1=5f2b…(hex)

{
  "id": "evt_01J9ZK3M7Q",
  "type": "payment.received",
  "created_at": "2026-10-04T16:20:05+03:00",
  "data": { "id": "PAY-881", "invoice_id": "INV-2026-0091", "customer_id": "C-77", "amount": 200.00, "currency": "SAR", "paid_at": "2026-10-04T16:20:00+03:00" }
}

Purchase tracking (optional)

On order.created and payment.received you may add data.customer.email and a data.tracking object. We use them to send the purchase server-side to the pixels the merchant enabled in One (Meta · Snapchat · TikTok · Google Analytics 4 · Microsoft Advertising). Send the same event_id your browser pixel uses so the platforms merge the two instead of counting twice.

FieldUse
event_id · transaction_idDeduplication key · order number shown in reports.
value · currencyPurchase value (defaults to the event amount).
ga_client_id · ga_session_id · gclidGoogle Analytics 4 and Google Ads attribution.
fbp · fbcMeta attribution.
ttp · ttclidTikTok attribution.
sc_cookie1 · sc_click_idSnapchat attribution.
msclkidMicrosoft Advertising (Bing) attribution — the click ID from the landing-page URL; without it we match by the hashed email or phone.
ip · ua · urlCustomer IP, user agent and page — improves matching.

Signature

Header X-Alaamah-Signature: t=<unix>,v1=<hex> where v1 = HMAC-SHA256(secret, t + "." + raw body). We reject requests whose timestamp differs from our clock by more than 5 minutes, or with a wrong signature (401). id is unique per event: a re-sent event returns 200 with "duplicate": true and is never applied twice — retry safely on network errors.

# PHP
$t   = time();
$sig = hash_hmac('sha256', $t . '.' . $rawBody, $secret);
$header = "t={$t},v1={$sig}";

# Node.js
const t = Math.floor(Date.now() / 1000);
const sig = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
headers['X-Alaamah-Signature'] = `t=${t},v1=${sig}`;

# Python
t = int(time.time())
sig = hmac.new(secret.encode(), f"{t}.{raw_body}".encode(), hashlib.sha256).hexdigest()
ResponseMeaning
200Received (result: applied · ignored) or duplicate.
401Bad signature or timestamp outside the window.
404 · 410Unknown URL · connection disconnected.
413 · 422Body over 256 KB · bad type or shape.

Version 3 events

Same signature and rules as Webhooks: quote.created · quote.approved · po.created · po.approved · goods.received · return.created (data.type: sale · purchase) · payment.made (a supplier payment) · stock.adjusted. data is shaped like the matching endpoint. Internal events: stored, never sent to a customer.

{ "id": "evt_01JA2B3C4D", "type": "po.approved", "created_at": "2026-10-03T12:30:05+03:00",
  "data": { "id": "PO-1042", "number": "PO-1042", "supplier_id": "S-12", "status": "approved", "total": 4600.00, "currency": "SAR",
            "approved_at": "2026-10-03T12:30:00+03:00", "approved_by": "U-2" } }
Connection guides

Connect from Odoo · Daftra · Qoyod · Zoho · SAP · Oracle

SystemHow
Alaamah ERPReady: in Alaamah ERP → Settings → “Link Alaamah One” create a key and paste it into the “Alaamah ERP” card. No URL, no code.
Odoo (Online and 14–18)Built-in connector beta: Odoo URL + database + user email + API key (Preferences → Account Security). We read via JSON-RPC: items and images, customers, suppliers with purchase prices (supplierinfo), sales orders, invoices and payments. We never write.
DaftraBuilt-in connector beta: account name + API key (Settings → API). Items with stock and cost, clients, suppliers, invoices and payments.
QoyodBuilt-in connector beta: API key from General Settings. Items, customers, vendors, invoices and payments (Qoyod exposes no item images).
Zoho BooksBuilt-in connector beta: “Connect Zoho Books” button with read-only OAuth consent.
SAP (Business One · S/4HANA)No direct connector yet: your developer or SAP partner implements this spec on top of the Service Layer (B1) or OData (S/4HANA) — a small read layer mapping Items, BusinessPartners (C/S), Orders, Invoices and IncomingPayments to the shapes above — then the owner connects it as “Custom system (API)”.
Oracle (NetSuite · Fusion)Same via “Custom system (API)”: a read-only RESTlet or SuiteQL in NetSuite, or the official REST APIs in Fusion, plus a mapping layer to this spec.
Anything else (POS · Wafeq · Microsoft Dynamics…)“Custom system (API)”: implement the endpoints above (v1 is enough to start) and give the account owner the URL and key.
MCP server

MCP server

Alaamah One is a remote Model Context Protocol server. Any MCP client can read the brand identity, list works and products, and create images, flyers and videos on the user's plan.

ItemValue
Server URLhttps://one.alaamah.com/mcp
TransportStreamable HTTP — POST (JSON-RPC 2.0), GET, DELETE
Protocol versions2025-11-25 · 2025-06-18 · 2025-03-26 · 2024-11-05
Server infoalaamah-one 1.2.0

Connect a client

Add https://one.alaamah.com/mcp as a custom connector (remote MCP server) in your client. The client discovers the authorization server, registers itself and opens the Alaamah One sign-in page, where the user approves access.

{
  "mcpServers": {
    "alaamah-one": { "url": "https://one.alaamah.com/mcp" }
  }
}

OAuth 2.1

EndpointPurpose
GET /.well-known/oauth-protected-resourceProtected resource metadata (RFC 9728).
GET /.well-known/oauth-authorization-serverAuthorization server metadata (RFC 8414).
POST /mcp/oauth/registerDynamic client registration (RFC 7591).
GET /mcp/oauth/authorizeUser sign-in and consent.
POST /mcp/oauth/tokenGrants authorization_code and refresh_token.
POST /mcp/oauth/revokeToken revocation.
  • PKCE with S256 is required.
  • Send the access token as Authorization: Bearer … on every /mcp request.
  • The user can revoke any client at any time from Connected apps in Alaamah One.

Brand selection

An account can own several brands. Studio tools act on the current brand; send X-Alaamah-Brand: <brand id> to choose another. The server accepts it only if the brand belongs to the token owner, otherwise it answers 403.

Preview and confirm

Tools that spend credits never run on the first call. They return a preview with the cost estimate and a plan_token. Ask the user, then call the same tool with the same inputs plus "confirm": true and that plan_token. confirm without a matching token is rejected, and previews expire after 15 minutes.

// 1) preview
{"name": "generate_image", "arguments": {"prompt": "A product shot on a white table"}}
// → a preview with the cost estimate and a plan_token

// 2) run after the user approves
{"name": "generate_image", "arguments": {"prompt": "A product shot on a white table", "confirm": true, "plan_token": "<from the preview>"}}

Tools

53 tools. The list a client sees depends on the user's plan and team permissions.

ToolTitleAccess
brand_bookBrand bookread
list_worksMy worksread
job_statusRunning jobsread
list_productsBrand productsread
list_social_accountsConnected social accountsread
company_profileCompany profile PDFwrite
generate_imageGenerate imagewrite
create_flyerCreate flyerwrite
smart_videoSmart videowrite
avatar_videoTalking avatar videowrite
schedule_postSchedule postwrite
brand_book_statusBrand book completenessread
brand_book_updateEdit brand bookwrite
brand_logo_setSet brand logowrite
agents_listWhatsApp agentsread
agent_profile_getAgent profileread
agent_profile_updateEdit agent profilewrite
agent_learned_reviewReview what the agent learnedwrite
comment_rules_listComment auto-repliesread
comment_rule_upsertAdd or edit an auto-reply rulewrite
comment_rule_toggleTurn a rule on/offwrite
comment_rule_deleteDelete a rulewrite
comment_replies_suggestSuggest reply variantswrite
supervisor_settings_getSupervisorsread
supervisor_settings_updateAdd or edit a supervisorwrite
escalations_listPending questionsread
escalation_getEscalationread
escalation_replyAnswer an escalationwrite
escalation_followupSend the customer follow-upwrite
agent_knowledge_reviewReview agent knowledgewrite
routing_rules_listRouting rulesread
routing_testTest routing (dry run)read
routing_decision_explainWhy was a message routed this wayread
escalation_manageAssign, reopen, resolve or closewrite
escalation_metricsEscalation metricsread
agent_knowledge_searchSearch agent knowledgeread
agent_activityAgent activityread
platform_servicesServices statusread
analytics_overviewAnalytics overviewread
usage_summaryUsage & pointsread
connections_statusConnections statusread
scheduled_postsScheduled postsread
wa_templatesWhatsApp templatesread
ads_overviewAds platformsread
bio_getBrand link pageread
bio_updateEdit the brand link pagewrite
agent_createCreate agentwrite
agent_permissions_getAgent permissionsread
agent_permissions_setChange agent permissionswrite
approvals_listWaiting approvalsread
approval_decideApprove or rejectwrite
audit_listAudit logread
plans_recommendWhich plan fits?read
Errors & launch

Error codes & how we handle them

ResponseWhat it means to us
200 + dataSuccess.
200 without data, or not JSONEndpoint not published yet (not an error) — re-checked on every sync.
401 · 403Key rejected — the account owner sees “the API rejected the key”, the sync is marked failed, and we retry on the next daily cycle.
404 · 405 · 501Endpoint doesn't exist yet (not an error).
301 · 302Not followed — we show the target URL so it can be used instead.
429We wait for Retry-After (up to 60 s) and retry once.
5xx · timeoutRetried twice, then the sync is marked failed and retried automatically on the next cycle.

Quick test

curl -H "Authorization: Bearer YOUR_API_KEY" -H "X-API-Key: YOUR_API_KEY" \
  "https://api.example.com/v1/products?page=1&per_page=200"

curl -H "Authorization: Bearer YOUR_API_KEY" -H "X-API-Key: YOUR_API_KEY" \
  "https://api.example.com/v1/customers?page=1&per_page=200&updated_since=2026-10-01T00:00:00Z"

curl -H "Authorization: Bearer YOUR_API_KEY" -H "X-API-Key: YOUR_API_KEY" \
  "https://api.example.com/v1/orders?page=1&per_page=200"

# expected without a key: 401
curl -i "https://api.example.com/v1/products?page=1&per_page=1"

The connection card in Alaamah One also has a “Test connection” button that shows each endpoint's status before connecting.

Pre-launch checklist

  • HTTPS URL on a public host, with no redirect.
  • Read-only key, read from Authorization: Bearer or X-API-Key; no key returns 401.
  • Each key returns only its own account's data (company or branch) — never another company's.
  • page and per_page work, and meta.last_page or has_more are correct.
  • id values are stable across syncs.
  • Every item has at least one https image.
  • Phones in international format +966… where possible.
  • Dates in ISO 8601 with a timezone (Z or +03:00).
  • Unpublished endpoints return 404.

Privacy

Your customer data stays in your brand’s account only, and the key is stored encrypted and never shown again. Disconnecting deletes the key and keeps what was imported (you can delete it). Tags and marketing consent set in Alaamah One are never overwritten by a sync.

Alaamah One · Developer documentation · Examples use example.com and fictional data.