Developers

Connect your website to Barrq with one API

Send your orders to Barrq and every customer gets a WhatsApp update at each status change. Keep your catalogue and customer list in sync. A simple, secure REST API.

REST + JSON

Versioned at /api/v1

HTTPS + key auth

Key and secret on every call

120 req / min

Per key, batches of 100

Idempotent writes

Safe to retry, always

Getting started

Introduction

The Barrq API lets a merchant's own website talk to Barrq server to server. Report each order and Barrq messages the customer on WhatsApp at every status change, in their language. Optionally, push your catalogue so the AI agent quotes your real prices and stock, and keep customers in step between your site and Barrq.

Base URL
https://app.barrq.co/api/v1
Format
JSON request and response bodies, UTF-8
Transport
HTTPS only, from your server — never from a browser
Version
v1 — additive changes only

Getting started

Quickstart

  1. 1

    Get your API key

    The store owner opens Barrq → Integrations → Website and creates the API key. Barrq shows a Key ID (bq_key_…) and a Secret (bq_secret_…). The Secret is shown once — store it in your server's secret manager.
  2. 2

    Test the connection

    A GET /orders changes nothing and returns what the key may do.
    curl https://app.barrq.co/api/v1/orders \
      -H "X-Barrq-Key: bq_key_YOUR_KEY_ID" \
      -H "X-Barrq-Secret: bq_secret_YOUR_SECRET"
  3. 3

    Report your first order

    Send it when the order is placed, then again on every status change.
    curl -X POST https://app.barrq.co/api/v1/orders \
      -H "X-Barrq-Key: bq_key_YOUR_KEY_ID" \
      -H "X-Barrq-Secret: bq_secret_YOUR_SECRET" \
      -H "Content-Type: application/json" \
      -d '{ "order_id": "10045", "status": "pending", "customer": { "name": "Sara Ahmed", "phone": "+201001234567", "email": "sara@example.com", "language": "ar" }, "currency": "EGP", "total": 1250, "items": [ { "name": "Rose face serum", "sku": "SER-01", "qty": 2, "price": 625 } ], "address": "12 Tahrir St, Cairo", "note": "Call before delivery" }'

Getting started

Authentication

Every request carries the Key ID and Secret as two headers. Requests without them, or with a revoked key, return 401.

HTTP headers
X-Barrq-Key: bq_key_YOUR_KEY_ID
X-Barrq-Secret: bq_secret_YOUR_SECRET

HTTP Basic authentication also works: Authorization: Basic base64(keyId:secret).

Rotating and revoking

If a Secret is lost or exposed, the owner presses Regenerate secret in Barrq. The Key ID stays the same and the old Secret stops working immediately. Revoke switches the key off entirely.

Getting started

Permissions

Reporting orders is always allowed. Catalogue and customer access are off until the store owner enables them in Integrations → Website → Catalogue & customers API. Write access includes read access.

Setting in BarrqScopeGrants
Catalogue → Readcatalog:readList and read products
Catalogue → Read & writecatalog:writeCreate, update and archive products
Customers → Readcustomers:readList and read customers
Customers → Read & writecustomers:writeCreate and update customers

Once your site pushes products, Barrq stops reading the catalogue from your web pages: your API becomes the source of truth.

Sell on your website

Your site as the store

Connect the website as the merchant's store — the same way a Shopify store is connected. From then on the AI agent builds the cart in the chat and sends the customer to your checkout; the order is placed and paid on your site; and the order you report back is tied to the conversation that sold it.

  1. 1

    Push your catalogue

    POST /products with SKU, price and stock. The agent only offers what is in stock.

  2. 2

    Choose how customers reach your checkout

    A cart link pattern (no code), or a checkout endpoint your server answers.

  3. 3

    The agent sells

    It sends a checkout button with your link. It never asks for addresses or payment in chat — your checkout does that.

  4. 4

    Report the order

    POST /orders with the barrq_ref from the link. The customer gets WhatsApp updates at every status.

The store owner turns this on in Barrq → Integrations → Website → Sell on your website. A Shopify or WooCommerce connection, if there is one, stays the store.

Sell on your website

POSTCheckout endpoint

For sites that create the cart on the server. Barrq POSTs the cart to your endpoint, signed, and expects the checkout URL back within 10 seconds. Answer 2xx with checkout_url; total, currency and expires_at are optional. A test: true request comes from the owner's "Try a test checkout" button — do not keep that cart.

