Skip to content

Payment Page

Each invoice has a public payment page that customers can use to complete their payment. No authentication is required.

Payment page URL

https://fincobra.com/pay/:id

Where :id is the invoice UUID returned when you create an invoice.

Payment page API

The payment page frontend fetches invoice data from a public endpoint:

GET /api/checkout/pay/:id

It then polls a lightweight status endpoint while the invoice is active:

GET /api/checkout/pay/:id/status

This endpoint requires no authentication and returns:

json
{
  "id": "a1b2c3d4-...",
  "amountUsd": 49.99,
  "status": "pending",
  "confirmations": 0,
  "productName": "Pro Plan - Monthly",
  "redirectUrl": "https://yoursite.com/thank-you",
  "paymentSummary": {
    "paymentState": "unpaid",
    "receivedAmount": 0,
    "remainingAmount": 49.99,
    "overpaidAmount": 0
  },
  "selectedPaymentOptionId": "payment-option-1",
  "paymentOptions": [
    {
      "id": "payment-option-1",
      "railType": "wallet_contract",
      "assetCode": "USDT",
      "network": "ethereum",
      "quotedAmount": 49.99,
      "quoteRate": 1,
      "destinationAddress": null,
      "paymentUri": null,
      "qrCode": null,
      "isDefault": true,
      "optionPayload": {
        "railType": "wallet_contract",
        "chainId": 1,
        "contractAddress": "0x...",
        "tokenContract": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
        "recipient": "0x1111111111111111111111111111111111111111",
        "decimals": 6,
        "requiredConfirmations": 14,
        "merchantIdHash": "0x...",
        "invoiceIdHash": "0x...",
        "paymentIdHash": "0x...",
        "paymentAmountAtomic": "49990000",
        "paymentCall": {
          "merchantId": "0x...",
          "invoiceId": "0x...",
          "paymentId": "0x...",
          "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
          "recipient": "0x1111111111111111111111111111111111111111",
          "amount": "49990000"
        }
      }
    }
  ],
  "payments": [],
  "paidAt": null,
  "confirmedAt": null,
  "paymentTiming": {
    "mode": "immediate",
    "expiresAfterMinutes": 20,
    "payableUntilAt": "2025-01-15T10:50:00.000Z"
  },
  "lastPaymentObservedAt": null
}

Features

The hosted payment page includes:

  • Rail-aware rendering — direct-transfer rails show amount, address, and QR; wallet rails show connect-wallet actions and the executable wallet-call payload
  • Invoice identity — optional billTo and issuedBy values appear on the hosted invoice when set
  • Timing-aware rendering — immediate invoices show a live countdown; due-date invoices show their due date instead
  • Copy buttons — one-click copy for the active address-transfer destination and amount
  • Real-time status — polls for payment updates and shows progress (partial payments, confirmations, exceptions)
  • Return navigation — customers can go back to the previous page in their browser without affecting the configured redirectUrl
  • Auto-redirect — when the payer-facing flow completes, the page redirects to the configured redirectUrl (if set). Deterministic address-transfer payments can redirect after on-chain receipt even though merchant withdrawal is a separate later action.

Linking customers to the page

You can link customers directly to the payment page:

html
<a href="https://fincobra.com/pay/a1b2c3d4-..."> Pay now </a>

The hosted page is intended to open directly in the browser. It is not designed for iframe embedding.

Polling behavior

The payment page loads GET /api/checkout/pay/:id once, then polls GET /api/checkout/pay/:id/status every few seconds while the invoice is pending or paid. Polling stops when the payer-facing flow is complete or the invoice reaches a terminal state (confirmed, expired, or underpaid).

Building a custom payment page

If you prefer a custom UI, use GET /api/checkout/pay/:id for the initial invoice payload and GET /api/checkout/pay/:id/status for polling.

For wallet-contract rails, after the payer transaction is mined you must also call:

POST /api/checkout/pay/:id/sync-wallet-payment

with:

json
{
  "paymentOptionId": "payment-option-1",
  "transactionHash": "0x..."
}

This records the on-chain PaymentAccepted event against the invoice so the hosted status and merchant views move forward correctly.

Public responses intentionally exclude operator-only fields such as reconciliation references, merchant withdrawal details, metadata, and exception resolution notes. Customer-facing invoice identity fields such as billTo and issuedBy remain part of the public payload.