API Reference

Catalog & Knowledge

Keep the account's catalog and knowledge base in step with your own system. The WhatsApp assistant answers prices, availability and questions from this data.

Explicit scopes and plan Every route here needs an explicit scope: catalog:read / catalog:write or knowledge:read / knowledge:write. A legacy null credential is denied. The account's plan must include the catalog API, otherwise the answer is 403 feature_disabled.

How to sync

Send your records with your own external_id to the bulk upsert (up to 500 per call). A record that exists is updated; one that did not change answers unchanged and is not written again. Fields of the account's item types (for example nationality and age on a CV) go in field_values; read their keys from GET /catalog/schema. category_path finds or creates up to three category levels by name.

Webhooks: catalog.item.*, catalog.category.* and knowledge.entry.* fire for single changes made in the panels or through these routes. A bulk upsert sends one catalog.items.bulk_upserted (or knowledge.entries.bulk_upserted) event, and a data source run sends one data_source.sync.finished or data_source.sync.failed. The account's plan must include catalog webhooks.

Schema and categories

GET /catalog/schema catalog:read https://staging-mobile.washeej.com/v1/catalog/schema

Item types and their custom fields (keys, labels, field type, options). Use the keys in field_values.

cURL
curl -H "client-id: YOUR_CLIENT_ID" \
     -H "client-secret: YOUR_CLIENT_SECRET" \
     https://staging-mobile.washeej.com/v1/catalog/schema
GET /catalog/categories catalog:read https://staging-mobile.washeej.com/v1/catalog/categories

All categories (flat list with parent_id).

cURL
curl -H "client-id: YOUR_CLIENT_ID" \
     -H "client-secret: YOUR_CLIENT_SECRET" \
     https://staging-mobile.washeej.com/v1/catalog/categories
POST /catalog/categories catalog:write https://staging-mobile.washeej.com/v1/catalog/categories

Create a category. name or name_ar is required; parent_id makes it a subcategory.

Parameter Type Required Description
name string optional English name (or name_ar).
name_ar string optional Arabic name.
parent_id integer optional Parent category id.
external_id string optional Your id for the category.
cURL
curl -X POST https://staging-mobile.washeej.com/v1/catalog/categories \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"name":"Oils","name_ar":"زيوت"}'

Common errors: validation_error, feature_disabled

PATCH /catalog/categories/{id} catalog:write https://staging-mobile.washeej.com/v1/catalog/categories/{id}

Update a category (only the fields sent).

cURL
curl -X PATCH https://staging-mobile.washeej.com/v1/catalog/categories/12 \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"status":false}'
DELETE /catalog/categories/{id} catalog:write https://staging-mobile.washeej.com/v1/catalog/categories/{id}

Delete a category. Its items stay without a category; its subcategories move up one level.

cURL
curl -X DELETE https://staging-mobile.washeej.com/v1/catalog/categories/12 \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET"

Items

POST /catalog/items/bulk-upsert catalog:write https://staging-mobile.washeej.com/v1/catalog/items/bulk-upsert

Create or update up to 500 items by external_id in one call. Each item is checked on its own; the answer has one result per item (created, updated, unchanged, failed with errors). Sends one catalog.items.bulk_upserted webhook, not one per item.

Parameter Type Required Description
items array required 1-500 item objects (same fields as POST /catalog/items), each with external_id.
cURL
curl -X POST https://staging-mobile.washeej.com/v1/catalog/items/bulk-upsert \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"external_id":"SKU-1","name":"Olive oil 1L","price":45},{"external_id":"SKU-2","name":"Ghee 500g","price":30}]}'

Common errors: validation_error, feature_disabled

GET /catalog/items catalog:read https://staging-mobile.washeej.com/v1/catalog/items

List items. Filters: category_id, external_id, item_type (key), status (true/false), search, updated_since (ISO date), per_page (1-100).

cURL
curl -H "client-id: YOUR_CLIENT_ID" \
     -H "client-secret: YOUR_CLIENT_SECRET" \
     "https://staging-mobile.washeej.com/v1/catalog/items?updated_since=2026-10-29T00:00:00Z&per_page=50"
GET /catalog/items/{id} catalog:read https://staging-mobile.washeej.com/v1/catalog/items/{id}

Show one item with its type, field values, media and tags.

cURL
curl -H "client-id: YOUR_CLIENT_ID" \
     -H "client-secret: YOUR_CLIENT_SECRET" \
     https://staging-mobile.washeej.com/v1/catalog/items/345
POST /catalog/items catalog:write https://staging-mobile.washeej.com/v1/catalog/items

