Checkout Sessions
Create secure, hosted payment pages for your customers.
The Checkout Sessions API allows you to create secure, temporary sessions for customer payments. Redirect your customer to the lomi. hosted checkout page to complete payment.
For cross-cutting rules (coupons, line items, currency, links to payment state), see Checkout behavior.
Checkout sessions expire after 60 minutes by default.
Create a checkout session
Creates a new checkout session and returns a URL to redirect your customer to.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | No* | Amount to charge. Optional if product_id is provided |
currency_code | string | Yes | Currency code (XOF, USD, EUR) |
title | string | No | Title shown on checkout page |
description | string | No | Description of the purchase |
customer_id | string | No | Existing customer ID |
customer_email | string | No | Customer email (pre-fills form) |
customer_name | string | No | Customer name (pre-fills form) |
customer_phone | string | No | Customer phone (pre-fills form) |
product_id | string | No | Product ID (amount calculated from product price) |
price_id | string | No | Specific price ID if product has multiple prices |
subscription_id | string | No | Subscription ID for renewals/modifications |
quantity | number | No | Quantity (default: 1) |
allow_quantity | boolean | No | Allow customer to change quantity |
success_url | string | No | Redirect URL on successful payment |
cancel_url | string | No | Redirect URL if payment cancelled |
allow_coupon_code | boolean | No | Allow discount codes (default: false) |
require_billing_address | boolean | No | Require billing address (default: true) |
payment_link_id | string | No | Associated payment link ID |
metadata | object | No | Custom key-value pairs |
*amount is required unless product_id is provided.
import { LomiSDK } from '@lomi./sdk';
const lomi = new LomiSDK({
apiKey: process.env.LOMI_API_KEY!,
environment: 'live',
});
// Simple checkout with amount
const session = await lomi.checkoutSessions.create({
amount: 10000,
currency_code: 'XOF',
title: 'Order #12345',
description: 'Payment for items in cart',
customer_email: 'customer@example.com',
success_url: 'https://your-site.com/success',
cancel_url: 'https://your-site.com/cancel',
metadata: {
order_id: 'ORD-12345',
},
});
// Product-based checkout
const productSession = await lomi.checkoutSessions.create({
product_id: 'prod_abc123...',
currency_code: 'XOF',
quantity: 2,
allow_coupon_code: true,
success_url: 'https://your-site.com/success',
});
console.log(`Redirect to: ${session.checkout_url}`);from lomi import LomiClient
import os
client = LomiClient(
api_key=os.environ["LOMI_API_KEY"],
environment="test"
)
# Simple checkout with amount
session = client.checkout_sessions.create({
"amount": 10000,
"currency_code": "XOF",
"title": "Order #12345",
"description": "Payment for items in cart",
"customer_email": "customer@example.com",
"success_url": "https://your-site.com/success",
"cancel_url": "https://your-site.com/cancel",
"metadata": {
"order_id": "ORD-12345"
}
})
print(f"Redirect to: {session['checkout_url']}")curl -X POST "https://api.lomi.africa/checkout-sessions" \
-H "X-API-KEY: $LOMI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 10000,
"currency_code": "XOF",
"title": "Order #12345",
"description": "Payment for items in cart",
"customer_email": "customer@example.com",
"success_url": "https://your-site.com/success",
"cancel_url": "https://your-site.com/cancel",
"metadata": {
"order_id": "ORD-12345"
}
}'Response
{
"id": "cs_abc123...",
"checkout_url": "https://checkout.lomi.africa/cs_abc123...",
"status": "open",
"amount": 10000,
"currency_code": "XOF",
"title": "Order #12345",
"customer_email": "customer@example.com",
"expires_at": "2024-01-15T11:30:00Z",
"created_at": "2024-01-15T10:30:00Z"
}List checkout sessions
Retrieve all checkout sessions with optional filtering.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: open, completed, expired (matches checkout_session_status in the database) |
limit | number | Results per page (default: 20) |
offset | number | Pagination offset (default: 0) |
const sessions = await lomi.checkoutSessions.list({
status: 'open',
limit: 20,
});sessions = client.checkout_sessions.list(status="open", limit=20)curl -X GET "https://api.lomi.africa/checkout-sessions?status=open&limit=20" \
-H "X-API-KEY: $LOMI_API_KEY"Get a checkout session
Retrieve details of a specific session.
const session = await lomi.checkoutSessions.get('cs_abc123...');
console.log(`Status: ${session.status}`);session = client.checkout_sessions.get('cs_abc123...')
print(f"Status: {session['status']}")curl -X GET "https://api.lomi.africa/checkout-sessions/cs_abc123..." \
-H "X-API-KEY: $LOMI_API_KEY"Checkout Session Object
| Field | Type | Description |
|---|---|---|
id | string | Unique session identifier |
checkout_url | string | URL to redirect customer to |
status | string | open, completed, expired |
amount | number | Amount to charge |
currency_code | string | Currency code |
title | string | Session title |
description | string | Session description |
customer_id | string | Associated customer ID |
customer_email | string | Customer email |
product_id | string | Associated product ID |
transaction_id | string | Created transaction (after completion) |
metadata | object | Custom metadata |
expires_at | string | Expiration timestamp |
created_at | string | Creation timestamp |
Webhooks
There are two different “webhook” layers in the API codebase:
-
Inbound provider webhooks (lomi. receives these): Wave and Stripe-style handlers use Stripe-like event type strings in the JSON body, for example
checkout.session.completed,checkout.session.payment_failed, andcheckout.session.expired. Those routes live under OpenAPI → Webhooks - Providers (e.g.`POST /webhooks/wave`,`POST /webhooks/stripe`). They are not the event names you pass to`authorized_events`on your own endpoint. -
Outbound merchant webhooks (lomi. calls your URL): Subscriptions are configured with the Postgres enum
webhook_event, the same set documented in Webhooks. The HTTP body field`event`and the`X-Lomi-Event`header use those values (for example`PAYMENT_SUCCEEDED`), as built in`WebhookSenderService.prepareWebhookPayload`in`apps/api`.
For checkout outcomes on your server, subscribe at minimum to:
authorized_events value | When it fires |
|---|---|
`PAYMENT_SUCCEEDED` | Payment completed; payload `data` follows the transaction shape (see Webhooks). |
`PAYMENT_FAILED` | Payment attempt failed (including some provider failure paths). |
There is no separate `checkout.session.*` value in the `webhook_event` enum (apps/api/src/utils/types/api.ts mirrors the database type). Session expiry without a successful charge is reflected on the session and transaction records (e.g. status `expired`); use `GET /checkout-sessions/{id}` or list with `status=expired` / `completed` rather than expecting a merchant webhook named like checkout.session.expired.
Error Responses
| Status | Description |
|---|---|
400 | Invalid input or validation error |
401 | Invalid or missing API key |
404 | Session not found or access denied |