Server-to-server integration — from checkout creation to webhook delivery.
This diagram shows the full developer integration using the SatsRail REST API. The merchant's backend creates checkout sessions server-side using the secret key (
sk_live_
), redirects customers to the hosted checkout page, and receives payment confirmations via signed webhooks. Funds settle directly to the merchant's Lightning wallet (non-custodial).
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /api/v1/checkout_sessions |
Create a new checkout session | sk_live_ |
| GET | /api/v1/checkout_sessions/{id} |
Retrieve checkout status | sk_live_ |
| GET | /api/v1/products |
List all products | sk_live_ |
| POST | /api/v1/products |
Create a product | sk_live_ |
| GET | /api/v1/transactions |
List transactions with filters | sk_live_ |
| GET | /api/v1/rates |
Current BTC/USD exchange rate | pk_live_ or sk_live_ |
Merchant registers on SatsRail and receives two API keys:
pk_live_... — Publishable key (safe for client-side/frontend)sk_live_... — Secret key (server-side only, never exposed to clients)Connect a Lightning wallet via the Dashboard or API. Configure a webhook endpoint URL where SatsRail will send payment event notifications.
Customer adds items to cart on the merchant's frontend, clicks "Checkout with Bitcoin." The frontend sends cart data to the merchant's backend server.
Merchant backend sends a POST request to SatsRail:
POST /api/v1/checkout_sessions
Authorization: Bearer sk_live_...
Content-Type: application/json
{
"checkout_session": {
"amount_cents": 5000,
"currency": "usd",
"customer_email": "buyer@example.com",
"success_url": "https://store.com/success",
"cancel_url": "https://store.com/cart",
"metadata": { "order_id": "ORD-1234" }
}
}
SatsRail validates the secret key, checks rate limits, validates the payload schema, then creates a CheckoutSession with a 15-minute TTL.
SatsRail returns:
{
"checkout_url": "https://satsrail.com/checkout/cs_abc123",
"token": "cs_abc123",
"status": "pending",
"expires_at": "2024-01-15T10:15:00Z"
}
The merchant backend returns the checkout_url to the frontend, which redirects the customer to the SatsRail hosted checkout page.
The SatsRail checkout page shows line items, total in USD and sats, and generates a Lightning invoice from the merchant's wallet (non-custodial). Customer pays via QR scan, copy, or WebLN.
Payment routes through Lightning and settles instantly to the merchant's wallet.
SatsRail sends a POST to the merchant's webhook endpoint:
POST https://merchant.com/webhooks/satsrail
X-SatsRail-Signature: sha256=abc123...
{
"event": "checkout.completed",
"checkout_id": "cs_abc123",
"payment_hash": "abc123...",
"amount_sats": 50000,
"amount_usd": "50.00",
"metadata": { "order_id": "ORD-1234" },
"timestamp": "2024-01-15T10:02:30Z"
}
The merchant verifies the HMAC signature using their webhook secret, processes the order, and returns 200 OK. On failure, SatsRail retries: 1 min → 5 min → 30 min → 2 hr.
Customer is redirected to the merchant's
success_url
with
checkout_id
as a query param. The merchant frontend calls
GET /api/v1/checkout_sessions/{checkout_id}
to verify the status is "completed" before showing the success page. Never trust the redirect alone — always verify server-side.
| HTTP Status | Error | Trigger | Recovery |
|---|---|---|---|
| 401 | Unauthorized | Invalid or missing API key | Check sk_live_ key in Authorization header |
| 422 | Validation Error | Malformed payload, missing required fields | Check field-level error messages in response body |
| 429 | Rate Limited | Too many requests per minute | Implement backoff; check Retry-After header |
| 410 | Gone | Checkout session expired (15 min TTL) | Create a new checkout session |
| 200 | Double Payment | Idempotency check detects existing payment | Returns existing payment record (no double-charge) |
| 5xx | Webhook Failure | Merchant endpoint unreachable or returns error | SatsRail retries: 1 min → 5 min → 30 min → 2 hr |
One API call to create a checkout. Lightning settlement. Webhook confirmation.