Create an item. name or name_ar is required. category_path (up to 3 names) finds or creates the category tree. field_values are checked against the item type (see /catalog/schema).

Parameter Type Required Description
name string optional English name (or name_ar).
price number optional Price; currency defaults to SAR.
type string optional product (default) or service.
availability string optional in_stock (default), out_of_stock, on_request.
category_path array optional Category names from top to bottom, e.g. ["Oils","Olive"]. Or category_id.
item_type string optional Item type key from /catalog/schema (or item_type_id).
field_values object optional Custom field values by field key.
external_id string optional Your id; unique among the items you send.
media array optional Up to 20 {url, kind: image|video|file, caption}.
tags array optional Up to 30 tags.
cURL
curl -X POST https://staging-mobile.washeej.com/v1/catalog/items \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"external_id":"SKU-1","name":"Olive oil 1L","price":45,"category_path":["Oils","Olive"],"stock":12}'

Common errors: validation_error, duplicate_external_id, feature_disabled

PATCH /catalog/items/{id} catalog:write https://staging-mobile.washeej.com/v1/catalog/items/{id}

Update an item (only the fields sent).

cURL
curl -X PATCH https://staging-mobile.washeej.com/v1/catalog/items/345 \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"price":49,"availability":"out_of_stock"}'
DELETE /catalog/items/{id} catalog:write https://staging-mobile.washeej.com/v1/catalog/items/{id}

Delete an item.

cURL
curl -X DELETE https://staging-mobile.washeej.com/v1/catalog/items/345 \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET"

Knowledge base

POST /knowledge/entries/bulk-upsert knowledge:write https://staging-mobile.washeej.com/v1/knowledge/entries/bulk-upsert

Create or replace up to 500 entries by external_id (title and content required for each). One result per entry; one knowledge.entries.bulk_upserted webhook.

cURL
curl -X POST https://staging-mobile.washeej.com/v1/knowledge/entries/bulk-upsert \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"entries":[{"external_id":"faq-1","title":"Hours","content":"9am to 9pm"}]}'
GET /knowledge/entries knowledge:read https://staging-mobile.washeej.com/v1/knowledge/entries

List knowledge base entries (what the assistant answers from). Filters: type, tag, search, per_page.

cURL
curl -H "client-id: YOUR_CLIENT_ID" \
     -H "client-secret: YOUR_CLIENT_SECRET" \
     https://staging-mobile.washeej.com/v1/knowledge/entries
POST /knowledge/entries knowledge:write https://staging-mobile.washeej.com/v1/knowledge/entries

Create an entry: title, content, type (faq, policy, price, offer, note…), tags, priority, valid_from, valid_until, external_id.

cURL
curl -X POST https://staging-mobile.washeej.com/v1/knowledge/entries \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"title":"Delivery","content":"Free delivery inside Riyadh.","type":"policy"}'

Common errors: validation_error, duplicate_external_id, feature_disabled

PATCH /knowledge/entries/{id} knowledge:write https://staging-mobile.washeej.com/v1/knowledge/entries/{id}

Update an entry (only the fields sent).

cURL
curl -X PATCH https://staging-mobile.washeej.com/v1/knowledge/entries/9 \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"is_active":false}'
DELETE /knowledge/entries/{id} knowledge:write https://staging-mobile.washeej.com/v1/knowledge/entries/{id}

Delete an entry.

cURL
curl -X DELETE https://staging-mobile.washeej.com/v1/knowledge/entries/9 \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET"

Data sources

Files, Google Sheets, APIs and WooCommerce stores connected in the panel. Ask for a run right after your data changed instead of waiting for the schedule.

GET /data-sources catalog:read https://staging-mobile.washeej.com/v1/data-sources

The account's data sources (files, Google Sheets, APIs, WooCommerce) with their last run. Connection details are never returned.

cURL
curl -H "client-id: YOUR_CLIENT_ID" \
     -H "client-secret: YOUR_CLIENT_SECRET" \
     https://staging-mobile.washeej.com/v1/data-sources
POST /data-sources/{id}/sync catalog:write https://staging-mobile.washeej.com/v1/data-sources/{id}/sync

Run a data source now (for example right after your system changed). Answers 202 with the queued run; 409 when a run is already in progress or the mapping is not saved yet.

cURL
curl -X POST https://staging-mobile.washeej.com/v1/data-sources/3/sync \
  -H "client-id: YOUR_CLIENT_ID" \
  -H "client-secret: YOUR_CLIENT_SECRET"

Common errors: not_runnable, not_found, feature_disabled