Skip to main content
Payoes provides a hosted checkout page so you do not need to build wallet integration yourself.

Checkout URL

Every payment includes a checkout_url:
https://your-payoes-host/c/{payment_id}
Share this link directly or redirect users from your application after creating a payment via API. Checkout sessions (cs_...) also resolve to the same hosted page.

Customer flow

  1. Customer opens the checkout URL
  2. Checkout loads payment amount, settlement asset, allowed assets, merchant name, and logo
  3. If multiple allowed assets are configured, the customer selects which asset to pay with
  4. Customer clicks Connect wallet (Stellar Wallet Kit: Freighter, xBull, etc.)
  5. Customer clicks Pay and approves the transaction in their wallet
  6. Payoes submits the signed transaction to Horizon
  7. Payoes verifies the payment, records paid_asset, and shows a success state
No Payoes login is required for customers.

What Payoes handles

  • Building the unsigned Stellar payment transaction in the customer’s chosen paid asset
  • Setting the correct destination (merchant settlement wallet)
  • Attaching a payment memo for reconciliation
  • Trustline preflight checks before signing
  • Horizon submission and verification against the paid asset
  • Status updates and webhook delivery

Checkout API (internal)

The hosted page uses public endpoints under /api/checkout/{payment_id}:
MethodPurpose
GETLoad payment (settlement_asset, allowed_assets) and merchant details
POST { action: "build_transaction", sourcePublicKey, paid_asset }Build unsigned transaction XDR
POST { txHash }Confirm payment after wallet submission
These endpoints are used by the checkout UI. Integrations should use /api/v1/payments instead.

Custom checkout (future)

Embedded checkout and payment widgets are on the roadmap. Today, redirect customers to the hosted checkout_url.

Retry confirmation

If a transaction succeeds on Stellar but confirmation fails (e.g. temporary Horizon delay), the checkout page offers Retry payment confirmation with the submitted transaction hash.

Integration pattern

// 1. Create payment on your server (uses organization asset defaults when omitted)
const payment = await fetch("https://payoes.example.com/api/v1/payments", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAYOES_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: "25",
    settlement_asset: { asset_code: "USDC", issuer_address: "..." },
    allowed_assets: [
      { asset_code: "USDC", issuer_address: "..." },
      { asset_code: "XLM", issuer_address: null },
    ],
    description: "Pro plan (monthly)",
    metadata: { user_id: "usr_123" },
  }),
}).then((r) => r.json());

// 2. Redirect customer to checkout
return Response.redirect(payment.checkout_url);
After payment, listen for payment.completed webhooks or poll GET /api/v1/payments/{id}. Completed payments include both settlement_asset and paid_asset.