Ecommerce API Integration
The Ecommerce API gives an approved website a read-only view of products explicitly published by one ERP tenant. It is disabled by default and does not accept orders or payments.
Before you connect
- Ask eSecured support to enable Ecommerce API for the tenant. This is a platform-controlled feature flag; tenant users cannot enable it themselves.
- In ERP, open Settings → Integrations → Ecommerce API as the tenant's Tenant Admin.
- Publish only the products intended for the storefront using Items → Edit Product → Publish to ecommerce. A product is returned only when it is a Product, Active, and explicitly published.
- Create a named API key for the website environment (for example,
staging website).
Use separate credentials for staging and production. The API key is shown once; store it in the website's server-side secret manager or environment configuration. Never place it in browser JavaScript, a mobile app, source control, or a public repository. Revoke a key immediately if it is exposed or no longer needed.
The public API hostname is api.erp.co.tz. It resolves through Cloudflare, but the Cloudflare Worker route for the catalog endpoint must be deployed before sharing this address with a live storefront. Until then, requests to this hostname will not reach the API. The hostname is a stable public address, not a security control: the upstream remains protected by the API key and tenant-bound authorization.
Endpoint
GET https://api.erp.co.tz/ecommerce/v1/products
Authorization: Bearer <ecommerce-api-key>
The credential is bound to its tenant when created. Do not send a tenant ID to choose the data source; the API derives the tenant from the verified credential.
Query parameters
| Parameter | Default | Limits | Meaning |
|---|---|---|---|
limit | 50 | 1–100 | Maximum products in this page |
cursor | none | opaque string returned by the API | Continue after the last product in the previous page |
Example response
{
"products": [
{
"id": "item-id",
"sku": "MAR-001",
"name": "Event T-shirt",
"description": "Official event shirt",
"unit": "Each",
"price": 25000,
"currency": "TZS",
"brand": null,
"barcode": null,
"category": "Apparel",
"updatedAt": "2026-10-25T12:00:00.000Z"
}
],
"page": {
"limit": 50,
"hasMore": false,
"nextCursor": null
}
}
| Field | Source |
|---|---|
sku | The item's Item Code |
price | The item's Selling Price as entered in ERP. It is VAT-inclusive or VAT-exclusive according to the tenant's price-entry VAT setting (Settings → Company → Regional & Tax); the API doesn't convert it |
currency | The tenant's base currency |
category | The item's Item Category. If none is set, the Food / Beverage tag used by Restaurant POS; otherwise null |
description, brand, barcode | null when not set on the item |
Only public catalog fields are returned. Internal cost prices, account mappings, stock movements, and customer records are never included. Inventory availability is not part of this first version.
Treat name, description, and other catalog values as text supplied by tenant users. Escape them when rendering in a storefront; do not inject them as HTML.
Server-side JavaScript example
Keep ESECURED_ECOMMERCE_API_KEY in the server's secret manager or environment configuration:
const response = await fetch(
"https://api.erp.co.tz/ecommerce/v1/products?limit=50",
{
headers: {
Authorization: `Bearer ${process.env.ESECURED_ECOMMERCE_API_KEY}`,
Accept: "application/json",
},
},
);
if (!response.ok) {
throw new Error(`ERP catalog request failed: ${response.status}`);
}
const catalogPage = await response.json();
For more products, request the next page using page.nextCursor while page.hasMore is true. Do not log the Authorization header or API key.
Credential lifecycle and safeguards
- Keys are random, tenant-bound, read-only (
products:read), and stored as hashes. - A newly created key is returned once to the Tenant Admin; the ERP does not display it later.
- Up to 10 active credentials can exist for a tenant. Give each integration environment its own key.
- Each key is limited to 60 requests per minute. A
429response includesRetry-After. - Revocation takes effect immediately on the next request.
- Product API requests are read-only, limited to published active products, and paginated with a maximum page size of 100.
- The catalog endpoint rejects browser-originated requests. Keep credentials on the website server; CORS is not an authentication mechanism.
- Responses use
Cache-Control: no-store. Catalog reads update the credential's last-used time but are excluded from per-request API telemetry to avoid storing product data or generating excessive logs. Credential-management operations are logged without request or response bodies.
Errors
| Status | Error | Action |
|---|---|---|
400 | Invalid limit or cursor | Correct the query parameters; use the cursor returned by the previous page |
401 | unauthorized | The key is missing, malformed, unknown or revoked. Check the key; create a replacement if it was lost or revoked |
403 | ecommerce_api_disabled or server_to_server_only | Ask eSecured support to check the tenant feature flag; make the request from the website server, not a browser |
429 | rate_limit_exceeded | Wait for the Retry-After interval before retrying |
500 | internal_error | Retry with backoff; contact support if it persists |
503 | service_unavailable | Retry with backoff; contact support if it persists |
API contract
The machine-readable OpenAPI specification describes the product endpoint and the Tenant Admin credential-management operations. Only GET /ecommerce/v1/products is available at https://api.erp.co.tz. The credential-management operations are internal: they are what Settings → Integrations → Ecommerce API uses, they need a signed-in Tenant Admin's ERP session, and they can't be called through the public hostname.