POST https://yourshop.com/api/barrq/checkout
Content-Type: application/json
X-Barrq-Event: checkout.create
X-Barrq-Signature: t=1760000000,v1=5f2b…

{
  "event": "checkout.create",
  "test": false,
  "reference": "bq_co_9m7wBFC8y8qq",
  "currency": "EGP",
  "subtotal": 1250,
  "customer": { "name": "Sara Ahmed", "phone": "+201001234567", "email": null, "language": "ar" },
  "items": [
    { "sku": "SER-01", "title": "Rose face serum", "quantity": 2, "unit_price": 625 }
  ]
}

Sell on your website

POSTOrder status webhook

Optional, and what lets a merchant run the store from Barrq. When an order your site sent is confirmed, cancelled, shipped or delivered inside Barrq — on its order page, or by the customer on an order-confirmation call — Barrq tells your site, signed. Update the order on your side, then report its new status through POST /orders as usual: reporting the status Barrq already has changes nothing and messages no one, so there is no loop. Answer 2xx; anything else (for example 404 for an order you do not know) is shown on the order in Barrq as a failure.

Request from Barrq
POST https://yourshop.com/api/barrq/order-status
Content-Type: application/json
X-Barrq-Event: order.status_requested
X-Barrq-Signature: t=1760000000,v1=8c1d…

{
  "event": "order.status_requested",
  "order_id": "10045",
  "order_number": "10045",
  "status": "confirmed",
  "requested_by": "barrq",
  "note": "Customer confirmed on the phone"
}

status is one of confirmed, shipped, delivered, cancelled. requested_by is barrq (the merchant, in Barrq) or voice (the customer, on a call); note is optional.

Your site can register this address itself, with the same API key it sends orders with: PUT /api/v1/webhook with { "url": "https://your-shop.com/api/barrq/webhook" }. Call it when your site starts or connects, and nobody has to paste it into Integrations → Website.

Sell on your website

Verifying signatures

Every request Barrq sends to your site carries X-Barrq-Signature: t=<unix seconds>,v1=<hex>, where the hex is HMAC-SHA256 of <t>.<raw body> keyed with the store's signing secret (whsec_…, shown on the Website page). Verify it on the raw body before parsing, and reject requests older than five minutes.

import crypto from "node:crypto";

