Core concepts

Payment intents

Payment intents are the core collection resource. You create an intent, share checkout details, then consume lifecycle updates.

Lifecycle

  • Create an intent with a token amount, chain, token, and optional metadata.
  • Display the returned deposit address or hosted checkout URL to the payer.
  • Track deposit progress with deposit_status: none, detected, pending_confirmation, or confirmed.
  • Use merchant-visible status values PENDING, EXPIRED, and COMPLETED.
  • Receive lifecycle updates via webhooks.

Create an intent

POST/v1/payment-intentsCreate payment intent

Required payload keys

FieldTypeDescription
amountrequiredstringDecimal amount in token units. Must be > 0 and within token precision.
chainrequiredstringCanonical deposit chain (for example ethereum).
tokenrequiredstringCanonical deposit token (for example USDC).

Customer identity (`customer_id`)

Pass a stable merchant-defined customer key as the top-level customer_id field (not only inside metadata). The API echoes it on the payment intent and uses it for deposit routing and reporting.

  • Required when your merchant deposit_identity_mode is IDENTITY_BASED (all chains).
  • Tron: with customer_id and mode IDENTITY_BASED or HYBRID, deposits use a persistent per-customer address (same customer_id reuses the same Tron deposit address for that chain/token). Integrations collecting on Tron should always send customer_id when using those modes.
  • HYBRID without customer_id may allocate a shared hot-wallet pool address (when enabled) instead of a dedicated customer wallet.
  • Max length 256 characters. Configure defaults via GET|PUT /v1/merchant/deposit-rules-default.

Do not rely on metadata alone

Putting customer_id only inside metadata does not drive deposit identity routing. Use the top-level field.

Optional payload keys, enums, and defaults

FieldTypeDescription
customer_idstringStable merchant customer key. Required when deposit_identity_mode is IDENTITY_BASED; required for Tron persistent wallets in IDENTITY_BASED/HYBRID.
metadataobjectDefault: {}. Merchant-defined non-financial metadata echoed in responses/webhooks.
purposemerchant_payment | invoice_paymentDefault: merchant_payment. Use invoice_payment for fixed invoices that must be paid in full before completion while the checkout window is open; partial confirmed inbound may settle after expiry.
funding_acceptance_modeOPEN_AMOUNT | TARGET_WITH_TOLERANCE | EXACTDefault: EXACT. Controls how inbound deposit amounts are accepted. Ignored for invoice_payment (always EXACT).
target_settlement_amountstringDefault: amount. Settlement target in token units.
allowed_deviation_typeABSOLUTE | PERCENTAGENo default. Must be sent with allowed_deviation_value when using deviation.
allowed_deviation_valuestringNo default. Positive decimal. Required when allowed_deviation_type is set.
allow_partial_fundingbooleanDefault: false (true for invoice_payment). Allows multiple confirmed deposits to accumulate before routing.
allow_overpaymentbooleanDefault: false. Whether inbound amount above maximum policy bound is accepted.
overpayment_handlingCREDIT_EXCESS | REJECT_EXCESSDefault: REJECT_EXCESS. Controls behavior when overpayment is accepted.
settlement_recipient_typeMERCHANT | CUSTOMEROptional override. Rejected when it conflicts with merchant type policy.
beneficiary_detailsobjectRequired when settlement_recipient_type resolves to CUSTOMER; must be provider-resolved before create.

Funding acceptance mode rules

  • EXACT (default): fixed amount acceptance behavior.
  • TARGET_WITH_TOLERANCE: requires both allowed_deviation_type and allowed_deviation_value.
  • OPEN_AMOUNT: variable amount flow, commonly paired with partial/overpayment allowances.

Invoice payments (invoice_payment)

Set purpose to invoice_payment when collecting a fixed invoice amount. Xpend applies stricter rules than a generic merchant_payment with manual funding flags.

  • While open: cumulative confirmed inbound must reach the exact quoted amount (no downward tolerance). Multiple deposits are allowed and sum toward the target.
  • Before full payment: status stays PENDING, payment_intent.completed does not fire, and routing is blocked (funding_status.acceptance_state may show SHORTFALL).
  • After expiry: if the customer paid only part of the invoice, Xpend settles the confirmed partial amount and the intent can complete with whatever was received.

Policy locked at create

For invoice_payment, Xpend sets funding_acceptance_mode to EXACT, enables allow_partial_funding, and uses zero downward deviation regardless of other funding fields you send.

Validation coupling

If either allowed_deviation_type or allowed_deviation_value is provided, the other must also be provided.
curl "$XPEND_BASE_URL/v1/payment-intents" \
  -H "Authorization: Bearer $XPEND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_8421" \
  -d '{
    "amount": "150.00",
    "chain": "ethereum",
    "token": "USDC",
    "metadata": {
      "order_id": "order_8421"
    }
  }'

Important response fields

FieldTypeDescription
payment_intent_idrequiredstringXpend payment intent identifier. Store this on your order.
customer_idstringEchoed when set at creation (top-level field).
deposit_addressrequiredstringAddress the payer should fund on the requested chain/token route.
statusrequiredPENDING | EXPIRED | COMPLETEDMerchant-visible lifecycle state.
deposit_statusrequirednone | detected | pending_confirmation | confirmedOn-chain deposit progress.
transaction_hashstringBest-known funding/settlement transaction hash or signature when available.
checkout_urlstringHosted checkout URL when available.
metadatarequiredobjectMerchant metadata echoed from creation.

Read/list intents

GET/v1/payment-intentsList payment intents
GET/v1/payment-intents/{id}Get payment intent by ID
GET/v1/payment-intents/settlement-summarySummarized settlement totals

Funding status on GET

GET /v1/payment-intents/{id} may include funding_status with cumulative funded_amount, acceptance_state (SHORTFALL, WITHIN_POLICY, COMPLETED, etc.), and policy hints. For invoice payments, poll this field or use webhooks while waiting for the customer to finish paying.

Recommended integration pattern

  • Persist the returned payment intent ID in your order record.
  • Redirect users to hosted checkout when checkout_url is present, or render the returned deposit address.
  • Use payment_intent.completed for fulfillment decisions.
  • Use list/get endpoints for operator dashboards and support tooling.

Avoid polling loops

Polling /v1/payment-intents/{id} aggressively is unnecessary. Use webhooks for state transitions and occasional reads for UI refresh.

See full endpoint details in /business/reference/payment-intents.