Accepting payments

Payments.

A payment is one customer's attempt to pay a link. Axle tracks it from creation to on-chain confirmation, and you read it with your API key.

Retrieve a payment

request
GET /v1/payments/:id
Authorization: Bearer sk_test_...
curl
curl https://axle-production-fa2b.up.railway.app/v1/payments/<paymentId> \
  -H "Authorization: Bearer $AXLE_API_KEY"
response 200
{
  "object": "payment",
  "id": "9d94…",
  "method": "crypto",
  "status": "success",
  "amountMinor": 4900,
  "currency": "USD",
  "customerEmail": "customer@example.com",
  "customerName": null,
  "failureReason": null,
  "livemode": true,
  "createdAt": "2026-09-17T10:02:11.000Z",
  "updatedAt": "2026-09-17T10:06:40.000Z",
  "crypto": {
    "provider": "direct-wallet",
    "payCurrency": "USDC",
    "payAddress": "0x71C7…976F",
    "payAmount": 49.02,
    "actualAmountReceived": 49.02,
    "txHash": "0xabc1…",
    "confirmations": 12,
    "status": "finished",
    "rateLockedUntil": "2026-09-17T10:22:11.000Z"
  }
}

An unknown ID, or one belonging to a different merchant, returns 404 transaction_not_found.

Key fields

FieldMeaning
amountMinorThe price in your currency's minor units. currency is the fiat code (USD).
crypto.payCurrencyWhat the customer actually pays in: ETH, USDC or USDT.
crypto.payAddressYour wallet, where the funds were sent.
crypto.payAmountThe crypto amount quoted, as a high-precision decimal (not minor units).
crypto.actualAmountReceivedThe amount observed on-chain. null until the payment is confirmed.
crypto.txHashThe transaction hash. Look it up on a block explorer to verify independently.
crypto.confirmationsConfirmations seen so far.
livemodeWhether this belongs to a live or test key environment.

Status lifecycle

A payment is created pending the moment checkout issues the quote, and stays pending while it waits for the customer's transaction and while confirmations accrue. It then ends in one terminal state:

happy path
pending → success
StatusMeaning
pendingAwaiting the customer's transaction, or waiting on confirmations. Track progress with crypto.status and crypto.confirmations.
successVerified on-chain: right recipient, right amount, enough confirmations. Final, and safe to fulfil.
failedThe on-chain transaction reverted or didn't match the expected currency. See failureReason.
canceledCanceled by the merchant while still pending. A customer can't cancel their own payment.
partially_refundedA successful payment that has been partly refunded. Some balance remains.
refundedFully refunded. See Refunds.

The status enum also contains created, processing and expired. Direct-wallet payments don't use them today, so don't build logic that depends on seeing them.

Confirmation progress: crypto.status

crypto.statusMeaning
waitingQuote issued; no transaction submitted yet.
confirmingA transaction hash has been submitted and is being verified; confirmations are accruing.
finishedVerified. The payment moves to success.
failedThe on-chain transaction failed.
expiredThe payment was canceled by the merchant.

How Axle verifies a payment

Axle never takes the customer's word for it. For every submitted transaction it reads the chain itself:

  • The transaction actually paid your connected wallet address.
  • For tokens, the transfer is emitted by the real token contract (USDC/USDT), read from the contract's Transfer event, not the transaction's own fields.
  • The amount is at least the quote. A payment up to 0.5% short is accepted to absorb rounding; anything further short is left pending rather than failed, in case it's a transient read problem. A payment more than 1% over still succeeds and is noted in the receipt.
  • It has enough confirmations: 12 on Ethereum mainnet, 3 on Sepolia.
  • The transaction hash hasn't already been used for a different payment (enforced by a database constraint).

RPC reads fail over across several providers, and every read is retried, so a single provider outage doesn't stall verification.