Checkout intents
Create a checkout from a cart, then read it until it's paid.
A checkout intent is one payable checkout: a priced cart, the amount due, and the ways the buyer can pay. Create one per purchase attempt. See Headless checkout for the full guide.
Create a checkout
Scope: commerce.checkout
Body
| Field | Type | Required | Notes |
|---|---|---|---|
items | array | Yes | 1 to 60 lines |
items[].productId | string | Yes | A product _id from your store (24 hex characters) |
items[].quantity | integer | No | 1 to 999, default 1 |
items[].selectedOptions | object | When the product has options | e.g. { "Color": "Black", "Size": "M" } |
customerInfo | object | For physical items | name, email, phone, address { line1, line2, city, state, postalCode, country } |
paymentRail | string | No | Omit for crypto only; "buyer_choice" to offer card when eligible |
description | string | No | Defaults to one built from the items |
expiresAt | ISO 8601 | No | Default 24 hours, maximum 30 days |
Sending price, amount or unitPrice on any item is rejected with 400. Swop always prices from your catalogue.
curl -X POST https://apps.apiswop.co/api/v5/merchant/checkout-intents \
-H "Authorization: Bearer $SWOP_MERCHANT_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [ { "productId": "66a1b2c3d4e5f6a7b8c9d0e1", "quantity": 1, "selectedOptions": { "Color": "Black" } } ],
"customerInfo": {
"name": "Ada Buyer",
"email": "ada@example.com",
"address": { "line1": "1 Main St", "city": "Austin", "state": "TX", "postalCode": "78701", "country": "US" }
},
"paymentRail": "buyer_choice"
}'Response 201
{
"success": true,
"data": {
"intentId": "co_7Hk2mPq9xR4s",
"status": "active",
"paymentRail": "crypto",
"checkoutMode": "online",
"description": "Swop Classic Card",
"amount": { "value": 30, "currency": "USDC" },
"fees": {
"currency": "USDC",
"feesPayer": "merchant",
"subtotalAmount": 30,
"platformFeeBps": 50,
"platformFeeAmount": 0.15,
"royaltyAmount": 0,
"merchantReceivesAmount": 29.85,
"totalDueAmount": 30
},
"lineItems": [
{
"productId": "66a1b2c3d4e5f6a7b8c9d0e1",
"name": "Swop Classic Card",
"quantity": 1,
"unitAmount": 25,
"totalAmount": 25,
"requiresShipping": true,
"shippingAmount": 5,
"productType": "physical",
"selectedOptions": { "Color": "Black" }
}
],
"merchant": { "id": "65f0c1…", "name": "Acme", "wallet": { "address": "…" } },
"customerInfo": { "name": "Ada Buyer", "email": "ada@example.com", "address": { "line1": "1 Main St", "city": "Austin", "state": "TX", "postalCode": "78701", "country": "US" } },
"checkoutUrl": "https://www.swopme.app/checkout/co_7Hk2mPq9xR4s",
"paymentRequest": {
"rail": "solana_pay",
"recipient": "…",
"amount": 30,
"currency": "USDC",
"tokenMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"tokenDecimals": 6,
"reference": "…",
"memo": "swop:co_7Hk2mPq9xR4s",
"url": "solana:…",
"status": "awaiting_payment",
"expiresAt": "2026-10-30T18:00:00.000Z"
},
"cardOffered": false,
"marketplaceOrder": null,
"expiresAt": "2026-10-30T18:00:00.000Z",
"createdAt": "2026-10-29T18:00:00.000Z",
"updatedAt": "2026-10-29T18:00:00.000Z"
}
}Key fields
| Field | Type | Meaning |
|---|---|---|
intentId | string | co_…. Save it with your order. |
status | string | See statuses |
paymentRail | string | The rail in use, e.g. crypto |
amount.value | number | Total due, USDC |
fees.totalDueAmount | number | What the buyer pays (shipping included) |
fees.platformFeeBps | number | 50 = 0.5% |
fees.platformFeeAmount | number | The fee in USDC |
fees.merchantReceivesAmount | number | What you receive |
lineItems[] | array | Priced lines, including shippingAmount and requiresShipping |
checkoutUrl | string | Swop's hosted page for this checkout |
paymentRequest | object | null | The USDC payment request. null while the buyer is choosing card or crypto. |
paymentRequest.url | string | A solana: link. Show as a link and a QR code. |
cardOffered | boolean | Whether card can be used for this checkout |
marketplaceOrder | object | null | The order created once paid |
expiresAt | ISO 8601 | When it stops being payable |
Errors
| Status | When |
|---|---|
400 | A price on an item; bad productId; product unavailable; invalid options; bad paymentRail (paymentRail must be omitted (crypto) or "buyer_choice".); bad expiresAt |
400 SHIPPING_DETAILS_REQUIRED | Physical item without name, email or address; see missing |
403 | Key lacks commerce.checkout |
404 | A product that isn't yours |
Retrieve a checkout
Scope: commerce.read
Returns the same object as create (without cardOffered). Only checkouts that belong to you are found; anything else is 404 (No such checkout.).
curl https://apps.apiswop.co/api/v5/merchant/checkout-intents/co_7Hk2mPq9xR4s \
-H "Authorization: Bearer $SWOP_MERCHANT_KEY"Public payment endpoints
These are called without an API key. The unguessable intentId authorises them, so your buyer's browser can call them directly. Base: https://apps.apiswop.co/api/v5/checkout-intents. Rate limit: 20 requests per 15 minutes per client.
| Method | Path | Body | Does |
|---|---|---|---|
POST | /{intentId}/select-crypto | none | Buyer chose USDC. Read the checkout again for paymentRequest. |
POST | /{intentId}/card-payment-intents | none | Buyer chose card. Returns clientSecret and publishableKey for Stripe's Payment Element. |
GET | /{intentId}/card-payment | Card payment state. Treat transfer_pending, transfer_in_progress or transferred as paid. | |
POST | /{intentId}/card-payment/release | none | Abandon card so the buyer can switch back to USDC |