TeePayDocs
Payments

Checkout sessions

Create a TeePay hosted checkout page from your server and redirect your customer to it.

Available

A checkout session is a TeePay-hosted payment page for one amount. You create it from your server, redirect the customer to checkout_url, and TeePay collects the phone number, sends the prompt and shows the result. You never handle payment details.

POST/v1/checkout-sessionscheckout:create

Create a session

curl https://api.teepay.me/v1/checkout-sessions \
  -H "Authorization: Bearer $TEEPAY_API_KEY" \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Order 1001",
    "description": "2 x Coffee bag",
    "amount_minor": "500000",
    "currency": "TZS",
    "expires_in": 86400,
    "reference": "order-1001",
    "metadata": { "cart": "c-77" }
  }'

Prop

Type

Unknown fields are rejected, so typos never pass silently.

Response 201

{
  "id": "7c0e5d2a-1b3f-4c8e-9a6d-2f4b8e1c0d9a",
  "object": "checkout_session",
  "status": "open",
  "title": "Order 1001",
  "description": "2 x Coffee bag",
  "currency": "TZS",
  "amount_minor": "500000",
  "checkout_url": "https://checkout.teepay.me/checkout/…",
  "payment_profile_id": null,
  "reference": "order-1001",
  "metadata": { "cart": "c-77" },
  "payment": null,
  "environment": "live",
  "created_at": "2026-10-28T10:00:00Z",
  "expires_at": "2026-10-29T10:00:00Z"
}

Redirect the customer to checkout_url.

Session status

statusMeaning
openWaiting for payment. A failed attempt keeps it open so the customer can retry.
processingA payment is in progress. Do not fulfil yet.
paidTeePay verified and ledger-posted the payment. payment.reference is set. Fulfil.
expiredThe page expired without a verified payment.
unavailableStatus could not be read right now. Try again; never assume payment.

Payment profiles

A payment profile is optional. Without one, the customer sees TeePay's standard checkout with your business name and mobile money, and returns to teepay.me afterwards. With a profile (or a default profile on your account) the page uses its branding, the customer returns to its return URL, and webhooks go to its webhook URL.

Return and webhook URLs are only configured in the dashboard, never per request, so a leaked key cannot redirect your customers or your webhooks elsewhere.

Confirm payment

The payment.completed webhook for a session has:

"source": { "type": "checkout_session", "id": "7c0e5d2a-1b3f-4c8e-9a6d-2f4b8e1c0d9a" }

Or read the session:

GET/v1/checkout-sessions/{id}checkout:read

Idempotency and limits

  • Same Idempotency-Key and same body: the same session, with Idempotent-Replayed: true.
  • Same key, different body: 409 idempotency_conflict.
  • 30 sessions per account per minute, plus your account's collection limits.
  • Errors specific to sessions: invalid_amount, unsupported_currency, payment_profile_unavailable (an unknown payment_profile_id).

On this page