OrderBridge REST API
Implement these endpoints on your middleware so OrderBridge can match catalogue data, check pricing and allocations, and create draft sales orders. Every call uses POST, JSON, and a required Bearer token. See the PO workflow for when each endpoint is called.
Replace {baseUrl} with the base URL configured in Settings → Integrations (no trailing slash) and {token} with the Alderstone-generated API key for that company. Contract version is always "1".
Endpoints
| Path | Purpose | Called during |
|---|---|---|
POST /health | Connection validation | Save / test in Settings |
POST /catalog/customers/search | Customer matching | PO match stage |
POST /catalog/customers/addresses | Ship/bill address lookup | PO match stage |
POST /catalog/products/search | Product matching by text | PO match stage |
POST /catalog/products/by-sku | Product matching by SKU | PO match stage |
POST /pricing/resolve | Unit price validation | Price check |
POST /credit/customer | Credit exposure snapshot | Optional credit check |
POST /purchase-orders/list | Existing PO reads | Optional list views |
POST /sales-orders/list | Existing SO reads | Optional list views |
POST /sales-orders/usage | Historical order quantity | Allocation caps |
POST /sale-draft | Draft sales order creation | PO submit |
Conventions
Request headers
All endpoints require:
- Name
Authorization- Type
- string
- Description
Bearer {token}: required. Missing or invalid tokens must return 401.
- Name
Content-Type- Type
- string
- Description
application/json
Request body
Every JSON body must include schemaVersion set to "1".
Catalogue hits and confidence
Search endpoints return a hits array of ERP entities. Do not compute or return confidence. Alderstone scores every hit after the response. Return rows in relevance order when possible; Alderstone uses position as a tie-breaker.
Request
{
"schemaVersion": "1"
}
Response
{
"schemaVersion": "1",
"ok": true,
"service": "your-erp"
}
Error responses
Return this JSON shape for all 4xx and 5xx responses. See Errors for the full code reference:
- Name
error- Type
- string
- Description
Human-readable message.
- Name
code- Type
- string
- Description
One of
UNAUTHORIZED,FORBIDDEN,INVALID_JSON,VALIDATION_FAILED,BAD_REQUEST,INTERNAL_ERROR.
- Name
details- Type
- object
- Description
Optional; commonly used for 422 validation (field errors).
Response
{
"schemaVersion": "1",
"error": "Human-readable message",
"code": "UNAUTHORIZED",
"details": {}
}
Health check
Verify connectivity and contract version. Alderstone calls this on Save and Test in Integrations.
Request
{
"schemaVersion": "1"
}Response
{
"schemaVersion": "1",
"ok": true,
"service": "your-erp"
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Search customers
Search customers by name for PO buyer matching.
Body attributes
- Name
query- Type
- string
- Description
Search text. Empty string returns the first page.
- Name
limit- Type
- integer
- Description
Max results (1–500, default 20).
ERP SQL reference
The ERP reference panel shows example queries per dialect: a browse query for empty query strings and an indexed name search. Keep them read-only SELECTs (no FOR UPDATE, no writes) with indexed predicates and a LIMIT so the planner can stop early.
ERP reference
-- Browse (empty query)
SELECT c.external_id AS erp_id,
c.display_name AS erp_name,
c.city
FROM erp.customers AS c
WHERE c.is_active = TRUE
ORDER BY c.display_name
LIMIT $1; -- :limit
-- Fuzzy name search (pg_trgm, PostgreSQL 9.1+)
-- CREATE INDEX customers_name_trgm_idx
-- ON erp.customers USING gin (display_name gin_trgm_ops);
SELECT c.external_id, c.display_name, c.city
FROM erp.customers AS c
WHERE c.is_active = TRUE
AND c.display_name % $1
ORDER BY similarity(c.display_name, $1) DESC, c.display_name
LIMIT $2;Request
{
"schemaVersion": "1",
"query": "acme",
"limit": 20
}Response
{
"schemaVersion": "1",
"hits": [
{
"erpId": "STUB-CUST-001",
"erpName": "Acme Retail (Stub)",
"city": "Cape Town"
},
{
"erpId": "STUB-CUST-002",
"erpName": "Beta Wholesale (Stub)",
"city": "Johannesburg"
}
]
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Customer addresses
List ship-to or billing addresses for a matched customer.
Body attributes
- Name
customerId- Type
- string
- Description
ERP customer id from search (
erpIdin hits).
- Name
kind- Type
- string
- Description
Optional.
shippingorbilling. Omit to return all kinds.
ERP SQL reference
The ERP reference panel shows the point lookup per dialect. Index (customer_id, kind) or (customer_id) plus a filter. No row locks required; a plain read under the database default isolation level (READ COMMITTED on PostgreSQL) is sufficient.
ERP reference
-- Point lookup by customer; index (customer_id, kind)
SELECT a.external_id AS erp_location_id,
a.label AS erp_label,
trim(both ', ' from concat_ws(', ',
a.line1, a.city, a.region, a.postal_code)) AS address,
a.kind AS address_kind
FROM erp.customer_addresses AS a
WHERE a.customer_id = $1
AND a.is_active = TRUE
AND ($2::text IS NULL OR a.kind = $2)
ORDER BY a.is_default DESC, a.label
LIMIT 50;Request
{
"schemaVersion": "1",
"customerId": "STUB-CUST-001",
"kind": "shipping"
}Response
{
"schemaVersion": "1",
"hits": [
{
"erpLocationId": "STUB-ADDR-SHIP-001",
"erpLabel": "Main warehouse",
"address": "1 Dock Rd, Cape Town",
"addressKind": "shipping"
},
{
"erpLocationId": "STUB-ADDR-BILL-001",
"erpLabel": "Accounts payable",
"address": "2 Finance Ave, Cape Town",
"addressKind": "billing"
}
]
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Search products
Search products by name or description for line matching.
Body attributes
- Name
query- Type
- string
- Description
Search text. Empty string returns the first page.
- Name
limit- Type
- integer
- Description
Max results (1–500, default 20).
ERP SQL reference
The ERP reference panel shows a browse query and a full-text search per dialect. Engines without full-text support can fall back to a prefix match on SKU plus a case-insensitive LIKE on name; rank SKU-prefix hits first.
ERP reference
-- Browse (empty query)
SELECT p.external_id AS erp_product_id,
p.sku AS erp_sku,
p.name AS erp_desc
FROM erp.products AS p
WHERE p.is_active = TRUE
ORDER BY p.sku
LIMIT $1;
-- Text search (full-text, GIN on tsvector)
-- CREATE INDEX products_search_idx
-- ON erp.products USING gin (search_tsv);
SELECT p.external_id, p.sku, p.name
FROM erp.products AS p
WHERE p.is_active = TRUE
AND p.search_tsv @@ plainto_tsquery('simple', $1)
ORDER BY ts_rank(p.search_tsv, plainto_tsquery('simple', $1)) DESC,
p.sku
LIMIT $2;Request
{
"schemaVersion": "1",
"query": "widget",
"limit": 20
}Response
{
"schemaVersion": "1",
"hits": [
{
"erpSku": "DEMO-SKU",
"erpDesc": "Demo product (stub)",
"erpProductId": "STUB-PROD-001"
},
{
"erpSku": "WIDGET-42",
"erpDesc": "Widget 42 (stub)",
"erpProductId": "STUB-PROD-002"
}
]
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Product by SKU
Exact or partial SKU lookup during product matching.
Body attributes
- Name
sku- Type
- string
- Description
SKU from the PO line or operator search.
- Name
limit- Type
- integer
- Description
Max hits (1–100, default 10).
ERP SQL reference
The ERP reference panel shows both paths per dialect: prefer an exact match on a unique sku column first, falling back to a prefix match when the PO line is truncated. Avoid %suffix or %infix% patterns on large tables; they force sequential scans and increase lock contention risk on heap pages under concurrent writes.
ERP reference
-- Exact match first (unique btree on sku, cheapest path)
SELECT p.external_id AS erp_product_id,
p.sku AS erp_sku,
p.name AS erp_desc
FROM erp.products AS p
WHERE p.sku = $1
LIMIT 1;
-- Partial / prefix SKU (leading literal only, index-friendly)
SELECT p.external_id, p.sku, p.name
FROM erp.products AS p
WHERE p.sku LIKE $1 || '%'
ORDER BY length(p.sku), p.sku
LIMIT $2;Request
{
"schemaVersion": "1",
"sku": "DEMO-SKU",
"limit": 10
}Response
{
"schemaVersion": "1",
"hits": [
{
"erpSku": "DEMO-SKU",
"erpDesc": "Demo product (stub)",
"erpProductId": "STUB-PROD-001"
}
]
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Resolve pricing
Return the unit price Alderstone should compare against the PO line price. Use null for systemUnitPrice when no price exists.
Body attributes
- Name
customerErpId- Type
- string
- Description
Customer
erpIdfrom catalogue search.
- Name
productErpId- Type
- string
- Description
Product
erpProductIdfrom catalogue search.
Request
{
"schemaVersion": "1",
"customerErpId": "STUB-CUST-001",
"productErpId": "STUB-PROD-001"
}Response
{
"schemaVersion": "1",
"systemUnitPrice": 99.5,
"source": "tier-1"
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Customer credit
Optional credit exposure snapshot for the customer. Fields may be null when credit is not tracked.
Body attributes
- Name
customerErpId- Type
- string
- Description
Customer
erpIdfrom catalogue search.
Request
{
"schemaVersion": "1",
"customerErpId": "STUB-CUST-001"
}Response
{
"schemaVersion": "1",
"creditLimit": 100000,
"creditUsed": 12500,
"currency": "ZAR"
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}List purchase orders
List existing purchase orders (optional customer filter).
Body attributes
- Name
customerErpId- Type
- string
- Description
Optional; filter by customer
erpId.
- Name
limit- Type
- integer
- Description
Max rows (1–100, default 20).
Request
{
"schemaVersion": "1",
"customerErpId": "STUB-CUST-001",
"limit": 20
}Response
{
"schemaVersion": "1",
"orders": [
{
"erpPoId": "STUB-PO-001",
"poNumber": "PO-STUB-001",
"customerErpId": "STUB-CUST-001",
"status": "open",
"orderDate": "2026-01-15"
}
]
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}List sales orders
List sales orders for a customer (optional filter).
Body attributes
- Name
customerErpId- Type
- string
- Description
Optional; filter by customer
erpId.
- Name
limit- Type
- integer
- Description
Max rows (1–100, default 20).
Request
{
"schemaVersion": "1",
"customerErpId": "STUB-CUST-001",
"limit": 20
}Response
{
"schemaVersion": "1",
"orders": [
{
"erpSoId": "STUB-SO-001",
"soNumber": "SO-STUB-001",
"customerErpId": "STUB-CUST-001",
"status": "authorised",
"orderDate": "2026-02-01"
}
]
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Sales usage
Sum ordered quantity for a customer + SKU in an allocation window. Use periodEnd: null for an open-ended window.
Body attributes
- Name
customerErpId- Type
- string
- Description
Customer
erpId.
- Name
sku- Type
- string
- Description
Product SKU.
- Name
periodStart- Type
- string
- Description
Inclusive start date (
YYYY-MM-DD).
- Name
periodEnd- Type
- string | null
- Description
Inclusive end date, or
nullfor no upper bound.
Request
{
"schemaVersion": "1",
"customerErpId": "STUB-CUST-001",
"sku": "DEMO-SKU",
"periodStart": "2026-01-01",
"periodEnd": "2026-12-31"
}Response
{
"schemaVersion": "1",
"units": 42
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Create draft sale
Create a draft sales order when a PO is confirmed. Return saleId (ERP internal reference). When you also return saleNumber, OrderBridge stores and displays that human-readable SO number instead of saleId.
Body attributes
- Name
poNumber- Type
- string
- Description
Purchase order number from the uploaded PO.
- Name
currency- Type
- string
- Description
ISO 4217 code (3 letters), e.g.
ZAR.
- Name
lines- Type
- array
- Description
One or more line objects (see below).
Line attributes
- Name
sku- Type
- string
- Description
Product SKU (required).
- Name
qty- Type
- integer
- Description
Quantity: positive integer.
- Name
unitPrice- Type
- number
- Description
Unit price from the PO line.
Request
{
"schemaVersion": "1",
"poNumber": "DEMO-PO-001",
"currency": "ZAR",
"lines": [
{
"sku": "DEMO-SKU",
"qty": 10,
"unitPrice": 12.5
},
{
"sku": "WIDGET-42",
"qty": 2,
"unitPrice": 99
}
]
}Response
{
"schemaVersion": "1",
"saleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"saleNumber": "SO-12345",
"status": "draft",
"receivedAt": "2026-05-26T10:15:30.000Z"
}Errors
{
"schemaVersion": "1",
"error": "Missing or invalid Authorization header. Use: Authorization: Bearer <token>",
"code": "UNAUTHORIZED"
}Test in the sandbox
The recommended way to test your middleware is the Developer Sandbox. It sends the same requests Alderstone makes, validates responses against this contract, and includes a built-in mock ERP when you have not deployed middleware yet.
Open sandboxQuick link
/sandbox?product=orderbridge&endpoint=health