Checkout Sessions

Create one-off payments programmatically — the only public payments endpoint today.

Checkout Sessions

A Checkout Session is the primary API endpoint for taking a payment. You create it from your server, redirect the customer to checkout_url, and receive a webhook when it's paid.

Base URL: https://api.spuke.com/v1 Auth: Authorization: Bearer sk_live_… (or sk_test_…)

Create a session

POST /v1/checkout/sessions

curl -X POST https://api.spuke.com/v1/checkout/sessions \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_12345" \
  -d '{
    "amount": 4990,
    "currency": "eur",
    "customer_name":  "Jane Doe",
    "customer_email": "jane@example.com",
    "reference": "ORDER-12345",
    "description": "Order #12345",
    "line_items": [
      { "name": "Sneaker Runner Pro", "quantity": 1, "amount": 4990, "image_url": "https://…/sneaker.jpg", "price_id": "price_1Tu…" }
    ],
    "success_url": "https://shop.example.com/thanks?o=12345",
    "cancel_url":  "https://shop.example.com/cart"
  }'

Body

Field Type Required Notes
amount integer Minor units (cents). Minimum 250 (= 2.50 in the currency).
currency string 3-letter ISO, lowercase.
customer_name string 2–120 chars. Needed to attribute the payment.
customer_email string Valid email. Receipt is sent here.
mode string payment (default) or subscription. For subscription, pass line_items[0].price_id pointing at a recurring price and omit amount.
reference string Your order ID. Echoed on receipts and webhooks.
description string Short description shown on the checkout.
line_items array Display only. Fields: name, quantity, amount, image_url, price_id, product_id.
success_url / cancel_url string Where the browser is sent after the session ends.
metadata object Free-form key/value returned in webhooks.

line_items[].price_id is optional — pass it when the item comes from a product you created in the dashboard, so it appears in receipts and analytics with its catalog link. The actual amount charged is amount — the price is not fetched from the catalog.

Response

{
  "id": "cs_01H…",
  "object": "checkout.session",
  "mode": "live",
  "status": "open",
  "amount": 4990,
  "currency": "EUR",
  "client_secret": "cs_01H…_secret_…",
  "checkout_url": "https://payments.spuke.com/c/cs_01H…?cs=…",
  "embed_url":    "https://payments.spuke.com/embed/cs_01H…?cs=…",
  "expires_at": 1735776000,
  "created": 1735689600
}

Redirect the buyer to checkout_url, or mount embed_url in an iframe.

Retrieve & expire

GET  /v1/checkout/sessions/{id}
POST /v1/checkout/sessions/{id}/expire

Sessions expire automatically 24 hours after creation. An expired session emits checkout.session.expired.

Idempotency

Send Idempotency-Key: <your-key> on every POST. Keys are scoped to (merchant_id, method, path) and expire after 24 hours.

  • Same key + same body → the original response is replayed verbatim (same status, same body).
  • Same key + different body409 Conflict with:
{
  "error": {
    "type": "idempotency_error",
    "code": "idempotency_key_reused",
    "message": "Idempotency-Key reused with a different request body"
  }
}

See Error reference for the full model.

Fees

Fees are calculated in EUR on your active plan and deducted from the merchant's balance in the transaction currency (converted at live FX). See Fees, currency & minimum amounts.

Errors

HTTP error.type error.code Meaning
400 invalid_request field-specific Missing / malformed field.
400 amount_too_small amount_below_minimum amount below the 2.50 minimum.
401 authentication_error invalid_api_key Bad, revoked or wrong-mode key.
402 card_error card_declined Buyer's card was declined.
409 idempotency_error idempotency_key_reused Same key sent with a different body.
409 resource_conflict merchant_not_ready Merchant onboarding incomplete.
429 rate_limit_error rate_limited Slow down. Respect Retry-After.