Skip to content

The Payment Page

Overview

Every payment request generates a hosted payment page at:

https://app.tokencashflow.com/pay/{payment_id}

This page is fully managed by TokenCashFlow — no embedding or custom frontend work required. Simply redirect your customer to the pay_url returned from POST /v1/payments.

The page is:

  • Publicly accessible — no login required for the payer
  • Mobile-first — designed for smartphones
  • Real-time — status updates every 5 seconds

What the payer sees

1. Crypto selector (AWAITING_SELECTION)

The payer sees your enabled cryptos grouped by token. For each token available on multiple chains (e.g. USDT on Ethereum and USDT on Polygon), the chains are listed separately with an estimated network fee for each. The chain with the lowest estimated fee is highlighted with a "Recommended — Lowest fee" badge.

For each option the payer sees:

  • Token symbol and name
  • Logo
  • Approximate USD equivalent of the required amount at the current live rate
  • Estimated network fee (refreshed every 30 seconds; approximate only)

2. Rate lock (AWAITING_PAYMENT)

After selecting a crypto, the payer sees:

  • The current exchange rate (e.g. 1 ETH = $2,000.00)
  • The exact crypto amount they must send (e.g. You will send: 0.075000 ETH)
  • A Confirm and Pay button

Clicking Confirm locks the rate. The exact amount displayed is final for the duration of the chain selection window. A countdown timer starts at this point, tracking selection_expires_at.

3. Payment instructions (AWAITING_PAYMENTPARTIALLY_PAIDCONFIRMING)

After rate lock the payer sees:

  • The payment wallet address (text + QR code)
  • The exact amount in crypto
  • The expiry countdown timer
  • Deep-link buttons: Open in MetaMask (EIP-681 URI) and Open in Wallet (for mobile wallets)
  • Live status banner updating in real time

Rate locking

The rate is fixed when the payer clicks "Confirm and Pay". The locked rate is stored in the payment record. The exact crypto amount is calculated at lock time:

required_crypto_amount = amount_usd / locked_rate_usd

(adjusted if fee_payer = payer — see your account's payment settings)

The rate is valid until the chain selection window expires (selection_expires_at). This window is set per-chain by the platform (chain.payment_expiry_minutes). The countdown timer on the payment page tracks this window — not a global payment expiry.

Payments never expire. A payer can always return to the payment link. Only the chain selection (rate lock window) expires. If it expires, the payer can reselect a token and get a new rate.

Selection expiry and reselection

When the chain selection window (selection_expires_at) passes:

  • If no transaction is in progress → status becomes EXPIRED_SELECTION
  • The payer can return to the payment page at any time and reselect a token (same or different) with the current market rate
  • A new selection window starts on reselection
  • If a transaction is already being confirmed, the expiry is held until the transaction resolves

The amber banner on the payment page reads:
"Your previous selection expired. Please select a payment method to continue."

Partial payments

If the payer sends less than the required amount:

  1. The page updates automatically to show:
    "Partial payment received: 0.030 ETH. Remaining: 0.045 ETH (~$90.00 USD)"
  2. The payer can top up the remaining amount to the same wallet address before selection_expires_at
  3. The remaining amount in crypto is calculated using the locked rate (not the current market rate)

If the chain selection window expires while in PARTIALLY_PAID state (and no unconfirmed tx):

  • Status transitions to EXPIRED_SELECTION
  • The payer must reselect to continue — a new rate is applied to the remaining USD amount
  • Previously received funds are counted; only the remaining gap is recalculated at the new rate
  • The page shows: "Selection expired — $XX.XX USD remaining. Reselect to pay at the current rate."

Partially paid payments are never permanently closed by expiry — the payer can always complete them.

Overpayments

If the payer sends more than the required amount:

  • The payment proceeds to CONFIRMINGCOMPLETED as normal
  • The excess crypto is absorbed by the platform — no refund is issued
  • You are credited for the original amount_usd only, not the excess
  • A notice on the payment page informs the payer: "Overpayment is non-refundable"

Redirect after completion

When the payment reaches COMPLETED:

  1. The payer sees a success screen
  2. If you set a redirect_url when creating the payment, a 3-second countdown appears: "Redirecting in 3..."
  3. The payer is then redirected to your URL

Your redirect URL receives no extra query parameters from TokenCashFlow by default. Use the webhook payment.completed event to update your system, not the redirect.

Payer support

Payers can click "Having issues? Contact support" on any payment page to open a support ticket without logging in. They must provide their email address so the admin team can reply.

Page states reference

Payment statusPage display
AWAITING_SELECTIONCrypto selector; amount; description (no countdown yet)
AWAITING_PAYMENTWallet address; QR code; exact crypto amount; selection_expires_at countdown
PARTIALLY_PAIDRemaining amount (~USD); wallet address; QR code; selection_expires_at countdown
EXPIRED_SELECTION (no prior payment)Amber banner: "Your previous selection expired — please reselect"; crypto selector
EXPIRED_SELECTION (partial payment)Amber banner with remaining USD; crypto selector
CONFIRMING"Payment received — confirming on blockchain"; progress indicator
COMPLETEDSuccess state; redirect if configured
BLACKLISTED"Payment cannot be processed" (generic — blacklist reason not revealed)
FAILEDGeneric error message

TokenCashFlow Documentation