Docs
Firmly Agentic Commerce
Set theme to dark (⇧+D)

Session Transfer

POST https://api.firmly.work/api/v2/domains/{domain}/session/transfer

Transfers an existing merchant-side session (the buyer’s cart on the merchant’s own store) into the Firmly cart for the current device. The merchant adapter resolves the supplied handle (and any cookies) into the merchant cart, Firmly imports its contents, and the response is the cart in V2 form.

​​ Authentication

​​ Path Parameters

  • domain (string, required) — The merchant’s domain (e.g. staging.luma.gift).

​​ Request Body

  • handle (string, required) — Merchant session identifier. Always sent as a JSON string. Two forms are accepted: - Plain string — the merchant’s session id directly (e.g. "merchant-session-12345"). - JSON-stringified envelope — a JSON object stringified before being placed in handle, used when a merchant integration needs to pass additional metadata. Fields the envelope may carry: | Field | Type | Meaning | | ————– | —— | ——- | | handle | string | The merchant session id. | | token | string | Security token shared with the merchant. Must be ≥ 36 characters. | | merchantData | object | Arbitrary metadata the merchant supplies to Firmly for the transfer. | | version | string | Script / integration version identifier. | Pre-stringify the envelope before sending — the wire value of handle must be a string, not a JSON object.

  • cookies (string[], required) — List of cookies the merchant adapter needs to validate / hydrate the session. Always send this field as an array, even when you have no cookies — pass an empty array ([]) in that case. Although it is technically optional in the request schema, omitting cookies entirely causes the request to fail, because the server folds it into the session fingerprint before validation runs.

​​ Response

Returns the imported cart in the V2 shape — same schema as Get Cart.

​​ Examples


curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/session/transfer \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"handle": "external-session-12345",
"cookies": ["session_cookie_value"]
}'

curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/session/transfer \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"handle": "{\"handle\":\"external-session-12345\",\"token\":\"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0\",\"version\":\"2.0\",\"merchantData\":{\"source\":\"mobile-app\"}}",
"cookies": ["session_cookie_value"]
}'

// Plain handle
const response = await fetch(
'https://api.firmly.work/api/v2/domains/staging.luma.gift/session/transfer',
{
method: 'POST',
headers: {
'x-firmly-authorization': 'YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
handle: 'external-session-12345',
cookies: ['session_cookie_value']
})
}
);
// Stringified envelope
const envelope = {
handle: 'external-session-12345',
token: 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0',
version: '2.0',
merchantData: { source: 'mobile-app' }
};
const responseWithMeta = await fetch(
'https://api.firmly.work/api/v2/domains/staging.luma.gift/session/transfer',
{
method: 'POST',
headers: {
'x-firmly-authorization': 'YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
handle: JSON.stringify(envelope),
cookies: ['session_cookie_value']
})
}
);
const cart = await responseWithMeta.json();

import json
import requests
# Plain handle
response = requests.post(
'https://api.firmly.work/api/v2/domains/staging.luma.gift/session/transfer',
headers={
'x-firmly-authorization': 'YOUR_TOKEN',
'Content-Type': 'application/json'
},
json={
'handle': 'external-session-12345',
'cookies': ['session_cookie_value']
}
)
# Stringified envelope
envelope = {
'handle': 'external-session-12345',
'token': 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0',
'version': '2.0',
'merchantData': {'source': 'mobile-app'}
}
response_with_meta = requests.post(
'https://api.firmly.work/api/v2/domains/staging.luma.gift/session/transfer',
headers={
'x-firmly-authorization': 'YOUR_TOKEN',
'Content-Type': 'application/json'
},
json={
'handle': json.dumps(envelope),
'cookies': ['session_cookie_value']
}
)
cart = response_with_meta.json()

​​ 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 — MissingAuthHeader

The x-firmly-authorization header is missing or empty.


{ "code": 400, "error": "MissingAuthHeader", "description": "x-firmly-authorization header is missing or invalid." }
400 — InvalidToken

The authorization token is not a valid JWT structure.


{ "code": 400, "error": "InvalidToken", "description": "Jwt token is invalid." }
401 — InvalidJWTToken

The device JWT signature does not verify, or required claims are missing.


{ "code": 401, "error": "InvalidJWTToken", "description": "Jwt token is invalid." }
404 — PartnerNotFound

The appid claim on the device JWT does not map to a known partner / tenant.


{ "code": 404, "error": "PartnerNotFound", "description": "Partner not found." }
404 — DomainNotFound

The {domain} path parameter does not match any merchant configured with Firmly, or the merchant has been disabled.


{ "code": 404, "error": "DomainNotFound", "description": "This domain was not found in firmly servers." }
409 — CannotTransferSession

The supplied handle could not be turned into a usable merchant session. Common causes: invalid handle, expired or revoked session on the merchant side, or a token shorter than the required 36 characters when an envelope is sent.


{ "code": 409, "error": "CannotTransferSession", "description": "Required information to perform session transfer is not available." }
409 — NotEnoughStockError

The merchant cart was retrieved, but one or more line items have insufficient stock to import.


{ "code": 409, "error": "NotEnoughStockError", "description": "Not enough stock." }
412 — NoLineItemError

The transferred cart is empty (the merchant returned a cart with no line items).


{ "code": 412, "error": "NoLineItemError", "description": "No line item." }
412 — OperationNotSupported

The merchant adapter does not implement session transfer.


{ "code": 412, "error": "OperationNotSupported", "description": "This operation is not supported for this store." }
400 — InvalidInputBody

Request body fails schema validation. handle must be a string; cookies must be an array of strings when present.


{ "code": 400, "error": "InvalidInputBody", "description": "The body is not processable" }