Browser Session
POST https://api.firmly.work/api/v1/browser-session
Overview
POST https://api.firmly.work/api/v1/browser-session
Browser Session is the authentication endpoint that serves as the starting point for all Cart API integrations. It exchanges your App ID for a JWT access token that authenticates subsequent API calls.
Send the request without a body to start a new device session, or include an existing access_token (in the body or fsession_v2 cookie) to renew an existing session while preserving the same device_id.
Authentication
x-firmly-app-id(string, required) — Your App ID, provided by Firmly. This is the only credential this endpoint requires — it does not use thex-firmly-authorizationheader.
Request Body
The body is optional. Send it only to renew an existing token; omit it to start a new device session.
access_token(string) — An existing access token (active or expired) to renew. When provided, the response returns a new token bound to the samedevice_id. When omitted, a fresh device session is created.
Response
-
device_created(boolean, required) —truewhen a brand-new device was created for this session;falsewhen an existing token was renewed. -
access_token(string, required) — The JWT to pass in thex-firmly-authorizationheader on all subsequent API calls. -
device_id(string, required) — Unique identifier for this device session. -
expires_in(number, required) — Seconds until the token expires. Defaults to 3600 (1 hour); a different lifetime may be configured for your App ID. -
expires(number, required) — Unix timestamp (seconds) when the token expires.
Code Examples
curl -X POST https://api.firmly.work/api/v1/browser-session \-H "x-firmly-app-id: YOUR_APPLICATION_ID"
const response = await fetch('https://api.firmly.work/api/v1/browser-session', {method: 'POST',headers: {'x-firmly-app-id': 'YOUR_APPLICATION_ID'}});const { access_token, expires_in } = await response.json();console.log(`Token expires in ${expires_in} seconds`);
import requestsresponse = requests.post('https://api.firmly.work/api/v1/browser-session',headers={'x-firmly-app-id': 'YOUR_APPLICATION_ID'})data = response.json()access_token = data['access_token']expires_in = data['expires_in']print(f"Token expires in {expires_in} seconds")
Response Example
{"device_created": true,"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXZpY2VfaWQiOiI4MmIxMDUyMi01NDgzLTQ3MTktYjU5OS02ZDc4YjEyODI3ZjAiLCJhcHBfaWQiOiJhcHAtMTIzNDU2IiwiZXhwIjoxNjg4OTk4NTcyLCJpYXQiOjE2ODg5OTQ5NzJ9.signature","expires_in": 3600,"expires": 1688998572,"device_id": "82b10522-5483-4719-b599-6d78b12827f0"}
Token Renewal
To preserve the same device_id — and therefore the cart and session state attached to it — pass the previous access_token in the request body or in the fsession_v2 cookie. The server verifies the token’s signature but does not enforce an expiry window, so even long-expired tokens can be renewed as long as the signature is still valid.
curl -X POST https://api.firmly.work/api/v1/browser-session \-H "x-firmly-app-id: YOUR_APPLICATION_ID" \-H "Content-Type: application/json" \-d '{"access_token": "EXPIRED_TOKEN"}'
curl -X POST https://api.firmly.work/api/v1/browser-session \-H "x-firmly-app-id: YOUR_APPLICATION_ID" \-H "Cookie: fsession_v2=EXPIRED_TOKEN"
Using the Access Token
After obtaining the access token, include it in the x-firmly-authorization header on all subsequent API requests:
curl -X GET https://api.firmly.work/api/v2/domains/staging.luma.gift/cart \-H "x-firmly-authorization: YOUR_ACCESS_TOKEN"
Implementation Example
class FirmlyAuth {constructor(appId) {this.appId = appId;this.token = null;this.expiresAt = null;}async getToken() {// Return existing token if still validif (this.token && Date.now() < this.expiresAt) {return this.token;}// Get new tokenconst response = await fetch('https://api.firmly.work/api/v1/browser-session', {method: 'POST',headers: { 'x-firmly-app-id': this.appId }});const data = await response.json();this.token = data.access_token;this.expiresAt = data.expires * 1000; // Convert to millisecondsreturn this.token;}}
Next Steps
After authentication, you can:
- Get Cart — Retrieve the current cart
- Browse Products — View available products
- Add to Cart — Add items to cart
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 — ErrorMissingAppId
The x-firmly-app-id header was not sent.
{ "code": 400, "error": "ErrorMissingAppId", "description": "x-firmly-app-id header is missing or invalid." }
400 — ErrorInvalidAppId
The App ID is not recognized or exceeds the maximum length (512 characters).
{ "code": 400, "error": "ErrorInvalidAppId", "description": "App ID is invalid." }
400 — InvalidToken
An access_token was supplied (in the body or fsession_v2 cookie) but it is not a valid JWT structure (malformed). Returned only during token-renewal calls.
{ "code": 400, "error": "InvalidToken", "description": "Jwt token is invalid." }
401 — InvalidJWTToken
An access_token was supplied but its signature could not be verified, or required claims are missing. Returned only during token-renewal calls.
{ "code": 401, "error": "InvalidJWTToken", "description": "The JWT token is invalid." }