Server-to-Server Authentication
Overview
Server-to-Server (S2S) authentication enables your backend services to make authenticated API requests to Firmly APIs. This method is designed for backend integrations where your server communicates directly with Firmly’s APIs.
Required Headers
-
x-firmly-authorization(string, required) — Server-to-server secret token provisioned by Firmly. This is not your APPID — it is a dedicated secret mapped internally to your tenant for request isolation. You may send it either asx-firmly-authorization: <secret>or as the standardAuthorization: Bearer <secret>— the two forms are equivalent. -
x-firmly-device-id(string, required) — The device identifier of the client making the request. Your backend passes this through when making API calls on behalf of a client device.
Device ID
The x-firmly-device-id is used for cart isolation and session management. Pass through your client’s device ID when making API calls on their behalf.
Device ID Requirements
| Rule | Requirement |
|---|---|
| Presence | Must be present and non-empty |
| Max Length | 256 characters |
| Allowed Characters | a-z, A-Z, 0-9, -, _ |
Valid Examples:
user-12345session_abc12382b10522-5483-4719-b599-6d78b12827f0
Invalid Examples:
- Empty string
user.id(period not allowed)user id(space not allowed)
Code Examples
curl -X POST https://api.firmly.work/api/v1/discovery/search \-H "x-firmly-authorization: YOUR_S2S_SECRET" \-H "x-firmly-device-id: user-12345" \-H "Content-Type: application/json" \-d '{"query": "running shoes"}'
const response = await fetch('https://api.firmly.work/api/v1/discovery/search', {method: 'POST',headers: {'x-firmly-authorization': s2sSecret, // S2S secret (not APPID)'x-firmly-device-id': clientDeviceId,'Content-Type': 'application/json'},body: JSON.stringify({ query: 'running shoes' })});const results = await response.json();
import requestsresponse = requests.post('https://api.firmly.work/api/v1/discovery/search',headers={'x-firmly-authorization': s2s_secret, # S2S secret (not APPID)'x-firmly-device-id': client_device_id,'Content-Type': 'application/json'},json={'query': 'running shoes'})results = response.json()
Supported Endpoints
Server-to-Server authentication is accepted across the entire cart and checkout surface — v1 and v2 — plus Discovery and read-only catalog. In practice this is the same set of routes a browser-session or App ID caller can reach, minus the six device-scoped session routes listed under “Not accepted” below. On every accepted route, send the S2S secret plus x-firmly-device-id.
Accepted (S2S secret + x-firmly-device-id):
- Cart — Get Cart, Add / Update / Clear line items, Set Cart Attribution
- Checkout — Set Shipping Info, Set Billing Info, Get / Set Consents, shipping rates
- Promotions — Add / Clear Promo Codes
- Add-ons — Add / Remove Add-on
- Shipments — Set Fulfillment Type, Set Shipping Method, Get Availability
- Order & payment — order reads, the payment handle, and the place-order / complete-order calls
- Discovery & catalog — Discovery Search, Get Product from URL
Not accepted — device JWT only. These six device-scoped session routes require a device JWT; the S2S secret is rejected. Use Browser Session auth instead:
Next Steps
- Search Products — Search for products using S2S auth
Error Responses
Errors return a JSON body with code, error, and description. Program against the error value — descriptions are human-readable and may change.
400 — BadRequest
The x-firmly-device-id header is missing, empty, exceeds 256 characters, or contains characters outside a-z, A-Z, 0-9, -, _.
{ "code": 400, "error": "BadRequest", "description": "Bad request." }
400 — InvalidAPIToken
The S2S secret token is missing, malformed, or not recognized.
{ "code": 400, "error": "InvalidAPIToken", "description": "API token is invalid." }