lomi.
Payments

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

FieldTypeRequiredDescription
amountnumberNo*Amount to charge. Optional if product_id is provided
currency_codestringYesCurrency code (XOF, USD, EUR)
titlestringNoTitle shown on checkout page
descriptionstringNoDescription of the purchase
customer_idstringNoExisting customer ID
customer_emailstringNoCustomer email (pre-fills form)
customer_namestringNoCustomer name (pre-fills form)
customer_phonestringNoCustomer phone (pre-fills form)
product_idstringNoProduct ID (amount calculated from product price)
price_idstringNoSpecific price ID if product has multiple prices
subscription_idstringNoSubscription ID for renewals/modifications
quantitynumberNoQuantity (default: 1)
allow_quantitybooleanNoAllow customer to change quantity
success_urlstringNoRedirect URL on successful payment
cancel_urlstringNoRedirect URL if payment cancelled
allow_coupon_codebooleanNoAllow discount codes (default: false)
require_billing_addressbooleanNoRequire billing address (default: true)
payment_link_idstringNoAssociated payment link ID
metadataobjectNoCustom 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

ParameterTypeDescription
statusstringFilter by status: open, completed, expired (matches checkout_session_status in the database)
limitnumberResults per page (default: 20)
offsetnumberPagination 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

FieldTypeDescription
idstringUnique session identifier
checkout_urlstringURL to redirect customer to
statusstringopen, completed, expired
amountnumberAmount to charge
currency_codestringCurrency code
titlestringSession title
descriptionstringSession description
customer_idstringAssociated customer ID
customer_emailstringCustomer email
product_idstringAssociated product ID
transaction_idstringCreated transaction (after completion)
metadataobjectCustom metadata
expires_atstringExpiration timestamp
created_atstringCreation timestamp

Webhooks

There are two different “webhook” layers in the API codebase:

  1. 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, and checkout.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.

  2. 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 valueWhen 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

StatusDescription
400Invalid input or validation error
401Invalid or missing API key
404Session not found or access denied

On this page