Checkout sessions

A checkout session is the one-shot payment object: a buyer wants to pay amount for description, here's a hosted URL, redirect them to it, listen for the webhook. It's the cleanest way to take money for a single thing in Storlaunch and the underlying engine the public buy-now/cart-checkout endpoints sit on top of.

Storlaunch's checkout-sessions resource has two operating modes:

  1. Legacy mode — workspaces without the Plugipay module run on Storlaunch's own CheckoutSession table, with adapters for Xendit and PayPal wired up locally.
  2. Plugipay mode — workspaces with the module enabled proxy create/retrieve through to Plugipay, and the buyer is hosted at pay.plugipay.com.

Both modes return identical wire shapes; the only visible diff is hostedUrl.

All authenticated endpoints require an sk_* key. The :id/public, :id/pay, and :id/pixel-cookies routes are unauthenticated — they're hit by the buyer's browser on the hosted checkout page.

Endpoints

Merchant (authenticated)

Method Path Purpose
POST /v1/payment/checkout-sessions Create a session
GET /v1/payment/checkout-sessions List sessions
GET /v1/payment/checkout-sessions/:id Retrieve a session
POST /v1/payment/checkout-sessions/:id/refund Refund a completed session
POST /v1/payment/checkout-sessions/:id/confirm Confirm a manual-payment session

Buyer (unauthenticated)

Method Path Purpose
GET /v1/payment/checkout-sessions/:id/public Buyer-side read for the hosted checkout page
POST /v1/payment/checkout-sessions/:id/pay Submit payment-method choice from the hosted page
POST /v1/payment/checkout-sessions/:id/pixel-cookies Persist Meta _fbp / _fbc cookies onto the session

Create

POST /v1/payment/checkout-sessions

Idempotency-Key supported but optional. Same key with a different body returns 409 IDEMPOTENCY_KEY_REUSED.

Request body

Field Type Required Description
amount integer yes Smallest-unit total.
currency string (3) yes ISO 4217.
description string yes Shown to the buyer on the hosted page and in their receipt.
customerEmail string yes Used for the receipt and (for digital products) the delivery URL.
paymentMethods array of strings no Whitelist the methods shown. Subset of qris, va, card, ewallet, paypal. Empty means "all available".
paymentMethod string no Force one method. Skips the picker.
productId string conditional Required if this session is fulfilling a product purchase. Drives the post-pay delivery flow.
variantId / quantity string / integer no If a variant/quantity applies.
successUrl / cancelUrl string no Buyer redirects after pay-or-cancel.
expiresAt ISO 8601 string no Auto-expire time. Defaults to +24 hours.
metadata object no Free-form. Surfaced in webhooks.

Response201 Created

{
  "data": {
    "id": "cs_01HX...",
    "accountId": "acc_01HX...",
    "status": "open",
    "amount": 75000,
    "currency": "IDR",
    "description": "Field Notes Notebook",
    "customerEmail": "alice@example.com",
    "paymentMethods": ["qris","va","card"],
    "paymentMethod": null,
    "hostedUrl": "https://storlaunch.forjio.com/checkout/cs_01HX...",
    "expiresAt": "2026-05-14T10:42:00Z",
    "createdAt": "2026-05-13T10:42:00Z",
    "metadata": { "productId": "prod_01HX..." }
  },
  "error": null,
  "meta": { "requestId": "req_01HX...", "timestamp": "2026-05-13T10:42:00Z" }
}

In Plugipay mode, hostedUrl points at pay.plugipay.com/c/cs_….

Retrieve

GET /v1/payment/checkout-sessions/:id

Returns the session. Use this to poll status, but prefer webhooks — you'll spend less and pay less attention.

List

GET /v1/payment/checkout-sessions?limit=50&cursor=…&status=…

Cursor-paginated. Status filter: open, pending_review, completed, expired, failed.

Refund

POST /v1/payment/checkout-sessions/:id/refund

Fully or partially refund a completed session. The actual refund mechanics depend on the rail (QRIS refunds can take days; card auths refund instantly to the issuer). Refunds emit refund.created and (when the rail settles) refund.succeeded on the Plugipay side — subscribe there if you need that lifecycle, not here.

Request body

Field Type Required Description
amount integer no Smallest-unit. Defaults to the full session amount.
reason string no Free text. Surfaced on the receipt.

Confirm (manual session)

POST /v1/payment/checkout-sessions/:id/confirm

For sessions paid by manual bank transfer that are sitting in pending_review. The merchant has seen the transfer land; this call flips the session to completed, runs fulfilment, fires checkout.completed with metadata.source = "manual_confirm".

Buyer endpoints

These power the buyer-facing hosted checkout page:

  • GET /:id/public — lightweight read with only buyer-safe fields (no account secrets, no full metadata).
  • POST /:id/pay — called when the buyer picks a payment method on the hosted page. Server-side creates the underlying provider invoice (Xendit or PayPal in legacy mode; Plugipay handles it transparently in Plugipay mode) and returns the redirect URL.
  • POST /:id/pixel-cookies — buyer's browser stashes _fbp / _fbc cookies so server-side Meta CAPI can fire the post-pay Purchase event with deduplication intact.

These are called by Storlaunch's own checkout UI; you usually don't call them directly.

The session object

Field Type Nullable Description
id string no cs_ + 26-char ULID.
accountId string no Workspace.
status enum no open / pending_review / completed / expired / failed.
amount integer no Smallest-unit total.
currency string no ISO 4217.
description string no Buyer-visible.
customerEmail string no For receipt + delivery.
customerId string yes Linked customer (if known at create or upgraded later).
paymentMethods array no Allowed methods.
paymentMethod string yes Actual method used. null until paid.
hostedUrl string no Where to redirect the buyer.
successUrl / cancelUrl string yes Post-pay redirects.
expiresAt string (ISO 8601 UTC) no When open transitions to expired.
completedAt string (ISO 8601 UTC) yes When the session settled.
metadata object no Free-form.
createdAt string (ISO 8601 UTC) no Creation time.

Events

Event type Fires on Notes
checkout.completed Session transitions to completed. The canonical "money's in, fulfil this" event. See checkout.completed.
product.purchased Per delivery created post-checkout. Storlaunch-specific event with productId, deliveryId, licenseKey. See product.purchased.

checkout.expired, checkout.refunded, and payment.succeeded exist as concepts but are not emitted from Storlaunch's outbox — in Plugipay mode you can subscribe to the corresponding Plugipay events directly.

Next