post
https://www.locally.com/headless/api/1.0/cart/validate
Create a cart and add/validate multiple cart items. Authorize payment.
Request Parameters
🏷️ header · 📦 body field · unmarked parameters are query params
| Parameter | Type | Required | Description |
|---|---|---|---|
Locally-Api-Token 🏷️ | string | Yes | Locally API token must be passed in the header to authenticate the API consumer. |
card_token 📦 | string | Yes | |
host_domain 📦 | string | Yes | |
path_to_purchase 📦 | string | Yes | |
store_id 📦 | integer | Yes | |
delivery_estimate_id 📦 | integer | No | |
delivery_charge 📦 | number | No | |
tip_amount 📦 | number | No | |
mute_comms 📦 | integer | Yes | |
items[].upc 📦 | string | No | |
items[].qty 📦 | integer | No | |
items[].price_per_unit 📦 | number | No | |
items[].tax_per_unit 📦 | number | No | |
items[].message 📦 | string | No | |
shopper.email 📦 | string | Yes | |
shopper.phone 📦 | string | Yes | |
shopper.first_name 📦 | string | Yes | |
shopper.last_name 📦 | string | Yes | |
shopper.address 📦 | string | Yes | |
shopper.city 📦 | string | Yes | |
shopper.state 📦 | string | No | |
shopper.zip 📦 | string | Yes | |
shopper.country 📦 | string | Yes | |
shopper.is_opt_in_consent 📦 | integer | Yes | |
shopper.is_opt_in_consent_brand 📦 | integer | Yes |
Example Request
curl 'https://www.locally.com/headless/api/1.0/cart/validate' \
--request POST \
--header 'Locally-Api-Token: {{API_TOKEN}}' \
--header 'Content-Type: application/json' \
--data '{
"card_token": "seti_123XYZ",
"host_domain": "www.example.com",
"path_to_purchase": "bopis",
"store_id": 123,
"mute_comms": 0,
"items": [
{
"upc": "686487455948",
"qty": 2,
"price_per_unit": 225,
"tax_per_unit": 10,
"message": "This is a message for the store"
},
{
"upc": "686487455955",
"qty": 1,
"price_per_unit": 225,
"tax_per_unit": 10,
"message": "This is another message for the store"
}
],
"shopper": {
"email": "[email protected]",
"phone": "+10000000000",
"first_name": "Chester",
"last_name": "Copperpot",
"address": "24 Goondocks Drive",
"city": "Mars",
"state": "OR",
"zip": "99456",
"country": "US",
"is_opt_in_consent": 0,
"is_opt_in_consent_brand": 0
}
}'const response = await fetch('https://www.locally.com/headless/api/1.0/cart/validate', {
method: 'POST',
headers: {
'Locally-Api-Token': '{{API_TOKEN}}',
'Content-Type': 'application/json'
},
body: JSON.stringify({
card_token: 'seti_123XYZ',
host_domain: 'www.example.com',
path_to_purchase: 'bopis',
store_id: 123,
mute_comms: 0,
items: [
{
upc: '686487455948',
qty: 2,
price_per_unit: 225,
tax_per_unit: 10,
message: 'This is a message for the store'
},
{
upc: '686487455955',
qty: 1,
price_per_unit: 225,
tax_per_unit: 10,
message: 'This is another message for the store'
}
],
shopper: {
email: '[email protected]',
phone: '+10000000000',
first_name: 'Chester',
last_name: 'Copperpot',
address: '24 Goondocks Drive',
city: 'Mars',
state: 'OR',
zip: '99456',
country: 'US',
is_opt_in_consent: 0,
is_opt_in_consent_brand: 0
}
})
});
const data = await response.json();import requests
payload = {
"card_token": "seti_123XYZ",
"host_domain": "www.example.com",
"path_to_purchase": "bopis",
"store_id": 123,
"mute_comms": 0,
"items": [
{
"upc": "686487455948",
"qty": 2,
"price_per_unit": 225,
"tax_per_unit": 10,
"message": "This is a message for the store"
},
{
"upc": "686487455955",
"qty": 1,
"price_per_unit": 225,
"tax_per_unit": 10,
"message": "This is another message for the store"
}
],
"shopper": {
"email": "[email protected]",
"phone": "+10000000000",
"first_name": "Chester",
"last_name": "Copperpot",
"address": "24 Goondocks Drive",
"city": "Mars",
"state": "OR",
"zip": "99456",
"country": "US",
"is_opt_in_consent": 0,
"is_opt_in_consent_brand": 0
}
}
response = requests.post(
"https://www.locally.com/headless/api/1.0/cart/validate",
headers={"Locally-Api-Token": "{{API_TOKEN}}"},
json=payload,
)
data = response.json()card_token is a tokenized payment reference from your payment service provider (for Stripe, a SetupIntent seti_* token); if omitted, the cart and its items are validated without authorizing payment. path_to_purchase accepts bopis, ropis, sdd, or sts. A successful response returns a cart_hash_jwt — pass it as the Locally-Pl-Jwt header when committing the cart.
Example Response
{
"success": true,
"data": {
"items": [
{
"upc": "686487455948",
"auth": "SUCCESS",
"in_cart": 1,
"qty": 2
},
{
"upc": "686487455955",
"auth": "SUCCESS",
"in_cart": 1,
"qty": 1
}
],
"cart_hash": "QE3QL6",
"cart_hash_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYXJ0X2hhc2giOiJRRTNRTDYiLCJjcmVhdGVkX2F0IjoxNzIxNDA4MDAwfQ.sQ5xL0y3fY8pWq2ZbNvA7cRkT1uHdGmE4jXoPiC6VnM",
"session": {
"id": "vD2kq9mXw4bT7nR5cJ1sL8fA3gH6pZ0yE2uN4iK9"
}
},
"msg": ""
}{
"success": false,
"data": {
"items": [
{
"upc": "686487455948",
"auth": "SKIPPED",
"in_cart": 0,
"qty": 0
},
{
"upc": "686487455955",
"auth": "SKIPPED",
"in_cart": 1,
"qty": 1
}
],
"cart_hash": "QE3QL6",
"cart_hash_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYXJ0X2hhc2giOiJRRTNRTDYiLCJjcmVhdGVkX2F0IjoxNzIxNDA4MDAwfQ.sQ5xL0y3fY8pWq2ZbNvA7cRkT1uHdGmE4jXoPiC6VnM",
"session": {
"id": "vD2kq9mXw4bT7nR5cJ1sL8fA3gH6pZ0yE2uN4iK9"
}
},
"msg": ""
}{
"success": false,
"data": {
"items": [
{
"upc": "686487455948",
"desired_qty": 1000,
"current_qty": 22
}
],
"session": {
"id": "vD2kq9mXw4bT7nR5cJ1sL8fA3gH6pZ0yE2uN4iK9"
}
},
"msg": "We’re sorry, we've detected that this item is no longer available and cannot be purchased.",
"error_code": 1327
}Response Explanation
success— Boolean outcome of the call. Whenfalse, the response also carries a top-levelerror_codeand explanatorymsg— always checksuccess, not just the HTTP status.data.items[].auth— Per-item authorization status:SUCCESS(bank hold created),FAILED(authorization declined),SKIPPED(not attempted because another step failed), orPENDING. On any failure Locally cancels holds already created.data.items[].in_cart— Integer flag (not boolean):1if the item is in the cart,0if it could not be added.data.items[].desired_qty— Quantity you requested for an item that failed the stock check; returned witherror_code1327 in place of the normal item fields.data.items[].current_qty— Quantity the store can currently sell for that UPC when stock is insufficient.data.cart_hash— Unique short identifier for the cart. Other endpoints accept it as thehashparameter, and it appears in order URIs.data.cart_hash_jwt— Signed token identifying this cart; unlike the session ID it never expires. Pass it as theLocally-Pl-Jwtheader to retrieve, update, authorize, or commit the cart later.data.session.id— Locally session ID, returned on every response. Replay it via theLocally-Api-Session-Idheader to persist the shopper's session between calls; expired IDs are transparently replaced with fresh ones.msg— Human-readable error text; empty string on success. In production, unexpected server errors are masked asApp server errorwith alookupreference — see Handling Errors in Production.error_code— Numeric Locally error code present wheneversuccessisfalse.1327means requested quantity is unavailable (returned with HTTP 200); malformed payloads return HTTP 400 with codes1340–1373.
200Successful
400Bad Request
401Unauthorized
402Request Failed
403Forbidden
404Not Found
429Too Many Requests
500Server Error

