Checkout Modes
Lava checkout supports four modes, each for a different stage of the customer lifecycle.| Mode | Purpose | Creates Connection? | Requires Connection? |
|---|---|---|---|
subscription | Subscribe to a recurring plan | Yes | No |
topup | Add credits to existing balance | No | Yes |
credit_bundle | Buy a fixed credit pack (subscribers only) | No | Yes |
onboarding | One-time account creation (legacy) | Yes | No |
Subscription Mode
Use when: A customer is starting or updating a recurring plan. This is the recommended mode for most use cases. What happens:- Customer verifies phone number via SMS OTP (new customers enter their number; returning customers verify the phone on file)
- Customer adds payment method
- Customer is charged the plan amount (e.g., $25)
- Subscription is created with automatic monthly renewal
- You receive a
connection_idto use for billing
- Balance resets monthly to the plan amount
- Overages auto-charge to the customer’s card
- Customer can cancel anytime
Topup Mode
Use when: An existing customer wants to add more credits to their balance. What happens:- Customer verifies identity via SMS OTP (sent to the phone on file)
- Customer chooses an amount to add
- Customer is charged immediately
- Balance increases by that amount
- “Add Credits” button in your app
- Low balance warning with recharge CTA
- Letting power users pre-fund larger amounts
Topup requires an existing
connection_id. The customer must have already completed checkout via subscription or onboarding mode first.Credit Bundle Mode
Use when: An existing subscriber wants to buy a fixed credit pack attached to their plan. What happens:- Customer verifies identity via SMS OTP (sent to the phone on file)
- Customer sees the bundle (name, price, credit amount) and confirms payment
- Credits are added to their current subscription cycle
Onboarding Mode (Legacy)
Use when: You want one-time account creation without recurring billing. What happens:- Customer verifies phone number
- Customer adds payment method
- Customer adds an initial credit balance (one-time charge)
- You receive a
connection_id
Which Mode Should I Use?
Backend: Create a Session
Before opening checkout, create a checkout session on your backend. The session token authenticates the checkout flow.origin_url must match the domain that opens the checkout iframe — Lava uses it to restrict which origins can embed the flow.
| Parameter | subscription | topup | credit_bundle | onboarding |
|---|---|---|---|---|
origin_url | required | required | required | required |
subscription_config_id | required | — | — | — |
connection_id | optional | required | required | — |
credit_bundle_id | — | — | required | — |
Frontend: Embed Checkout
The@lavapayments/checkout package exports a useLavaCheckout hook that opens a full-screen checkout iframe when you call open() with a session token.
open() renders a full-screen iframe overlay. The checkout flow happens inside the iframe. When the user completes or cancels, Lava posts a message back to your page, triggering the appropriate callback.Handling Completion
When checkout completes, you receive aconnection_id — the billing relationship between this customer and your merchant account. This is the ID you’ll use for all future billing operations: generating forward tokens, checking balance, and retrieving usage.
The connection object includes has_lava_credit_balance: boolean — use this to check whether a customer has available credits before making requests.
Use frontend callbacks for immediate UX and backend webhooks for reliable processing. In production, use both.
Frontend Callbacks
TheonSuccess callback fires immediately when checkout completes — use it for instant UI feedback like toasts and redirects.
Pros: Immediate feedback, no setup required, great for development.
Cons: User can close browser before callback executes. Not reliable enough for production alone.
Backend Webhooks (Recommended)
Configure a webhook to receiveconnection.created events for reliable server-side processing. See the Webhooks guide for full setup instructions.
Combined Pattern (Best Practice)
Use callbacks for instant UX, webhooks for backend finalization:Troubleshooting
Session expired error
Session expired error
Cause: Checkout session was created more than 60 minutes ago.Solution: Create a new session when the user clicks the checkout button. Don’t pre-create sessions on page load.
Checkout not opening
Checkout not opening
Cause: Invalid or missing checkout session token.Solution:
- Verify
@lavapayments/checkoutis installed - Ensure the component uses the
'use client'directive (Next.js App Router) - Check that
open()is called with thecheckout_session_tokenfrom your backend - Check browser console for errors
Phone verification failing
Phone verification failing
Cause: Invalid phone number format or OTP delivery issues.Solution:
- Phone numbers must be in E.164 format:
+15551234567 - Verify the phone number can receive SMS
- Common mistakes:
(555) 123-4567(formatted) and555-123-4567(missing country code) will not work
Webhook not receiving events
Webhook not receiving events
Cause: Incorrect webhook URL, firewall blocking, or signature verification failing.Solution:
- Verify webhook URL is publicly accessible
- Check webhook logs in the Lava dashboard
- Verify signature validation uses
X-Webhook-Signatureheader with HMAC SHA-256 - Ensure your endpoint returns a 200 status code