Payments
Payment Intents
A payment intent is the single object for collecting money: it describes what the customer owes, where it settles, and — once verified on chain — how it was paid.
One resource
A payment intent is the payment./v1/payment-intents lists every checkout you created; /v1/payments lists the same objects filtered to those with an on-chain attempt (submitted, confirmed, finalized, failed, refunded). There is no separate "payment" record to reconcile.Create parameters#
| Field | Type | Description |
|---|---|---|
amount | decimal string | Whole MUNY, e.g. "249" or "12.5". Required unless line_items is given. Never a JSON number. |
line_items | array | Alternative to amount: name, quantity, unit_amount. The total is computed exactly server-side. |
token | "MUNY" | V1 accepts MUNY. The model is ready for USDC, SOL and other approved SPL tokens. |
reference | string | Your order reference. Shown on checkout, searchable, included in webhooks. |
external_order_id | string | Optional second identifier from your system. |
description | string | Shown to the customer on checkout. |
customer | object | { email, name } — prefills the payment record. |
collect_email / collect_name | boolean | Ask the customer on checkout before they pay. |
metadata | object | Up to 20 string pairs for your own use. Never shown to the customer. |
success_url / cancel_url | https URL | Where checkout sends the customer. Defaults come from Payments settings. |
display_amount / display_currency | string | A price you show elsewhere (e.g. 29.99 USD). Informational only. |
expires_in_minutes | integer | 5–10,080. Defaults to your merchant setting (30). |
wallet_id | uuid | Settle into a specific wallet instead of your default receiving wallet. |
idempotency_key | string | Required (or the Idempotency-Key header). Same key + same body returns the same payment. |
Line items, customer and metadata
const payment = await muny.paymentIntents.create({
line_items: [
{ name: "Pro Plan", quantity: 1, unit_amount: "249" },
{ name: "Extra seat", quantity: 2, unit_amount: "40" },
],
token: "MUNY",
reference: "ORDER-48291",
customer: { email: "customer@example.com" },
metadata: { plan: "pro", user_id: "12345" },
display_amount: "39.48",
display_currency: "USD",
expires_in_minutes: 60,
});
// payment.amount === "329"The object#
| Field | Description |
|---|---|
status | See the lifecycle below. |
amount, amount_refunded, token, token_mint | What is owed, what has been refunded, and the exact SPL mint. |
recipient_address, wallet_id | The settlement wallet, fixed at creation. Changing settings later never redirects an open payment. |
checkout_url | Hosted checkout: /pay/{id}. |
solana_pay_url, reference_key | Solana Pay transfer request and the unique reference key Muny uses to find the payment. |
payer_address, transaction_signature, explorer_url, transaction | Filled from on-chain verification, never from the client. |
fiat_value_at_payment | { amount, currency, price, source } snapshot taken when the payment confirmed. Historic reports never use today's price. |
late_confirmation | True when a valid payment arrived after expires_at. The funds are real, so the payment is recorded. |
risk_decision | allow | review | deny from compliance/risk providers at settlement. |
refunds | Refunds of this payment (on retrieve). |
livemode, network | Test (devnet) and live (mainnet) records never mix. |
Lifecycle#
status
requires_payment ──► pending ──► submitted ──► confirmed ──► finalized
│ │ │ │ │
│ │ │ └──► partially_refunded ──► refunded
├──► cancelled ├──► cancelled│
└──► expired ◄──┴─────────────┘ (a late, valid payment still moves expired ──► confirmed)
failed (underpaid / overpaid transfer carrying this reference)| Status | Meaning |
|---|---|
requires_payment | Created; waiting for the customer. |
pending | The customer connected a wallet and Muny built the transaction. |
submitted | A signature was reported or seen. Not proof of payment. |
confirmed | Verified on chain at confirmed commitment. Safe to fulfil for most goods. |
finalized | Reached finalized commitment — irreversible. |
expired | No valid payment before expires_at. Muny keeps watching the reference for 24 h for late payments. |
cancelled | Cancelled by you before any payment was in flight. |
failed | A transfer carrying this payment's reference was underpaid or overpaid. Review and refund. |
partially_refunded / refunded | After refunds confirm on chain. |
List, search and cancel#
ts
// Search by payment id, transaction signature, reference or customer email
const { data } = await muny.paymentIntents.list({ q: "ORDER-48291" });
// Only payments that saw an on-chain attempt
const paid = await muny.payments.list({ status: "confirmed", created_gte: "2026-09-01T00:00:00Z" });
// Iterate everything
for await (const p of muny.paymentIntents.listAll({ status: "expired" })) console.log(p.id);
await muny.paymentIntents.cancel(payment.id); // only while requires_payment / pendingCheckout sessions
POST /v1/checkout/sessions is a thin wrapper for cart-style integrations: pass line_items and it returns a payment intent whose description lists the items.
ts
// Equivalent convenience endpoint: POST /v1/checkout/sessions
const payment = await muny.checkout.sessions.create({
line_items: [{ name: "Pro Plan", quantity: 1, unit_amount: "249" }],
token: "MUNY",
success_url: "https://shop.example/thanks",
cancel_url: "https://shop.example/cart",
});
redirect(payment.checkout_url);Endpoints#
POST /v1/payment-intents·GET /v1/payment-intents·GET /v1/payment-intents/:id·POST /v1/payment-intents/:id/cancelGET /v1/payments·GET /v1/payments/:id·GET /v1/payments/:id/events(webhook deliveries) ·GET /v1/payments/analyticsPOST /v1/checkout/sessions
Required scopes: create_payments to create/cancel, view_payments to read. See the API keys guide.