Skip to main content

CROSS Pay API

Version 0.9.9

CROSS Pay v1 REST API. Merchant servers create a PaymentIntent and drive its lifecycle from a server-to-server context using the merchant API key.

Try it out on this site is proxied through the sandbox (/v1) with the sandbox API key injected server-side. Production keys are never exposed to the browser.

Download the spec

Import the full spec into Postman, an SDK generator, or your IDE. It covers exactly the merchant server endpoints documented on this page:

Authentication

All /payments/** endpoints and GET /catalog require a merchant API key (Authorization: Bearer <API_KEY>). The buyer-facing hosted checkout, on-chain session lookups for wallet clients, the public countries / chains lookups, and provider-side webhooks are consumed by the CROSS Pay hosted checkout, wallet SDKs, and the platform itself — they are not part of this merchant integration reference.

Environment

CROSS Pay currently exposes the Production environment (https://api.crosspay.io): a 53-country catalog, chain slugs ethereum / bsc / cross, crypto currencies USDT / CROSSD, and an API key prefix of sk_live_….

A public Sandbox environment (with self-serve test keys, test cards, and test tokens) is planned for an upcoming release.

See the Supported Countries & Payment Method Catalog for the full per-country mapping.

PaymentStatus overview

StatusMeaning / entry path
PENDINGRight after POST /payments. No quote selected yet.
PROCESSINGAfter the buyer selects a payment method on the hosted checkout. The external PG-handoff window — waiting for the PG/chain terminating webhook (PAID/FAILED) or the expiry worker (EXPIRED).
PAID / FAILEDA PG/chain webhook terminates PROCESSING. Terminal.
EXPIREDTTL expiry worker. Reachable from both PENDING and PROCESSING. Terminal.
CANCELLEDMerchant cancel call or a buyer-cancel webhook. Reachable only from PENDING — a PROCESSING cancel is rejected with 409 INVALID_PAYMENT_STATE due to the PG race. Terminal.
PARTIALLY_REFUNDED / REFUNDEDRefund results. Reached from PAID. Terminal.

PENDING → PAID/FAILED direct transitions are no longer allowed. Every webhook-driven terminal transition passes through PROCESSING. For the full state machine and webhook mapping, see the Webhooks Overview.

Recent changes

  • New PG: MyCard (v0.9.9, additive): the TW/HK/SEA fiat hosted-page PG MyCard was added to the PG registry. There is no buyer-facing wire-shape change — only the value mycard was added to the provider enum on Payment, and payments handled by MyCard report provider as mycard. The MyCard ops callbacks are outside this merchant reference (webhook group).
  • GET /catalog now requires authentication (v0.9.3, BREAKING): the formerly public (no-auth) catalog now requires a Merchant API Key. Calling it without Authorization: Bearer <API_KEY> returns 401. Cache-Control also changed from public to private so shared caches (CDN/proxy) do not store it. ETag / If-None-Match 304 revalidation is unchanged.
  • GET /catalog per-merchant scoping (v0.9.5): the catalog is filtered per authenticated merchant — it exposes only the currencies payable through the merchant's provisioned payment methods (merchant_payment_method) and omits countries with nothing payable. The response wire shape is unchanged; only the returned set narrows. The ETag now derives from per-merchant freshness.
  • include_pegged_assets now defaults to true (v0.7.55, BREAKING): POST /payments flips the opt-in flag introduced in v0.7.51 to opt-out. A fiat-currency payment created without the flag now also exposes stablecoins pegged to that fiat (USDT / USDC / …) as payment options on the hosted checkout. Merchants that must keep stablecoins hidden have to send an explicit include_pegged_assets: false. No other wire-shape or DB change. See the field description on CreatePaymentRequest for before/after behaviour.
  • Added GET /catalog (v0.7.55, additive): returns, per supported country, the currencies/assets payable through the calling merchant's provisioned payment methods, with the display decimals of each. Served from a cache with ETag / If-None-Match revalidation.
  • Country-level crypto restrictions (v0.7.55): an admin-managed restriction list (types CRYPTO / ONRAMP) now governs where crypto payment is offered. Checkout quotes hide crypto payment methods when the buyer's IP-resolved country (CloudFront-Viewer-Country — authoritative, not client-supplied) carries a CRYPTO restriction, and GET /catalog excludes crypto currencies for those countries. Response field structures are unchanged — only the returned sets narrow. The former on-ramp country_blacklist config (default KR) migrated into this list as ONRAMP rows.
  • Added PROCESSING status (v0.7.34, additive): PROCESSING was added to the PaymentStatus enum. The PG webhook terminates PROCESSING → PAID/FAILED. Existing clients keep working, but consumers that branch on status without a default / unknown path must explicitly handle PROCESSING (showing a "PG processing — awaiting result" state is recommended).
  • Re-opened POST /payments/{payment_id}/cancel (v0.7.34): the cancel route removed in v0.7.27 is exposed again to merchants with the same wire format. Cancelling a PROCESSING payment returns 409 INVALID_PAYMENT_STATE — done to avoid a race against the PG. Cancel only while PENDING, or wait for a terminal result and use the refund API.
  • POST /payments: the optional country field is only forwarded to the checkout URL as a ?country=XX hint and is not persisted to the database.

Authentication

MerchantApiKeyhttp (bearer)

Merchant API Key

Contact

Cross Pay Team