API Keys
Manage your API keys and authentication credentials
Overview
API keys are managed through the EQUOS subscriber console under Integrations → API Keys. Each key is an OAuth 2.0 machine-to-machine credential for server-to-server calls to /e9v3.
Authentication: These management endpoints require a signed-in account admin (Firebase ID token). They are separate from the M2M JWT you use on /e9v3.
Business tenancy
One API key binds to one business by default. When you exchange a classic key for a token and call /e9v3, EQUOS resolves the tenant from the key itself. Do not send X-Business-ID (or a businessId query) on public API requests for those keys — the header is ignored for tenancy.
- In the console, use the business picker at the top of Integrations to choose which business you are managing, then generate or revoke keys for that business.
- Multi-business account admins can still mint one key per business (you do not need to change your default claim first — pass
businessIdon the admin API, or pick the business in the UI). Existing keys keep working this way. - Optionally, select additional owned businesses when minting to create a multi-business key. Those keys require
X-Business-IDon every/e9v3call; the value must be one of the businesses bound at create time. Missing header → 400businessId required; unbound id → 403key not bound to business. Revoking that key from any one bound business stops it working for all of them.
GET/api/keysList API keys
List API keys for a business (home tenant or extra tenant). Omit businessId to use your Firebase claim default; pass ?businessId= for a business you own (or super admin).
| Field | Type | Required | Description |
|---|---|---|---|
businessId | string | Optional | Target business. Defaults to the businessId claim on your admin token. Override requires a business you own (or super admin). |
[
{
"id": "key-uuid-1",
"businessId": "biz_equos_demo",
"name": "Production Integration",
"prefix": "abc12345",
"scopes": ["orders:write"],
"createdAt": "2024-01-15T10:00:00Z",
"expiresAt": null,
"isActive": true
},
{
"id": "key-uuid-2",
"businessId": "biz_equos_demo",
"name": "Staging Integration",
"prefix": "def67890",
"scopes": ["orders:read", "orders:write"],
"createdAt": "2024-01-10T15:30:00Z",
"expiresAt": "2025-01-10T00:00:00Z",
"isActive": true
}
]{"error": "no businessId in user claims"}{"error": "not authorized for business"}- id: Unique identifier for the key
- businessId: On a list response, the business you requested, not the key's home business
- businessIds: Missing means a single-business key. Present means the key is shared. On a list response the array is only the business you requested.
- name: Human-readable label
- prefix: First 8 characters of the client_id (for identification)
- scopes: Array of granted scopes
- createdAt: Creation timestamp
- expiresAt: Expiration timestamp (null = never expires)
- isActive: Whether the key is active
A missing businessIds means a single-business key. A present businessIds means the key is shared. On a list response, businessId is the business you requested, not the key's home business, and a present businessIds array names only that business.
POST/api/keysCreate API key
Create a new API key bound to one business, or to several when businessIds has two or more ids and each is a business you own (or super admin). The clientSecret is only returned once at creation time.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Required | Display name for the key |
scopes | array | Required | At least one scope (see Available Scopes below) |
expiresAt | string (RFC3339) | Optional | Expiration date (null = never expires) |
businessId | string | Optional | Home business to bind the key to. Defaults to your claim businessId. Must be a business you own (or super admin). |
businessIds | string[] | Optional | Two or more ids, each a business you own (or super admin). Omit, or send a single id, for a classic one-business key. Home is businessId (or the claim default); extras are the remaining ids. |
{
"id": "key-uuid-3",
"businessId": "biz_equos_demo",
"name": "New Integration",
"prefix": "ghi11111",
"scopes": ["orders:write"],
"createdAt": "2024-01-20T12:00:00Z",
"expiresAt": null,
"isActive": true,
"clientId": "your_client_id",
"clientSecret": "secret_abc123def456..."
}{"error": "at least one scope is required"}{"error": "no businessId in user claims"}{"error": "not authorized for business"}- Save the clientSecret immediately: It is only shown once at creation time
- Use clientId and clientSecret for token exchange: See Authentication for details
- Expiration is optional: Leave expiresAt null for keys that never expire
- Binding is permanent: A classic key always resolves to the
businessIdstamped at create time. A multi-business key is permanently bound to that set; callers must sendX-Business-ID.
DELETE/api/keys/:idRevoke API key
Revoke an API key. This immediately invalidates the key for every business it is bound to. Pass ?businessId= when revoking a key for a non-default business.
| Field | Type | Required | Description |
|---|---|---|---|
businessId | string | Optional | Business that owns the key. Defaults to your claim businessId. |
{
"ok": true
}{"error": "api key not found"}{"error": "no businessId in user claims"}{"error": "not authorized for business"}- One revoke covers every binding: A key can be bound to several businesses. Revoking it from any one of them stops it working for all of them. On a list, a present
businessIdsmeans the key is shared, even when the array only names the business you requested.
Available Scopes
| Scope | Description | Common Use |
|---|---|---|
orders:read | Read order data and status | Monitoring, analytics |
orders:write | Create and manage orders | Order creation, integrations |
orders:fulfil | Finalize, fulfil (create warehouse tasks) and commit orders. Higher risk. Requires orders:write. | Ingest and other integrations that finalize, fulfil, and commit — on create via advance, or POST /e9v3/orders/{type}/{orderId}/finalize|fulfil|commit |
inventory:read | Read inventory data | Stock levels, forecasting |
inventory:write | Declare on-hand quantities and upsert/archive catalogue items | Stock adjustments, product catalogue sync |
contacts:read | Read contacts and search addresses; export a shopper's personal data (POST /e9v3/contacts/export) | Customer/supplier lookups, GDPR data requests |
contacts:write | Erase a shopper's personal data (POST /e9v3/contacts/erase and /erase/shop) | Shopify customers/redact and shop/redact |
warehouse:read | Reserved — not yet enforced by any endpoint | — |
warehouse:write | Reserved — not yet enforced by any endpoint | — |
webhooks:manage | Manage webhook subscriptions (order, shipment and inventory events) | Shopify app, event-driven integrations |
Best Practices
Key Security
- Store safely: Use environment variables or secrets management systems (AWS Secrets Manager, HashiCorp Vault, etc.)
- Never commit to version control: Add
.envand similar files to.gitignore - Rotate regularly: Create new keys and revoke old ones on a scheduled basis
- Prefer one key per business unless you need a multi-business key: Classic keys need no tenant header. Multi-business keys must send
X-Business-IDon every/e9v3call. - Use separate keys per environment: Maintain distinct keys for development, staging, and production
- Revoke immediately if compromised: If a key is exposed, revoke it using the DELETE endpoint
Scope Management
- Principle of least privilege: Grant only the scopes your integration actually needs
- Review regularly: Audit your active keys and remove any that are no longer in use
- Set expiration dates: Consider setting expiration dates for time-limited integrations
Monitoring
- Monitor for errors: Alert on repeated 401/403 errors which may indicate compromised credentials
- Track usage: Monitor which keys are being used and from which IP addresses (if applicable)
- Audit logs: Keep records of when keys are created, rotated, and revoked