Replacing Checkout
Use this approach when you want your server to redirect users to Simpler Checkout at the point where they would normally enter your CMS's native checkout.
This endpoint does not require any authentication headers. You only need your merchant_id (App ID).
Overview
The flow has three steps:
- Build a Cart Request object describing the user's cart.
- POST it to the Simpler endpoint.
- Forward the redirect response to the user's browser.
After the redirect, the user lands on the Simpler Checkout page where they complete their purchase. Simpler will then call your Platform Interface APIs to price the cart, resolve shipping, and submit the order.
Cart Request Schema
The Cart Request is sent as form fields. items and metadata are JSON-encoded strings; every other field is a plain string.
| Field | Type | Required | Description |
|---|---|---|---|
merchant_id | string | Yes | Your App ID. |
currency | string | Yes | ISO 4217 currency code (e.g. EUR, USD, GBP). Any valid ISO 4217 code is accepted. |
locale | string | Yes | IETF language tag per RFC 5646 (e.g. en, el, fr). Any valid tag is accepted. |
items | JSON string | Yes | JSON-encoded array of one or more line items (must not be empty). See below. |
coupon | string | No | A coupon code to pre-apply in the Simpler checkout form. |
remote_loyalty_coupon | string | No | A remote loyalty coupon code, pre-selected on your own site, to pre-apply in the Simpler checkout form. Independent of coupon — both can be sent together. See Remote loyalty coupons. |
remote_session_id | string | No | A token identifying a shopper logged in to your store, so they arrive at checkout signed in. See Cross-Login. |
metadata | JSON string | No | JSON-encoded object of string key-value pairs, passed through to your backend on every subsequent Platform Interface call for this session. Intended for read-only attribution or tracking (A/B test buckets, internal references). Do not use it as a mutable state store — see Cart Metadata. |
items[]
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Product identifier as used in your Platform Interface product catalog. |
quantity | integer | Yes | Number of units. Integer, minimum 1. |
attributes | object | No | Key-value pairs identifying a specific product variant (e.g. {"color": "blue", "size": "L"}). For products with variants, keys must match a catalog variant definition in your Platform Interface. Omit for simple products with no variants. |
Sending the Request
POST the cart data as application/x-www-form-urlencoded to:
https://checkout.simpler.so/v1/carts
JSON request bodies are not supported. Encode items and metadata as JSON strings before form-encoding the payload — bracket notation (items[0][id]=…) is not understood, and such a request arrives with no items. For example, a single item serialises on the wire as:
merchant_id=YOUR_APP_ID¤cy=EUR&locale=en&items=%5B%7B%22id%22%3A%22PRODUCT_ID%22%2C%22quantity%22%3A1%2C%22attributes%22%3A%7B%22color%22%3A%22blue%22%7D%7D%5D
On success, the server responds with a 303 See Other status and a Location header pointing to the Simpler Checkout page. Your server should forward this redirect to the user's browser:
HTTP/1.1 303 See Other
Location: https://checkout.simpler.so/carts/<uuid>
Content-Length: 0
The Location URL is reusable and does not expire. Note that each request creates a new checkout session — re-POSTing the same cart produces a duplicate session, and there is no idempotency key, so avoid blindly retrying this call on the redirect path.
If the request does not return a 303, you can redirect the shopper to a checkout URL built from the same cart instead, or render your native checkout. Note that checkout URLs use the shorter item field names qty and attrs.
PHP + cURL Example
$url = 'https://checkout.simpler.so/v1/carts';
$data = [
'merchant_id' => 'YOUR_APP_ID',
'currency' => 'EUR',
'locale' => 'en',
'items' => json_encode([
[
'id' => 'PRODUCT_ID',
'quantity' => 1,
'attributes' => [
'color' => 'blue',
'size' => 'L'
]
]
]),
'coupon' => 'WELCOME10',
'metadata' => json_encode([
'source' => 'cart_page'
])
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_FOLLOWLOCATION => false,
]);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
if ($info['http_code'] == 303) {
preg_match('/^Location:\s+(.*)$/mi', $response, $matches);
$location = trim($matches[1]);
curl_close($ch);
header("Location: $location", true, 303);
exit;
}
// The request did not result in a redirect — something went wrong.
$headerSize = $info['header_size'];
$body = substr($response, $headerSize);
curl_close($ch);
error_log("Cart request failed with status {$info['http_code']}: $body");
The example sets CURLOPT_FOLLOWLOCATION => false on purpose: you want to capture the Location header and forward the redirect to the shopper's browser, not follow it server-side. Re-emitting it with header("Location: $location", true, 303) preserves the 303 status so the browser performs the redirect.
curl Example
curl -i -X POST https://checkout.simpler.so/v1/carts \
--data-urlencode 'merchant_id=YOUR_APP_ID' \
--data-urlencode 'currency=EUR' \
--data-urlencode 'locale=en' \
--data-urlencode 'items=[{"id":"PRODUCT_ID","quantity":1,"attributes":{"color":"blue","size":"L"}}]' \
--data-urlencode 'coupon=WELCOME10' \
--data-urlencode 'metadata={"source":"cart_page"}'
The -i flag includes the response headers in the output, so you can see the 303 status and the Location header.
Error Responses
All error responses return a JSON body with a message field describing the issue.
| Status Code | Meaning |
|---|---|
400 | Invalid request body. |
404 | Invalid App ID / Store not found. |
500 | Internal server error. |