This guide is for creating a complete and fully formed Locally cart and authorizing for payment in a single request

Prerequisites

Before sending Locally a fully formed cart, your platform should be checking for stock and path-to-purchase availability for cart items following the information in this guide.

Forming a Bulk Cart Submission Request

POST https://www.locally.com/headless/api/1.0/cart/validate
API REFERENCE: https://api.locally.com/reference/headlessapicontrollercart_validate

This endpoint will:

  • Validate your request payload for the correct schema
  • Validate all submitted cart items, ensuring that each:
    • is in stock
    • can be purchased from the store using the requested path to purchase
    • has the correct in-store pricing
  • Accept any local sales tax overrides (circumventing Locally's sales tax estimations)
  • Accept and validate a tokenized reference to a shopper's credit card
  • Create credit card authorizations against each item in the cart
  • Return a response payload containing overall status as well as details about:
    • the cart items' salability and in-cart status (w/ quantities)
    • the status of credit card authorizations
  • Cancel any incomplete credit card authorizations (holds)

Note: this endpoint currently accepts BOPIS transactions only. ROPIS, Same-day Delivery and Ship-to-store transactions are available upon request.

Example Request:

curl --request POST \
  --url https://www.locally.com/headless/api/1.0/cart/validate \
  --header 'Content-Type: application/json' \
  --header 'Locally-Api-Token: {{ API_TOKEN }}'
  --data '{
    "card_token": "seti_XYZ123",
    "host_domain": "www.example.com",
    "path_to_purchase": "bopis",
    "store_id": 123,
    "mute_comms": 1,
    "items": [
        {
            "upc": "686487455948",
            "qty": 1,
            "price_per_unit": 225.00,
            "tax_per_unit": 0.07,
            "message": "This is a message for the store"
        },
        {
            "upc": "686487455955",
            "qty": 3,
            "price_per_unit": 225.00,
            "tax_per_unit": 0.07,
            "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"
    }
}'

Request Parameters:

ParameterDefinition / Notes
card_tokenOptional string. Any tokenized representation of a shopper's credit card. For example, a retailer using the Stripe PSP will expect a SetupIntent (seti_*) token. If not supplied, Locally will attempt to validate the cart and cart items without making any authorizations.
host_domainOptional string. For tracking and attribution.
path_to_purchaseRequired string. Options include bopis, ropis, sdd and sts
store_idRequired integer. Locally's LSID or unique store/location identifier
mute_commsOptional boolean integer. By default, Locally will utilize standard communication templates for notifying stores and shoppers about the purchase and any post-purchase statuses.
itemsRequired array containing list of items in the cart.
items.upcRequired string. 12 digit code representing a product variant.
items.qtyRequired integer. Number of units of this particular UPC which will be added to the cart. Request will fail if there aren't enough of this item's stock to fulfill the order.
items.price_per_unitRequired float. For verification purposes. If the store's own per-unit pricing doesn't match the amount for this UPC, the request will fail.
items.tax_per_unitOptional float. By default, Locally will determine the required sales tax per unit. However, you may choose to supply this amount on the retailers' behalf. If an amount is supplied, it will be used as the final per-unit amount charged to the shopper.
items.messageOptional string. Message from the shopper to the store about the item and/or order.
shopperRequired key/value object containing shopper's billing information.
shopper.emailRequired string. This will be validated for basic formatting.
shopper.phoneRequired string.
shopper.first_nameRequired string.
shopper.last_nameRequired string.
shopper.addressRequired string.
shopper.address_2Optional string.
shopper.cityRequired string.
shopper.stateRequired string.
shopper.zipRequired string. Postal code.
shopper.countryRequired string.
shopper.is_opt_in_consentOptional boolean. If true, the shopper's email will appear in the related retailer's Locally mailing list.
shopper.is_opt_in_consent_brandOptional boolean. If true, the shopper's email will appear in the related brand's Locally mailing list.

Example Responses:

Successful Response (HTTP Response == 200, success: true):

Validation and auth succeeded.

{
	"success": true,
	"data": {
		"items": [
			{
				"upc": "686487455948",
				"auth": "SUCCESS",
				"in_cart": 1,
				"qty": 2
			},
			{
				"upc": "686487455955",
				"auth": "SUCCESS",
				"in_cart": 1,
				"qty": 1
			}
		],
		"cart_hash": "{{hash}}",
		"cart_hash_jwt": "{{jwt}}",
		"session": {
			"id": "{{id}}"
		}
	},
	"msg": ""
}

Failed Response: Cart item couldn't be added. (HTTP Response == 200, success: false):

In this example, one of the cart items could not be added. Credit card authorization attempts were automatically skipped for all items. The item(s) that couldn't be added to the cart will show an in_cart value of 0.

{
	"success": false,
	"data": {
		"items": [
			{
				"upc": "686487455948",
				"auth": "SKIPPED",
				"in_cart": 0,
				"qty": 0
			},
			{
				"upc": "686487455955",
				"auth": "SKIPPED",
				"in_cart": 1,
				"qty": 1
			}
		],
		"cart_hash": "{{hash}}",
		"cart_hash_jwt": "{{jwt}}",
		"session": {
			"id": "{{id}}"
		}
	},
	"msg": ""
}

Failed Response. Authorization failed. (HTTP Response == 401, success: false):

In this example, one of the credit card authorizations failed. Any remaining items will display SKIPPED as their authorization (auth) status.

{
	"success": false,
	"data": {
		"items": [
			{
				"upc": "686487455948",
				"auth": "FAILED",
				"in_cart": 1,
				"qty": 1
			},
			{
				"upc": "686487455955",
				"auth": "SKIPPED",
				"in_cart": 1,
				"qty": 2
			}
		],
		"cart_hash": "{{hash}}",
		"cart_hash_jwt": "{{jwt}}",
		"session": {
			"id": "{{id}}"
		}
	},
	"msg": ""
}

Commit Your Cart

POST https://www.locally.com/headless/api/1.0/cart/commit
API REFERENCE: https://api.locally.com/reference/headlessapicontrollercart_commit

Once you have validated a cart and authorized credit card payment using /headless/api/1.0/cart/validate, you are now able to commit it as a completed purchase. Note: This will not capture funds automatically. In most cases Locally waits for the store to confirm that the item is in stock before funds are captured. However, you must explicitly commit the cart in order to continue the fulfillment process.

To commit a cart, post the request with a Locally-Pl-Jwt header containing the cart token which was returned as the cart_hash_jwt from a successful /headless/api/1.0/cart/validate response.

Example Request:

curl --request POST \
  --url https://www.locally.com/headless/api/1.0/cart/commit \
  --header 'Locally-Pl-Jwt: {{ JWT }}' \
  --header 'Locally-Api-Token: {{ TOKEN }}'

Example Response: (HTTP Response == 200, success: true):

{
	"success": true,
	"data": {
		"message": "Your order has been placed",
		"target_uri": "/order/49R1/UQP778",
		"status_code": 200,
		"session": {
			"id": "{{id}}"
		}
	},
	"msg": ""
}

This will initiate the fulfillment workflow.