Create cart. Add items. Authorize payment.

Create a cart and add/validate multiple cart items. Authorize payment.

Request Parameters

🏷️ header · 📦 body field · unmarked parameters are query params

ParameterTypeRequiredDescription
Locally-Api-Token 🏷️stringYesLocally API token must be passed in the header to authenticate the API consumer.
card_token 📦stringYes
host_domain 📦stringYes
path_to_purchase 📦stringYes
store_id 📦integerYes
delivery_estimate_id 📦integerNo
delivery_charge 📦numberNo
tip_amount 📦numberNo
mute_comms 📦integerYes
items[].upc 📦stringNo
items[].qty 📦integerNo
items[].price_per_unit 📦numberNo
items[].tax_per_unit 📦numberNo
items[].message 📦stringNo
shopper.email 📦stringYes
shopper.phone 📦stringYes
shopper.first_name 📦stringYes
shopper.last_name 📦stringYes
shopper.address 📦stringYes
shopper.city 📦stringYes
shopper.state 📦stringNo
shopper.zip 📦stringYes
shopper.country 📦stringYes
shopper.is_opt_in_consent 📦integerYes
shopper.is_opt_in_consent_brand 📦integerYes

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. When false, the response also carries a top-level error_code and explanatory msg — always check success, 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), or PENDING. On any failure Locally cancels holds already created.
  • data.items[].in_cart — Integer flag (not boolean): 1 if the item is in the cart, 0 if it could not be added.
  • data.items[].desired_qty — Quantity you requested for an item that failed the stock check; returned with error_code 1327 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 the hash parameter, 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 the Locally-Pl-Jwt header to retrieve, update, authorize, or commit the cart later.
  • data.session.id — Locally session ID, returned on every response. Replay it via the Locally-Api-Session-Id header 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 as App server error with a lookup reference — see Handling Errors in Production.
  • error_code — Numeric Locally error code present whenever success is false. 1327 means requested quantity is unavailable (returned with HTTP 200); malformed payloads return HTTP 400 with codes 13401373.
Body Params

Request payload

string
required
string
required
string
required
integer
required
integer
number
number
integer
required
items
array of objects
required
items*
shopper
object
required
Headers
string
required

Locally API token must be passed in the header to authenticate the API consumer

Responses
200

Successful

400

Bad Request

401

Unauthorized

402

Request Failed

403

Forbidden

404

Not Found

429

Too Many Requests

500

Server Error

Language
LoadingLoading…
Response
Click Try It! to start a request and see the response here!