Skip to content

Pay for a basket

POST
/storefront/sites/{host}/checkout
curl --request POST \
--url https://example.com/storefront/sites/northgate.shop.getbottle.app/checkout \
--header 'Content-Type: application/json' \
--data '{ "lines": [ { "productId": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f", "quantity": 1, "hasEmpty": true } ], "fulfilment": "delivery", "postcode": "example", "deliveryOptionId": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f", "customerId": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f", "name": "example", "email": "hello@example.com", "phone": "example", "address": { "line1": "example", "line2": "example", "city": "example", "postcode": "example" }, "wantedOn": "2026-04-15", "notes": "example", "marketingConsent": false, "ageConfirmed": true, "acceptsTerms": true, "addressId": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f", "payment": "card", "pin": "example" }'

Deliberately unauthenticated. Prices the basket again, checks it can be bought, the address is in the postcode priced, the day is one on offer (the first, when left out), the age box when the shop asks, and makes a Stripe payment page on the business’s own Stripe account. Answers with its address: send the shopper there. Card details are typed into Stripe, never into Bottle. The order is written once Stripe says it was paid, and the shopper comes back to /order/{id} on the shop. The page lasts an hour. Ten tries a minute from one address.

host
required
string
Example
northgate.shop.getbottle.app
preview
string
<= 2000 characters
Media typeapplication/json
object
lines
required
Array<object>
>= 1 items <= 50 items
object
productId
required

UUID v7

string format: uuid
Example
019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f
quantity
required
integer
>= 1 <= 50
hasEmpty
boolean
fulfilment
string
default: delivery
Allowed values: delivery collection
postcode
string
<= 10 characters
deliveryOptionId

UUID v7

string format: uuid
Example
019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f
customerId

UUID v7

string format: uuid
Example
019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f
name
required
string
>= 1 characters <= 120 characters
email
required
string format: email
<= 200 characters
phone
required
string
>= 7 characters <= 30 characters
address
object
line1
required
string
>= 1 characters <= 120 characters
line2
string
<= 120 characters
city
required
string
>= 1 characters <= 80 characters
postcode
required
string
>= 5 characters <= 10 characters
wantedOn
string format: date
notes
string
<= 500 characters
marketingConsent
boolean
ageConfirmed
boolean
acceptsTerms
required
boolean
addressId

UUID v7

string format: uuid
Example
019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f
payment
string
default: card
Allowed values: card account
pin
string
/^\d{4,6}$/

Where to send the shopper

Media typeapplication/json
object
url
required
string format: uri
placed
boolean
checkoutId

UUID v7

string format: uuid
viewToken
string
Example
{
"checkoutId": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f"
}

Not a shop, or not open. No body.

The basket cannot be bought as it is (basket_problems, with the problems), the address is not in the postcode priced (postcode_changed), the day is not on offer (day_not_offered), or the age box is needed (age_not_confirmed)

Media typeapplication/json
Any of:
object
error
required
string
message
required
string
problems
required
Array<object>
object
code
required
string
Allowed values: out_of_stock not_for_sale not_deliverable below_minimum no_postcode payments_off
productId
required

UUID v7

string | null format: uuid
message
required
string
Example
{
"error": "basket_problems",
"problems": [
{
"code": "out_of_stock",
"productId": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f"
}
]
}

Validation failed

Media typeapplication/json
object
error
required
string
Allowed values: validation
message
required
string
issues
required
Array<object>
object
path
required
string
message
required
string
Example
{
"error": "validation",
"issues": [
{
"path": "email",
"message": "Invalid email"
}
]
}

Too many requests from one address

Media typeapplication/json
object
error
required
string
message
required
string
Example
{
"error": "not_found",
"message": "Customer not found"
}

Stripe could not be reached; nothing was charged

Media typeapplication/json
object
error
required
string
message
required
string
Example
{
"error": "not_found",
"message": "Customer not found"
}