// rawBody: the exact request body as received (a string), before JSON parsing.
export function verifyBarrq(rawBody, header, secret) {
  const t = /t=(\d+)/.exec(header ?? "")?.[1];
  const v1 = /v1=([a-f0-9]+)/.exec(header ?? "")?.[1];
  if (!t || !v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // 5-minute window
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Orders

Report an order

POST/api/v1/ordersAlways allowed

Create or update an order, matched by your order_id. Barrq saves it and sends the customer the WhatsApp message that status earns. Sending the same report twice is safe: nothing changes and nobody is messaged twice.

Body parameters
  • order_idstringrequired

    Your order number or id, up to 64 characters.

  • statusstringrequired

    pending · confirmed · paid · shipped · out_for_delivery · delivered · cancelled. Common names from other platforms (processing, completed, refunded…) are mapped automatically.

  • customer.phonestringoptional

    Full number with country code, e.g. +201001234567. Required for WhatsApp messages.

  • customer.namestringoptional

    Customer name.

  • customer.emailstringoptional

    Customer email.

  • customer.languagestringoptional

    ar or en — the language of the WhatsApp message.

  • currencystringoptional

    ISO 4217 code, e.g. EGP.

  • totalnumberoptional

    Order total.

  • subtotalnumberoptional

    Before delivery, tax, fees and discounts. Defaults to the items’ total.

  • delivery_feenumberoptional

    Delivery / shipping charge.

  • taxnumberoptional

    Tax amount (tax_label optional, default “Tax”).

  • fees[]arrayoptional

    Other charges: { name, amount }.

  • discountnumberoptional

    Checkout discount amount, with discount_label and promo_code (both optional).

  • discounts[]arrayoptional

    More discounts: { label, amount, code }. Each charge and discount shows as its own line on the order.

  • items[]arrayoptional

    Up to 100: name (required), sku, qty (default 1), price per unit.

  • tracking_urlstringoptional

    https:// link, sent with the shipped update.

  • addressstringoptional

    Delivery address, up to 1,000 characters.

  • notestringoptional

    Up to 1,000 characters.

  • barrq_refstringoptional

    The {ref} of the checkout the agent sent. Ties the order to the conversation and customer that produced it.

curl -X POST https://app.barrq.co/api/v1/orders \
  -H "X-Barrq-Key: bq_key_YOUR_KEY_ID" \
  -H "X-Barrq-Secret: bq_secret_YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "order_id": "10045", "status": "pending", "customer": { "name": "Sara Ahmed", "phone": "+201001234567", "email": "sara@example.com", "language": "ar" }, "currency": "EGP", "total": 1250, "items": [ { "name": "Rose face serum", "sku": "SER-01", "qty": 2, "price": 625 } ], "address": "12 Tahrir St, Cairo", "note": "Call before delivery" }'
JSON
{
  "ok": true,
  "order": { "id": "cm2x8k…", "order_number": "10045", "status": "pending", "created": true },
  "whatsapp": { "sent": "text" }
}

whatsapp.sent is text or template when a message went out, otherwise none with a reason. The order is saved either way.

reasonMeaning
no_changeThe status did not change — nothing new to tell the customer.
no_phoneNo usable customer phone number.
stage_offThe store switched off messages for this status.
template_pendingOutside WhatsApp’s 24-hour window and the message template is not approved yet.
send_failedWhatsApp refused the message; detail says why.

Orders

Test the connection

GET/api/v1/ordersAlways allowed

Verifies the key without changing anything. Use it behind a "Test connection" button in your settings screen.

JSON
{
  "ok": true,
  "statuses": ["pending", "confirmed", "paid", "shipped", "out_for_delivery", "delivered", "cancelled"],
  "access": ["orders", "catalog:read"]
}

Products

Create or update products

POST/api/v1/productsScope catalog:write

Up to 100 products per request, matched by your sku. A new SKU needs title and price; for an existing SKU send only what changed. If any product is invalid, nothing is saved and you get 422 with every problem in details.

Body parameters
  • skustringrequired

    Your stable id for the product, up to 190 characters.

  • title / title_arstringoptional

    Name in English / Arabic. title is required for a new product.

  • description / description_arstringoptional

    Up to 5,000 characters each.

  • pricenumberoptional

    ≥ 0. Required for a new product.

  • compare_at_pricenumber | nulloptional

    The "was" price; kept only when higher than price. null clears it.

  • currencystringoptional

    3-letter code. Defaults to the store currency.

  • stockintegeroptional

    ≥ 0. 0 = out of stock; going above 0 sends back-in-stock alerts.

  • categorystringoptional

    Free text.

  • image_url / urlstringoptional

    http(s) links. url is the product page the agent shares.

  • activebooleanoptional

    false takes the product off sale; true restores it.

curl -X POST https://app.barrq.co/api/v1/products \
  -H "X-Barrq-Key: bq_key_YOUR_KEY_ID" \
  -H "X-Barrq-Secret: bq_secret_YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "products": [
    { "sku": "SER-01", "title": "Rose face serum", "title_ar": "سيروم الورد",
      "price": 625, "compare_at_price": 750, "currency": "EGP", "stock": 40,
      "category": "Skincare", "image_url": "https://example.com/ser-01.jpg",
      "url": "https://example.com/p/ser-01" },
    { "sku": "SOAP-01", "stock": 0 }
  ] }'
JSON
{
  "ok": true,
  "created": 1,
  "updated": 1,
  "results": [
    { "sku": "SER-01", "id": "cm2x…", "status": "created" },
    { "sku": "SOAP-01", "id": "cm2y…", "status": "updated" }
  ]
}

Products

List products

GET/api/v1/productsScope catalog:read

The catalogue, most recently changed first. See Pagination.

Query parameters
  • pageintegeroptional

    From 1. Default 1.

  • limitintegeroptional

    1–100. Default 50.

  • updated_sinceISO 8601optional

    Only products changed since then — for incremental syncs.

  • skustringoptional

    Return one product.

  • include_inactivebooleanoptional

    true includes archived products.

Each product: id, sku, title, title_ar, description, description_ar, price, compare_at_price, currency, stock, in_stock, category, image_url, url, active, source, updated_at.

Products

Get a product

GET/api/v1/products/{sku}Scope catalog:read

One product by your SKU (or Barrq's id). 404 when there is none.

Products

Archive a product

DELETE/api/v1/products/{sku}Scope catalog:write

Takes the product off sale. It is archived, not erased — past orders and conversations still refer to it. POST it again with "active": true to restore it.

Customers

Create or update customers

POST/api/v1/customersScope customers:write

Up to 100 per request, matched by phone first, then email. Only the fields sent are changed; tags are added, never removed.

Body parameters
  • phonestringoptional

    With country code, e.g. +971501234567. phone or email is required.

  • emailstringoptional

    phone or email is required.

  • namestringoptional

    Up to 190 characters.

  • tagsstring[]optional

    Up to 30 tags, 60 characters each.

  • marketing_opt_inbooleanoptional

    true = consented to marketing; false = opted out. Omit to keep the current choice.

cURL
curl -X POST https://app.barrq.co/api/v1/customers \
  -H "X-Barrq-Key: bq_key_YOUR_KEY_ID" \
  -H "X-Barrq-Secret: bq_secret_YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "customers": [
    { "phone": "+971501234567", "name": "Omar Khalid", "email": "omar@example.com",
      "tags": ["vip", "newsletter"], "marketing_opt_in": true }
  ] }'

Customers

List customers

GET/api/v1/customersScope customers:read

Customers from every channel Barrq serves, most recently active first.

Query parameters
  • page / limitintegeroptional

    As for products.

  • updated_sinceISO 8601optional

    Only customers changed since then.

  • phone / emailstringoptional

    Find one person.

Each customer: id, name, phone, email, whatsapp, instagram, status, tags, orders_count, lifetime_value, marketing_opt_in, first_seen_at, last_seen_at.

Customers

Get a customer

GET/api/v1/customers/{id}Scope customers:read

One customer by Barrq's id. 404 when there is none.

Reference

Pagination

List endpoints take page and limit and return the total. Request the next page while has_more is true. For scheduled syncs, store the time of your last run and send it as updated_since.

JSON
{ "ok": true, "products": [ … ], "page": 1, "limit": 100, "total": 342, "has_more": true }

Reference

Errors

Errors are JSON with a message written for your logs, and a list of every problem when a body is invalid.

JSON
{
  "ok": false,
  "error": "Some products could not be read. Nothing was saved.",
  "details": ["products[1] (SOAP-01): \"price\" must be a number ≥ 0."]
}
StatusMeaningWhat to do
200 / 201Success (201 = a new order)—
400Body is not JSON, or bad page / limit / updated_sinceFix the request
401Missing, wrong or revoked credentialsCheck the Key ID and current Secret
403Integration disabled, or the key lacks the scopeThe owner enables the permission
404No product or customer with that identifierCheck the SKU or id
413More than 100 items in one requestSend batches of up to 100
422Invalid fields — listed in detailsFix them; nothing was saved
429Rate limit reachedWait Retry-After seconds, then retry
500Error on Barrq’s sideRetry with the same body — it is safe

Each key may make 120 requests per minute. Repeated failed authentication from one address is throttled too. A 429 carries a Retry-After header in seconds.

Every write is idempotent: orders are matched by order_id, products by sku, customers by phone or email. Retry on 429, 5xx and network errors with exponential back-off (for example 1s, 2s, 4s, up to 5 attempts).

Reference

Security

Encrypted in transit

Call the API over HTTPS only, so the key and every payload are encrypted on the wire. Never send the Secret over plain HTTP.

Secrets never stored

Barrq keeps only a SHA-256 hash of each Secret and compares it in constant time. 40 random characters — not guessable.

Tenant isolation

A key reaches its own store’s data and nothing else. Catalogue and customer scopes are off by default.

Instant rotation

Regenerate or revoke a key at any time; the old Secret stops working immediately.

Your part

Keep the Secret on your server — in environment variables or a secret manager — never in front-end code, mobile apps or a public repository. If it is ever exposed, regenerate it straight away. More in our security overview.

Reference

Versioning

The API is versioned in the path. Within v1 we only add — new endpoints, new optional fields, new response fields — so ignore fields you do not recognise. A breaking change would ship as v2, with v1 kept running and notice given well in advance.

  • ✓The store owner created the API key and shared the Key ID and Secret privately.
  • ✓Both values live in your server’s secrets, not in front-end code.
  • ✓GET /orders returns ok: true with the access you expect.
  • ✓Catalogue and/or Customers access is enabled, if you sync them.
  • ✓Your site calls POST /orders on every new order and every status change.
  • ✓Customer phones are sent in international format (+ and country code).
  • ✓Bulk syncs use batches of up to 100 with retries on 429 and 5xx.
  • ✓A test order to your own WhatsApp number produced a message for each status.

Building something bigger?

Enterprise plans come with a dedicated account manager and an SLA. For support, send us the time of the request and the error text from the response.