Browse docs
API reference

Payments

Accept cards and wallets through one unified entry point, or hand card entry to the hosted checkout page. Results arrive as signed notifications.

Methods & modes

payment_methodDirect (/payments/create)Checkout (/payments/checkout)
CARDYes — you collect card detailsYes — customer enters card on the hosted page
APPLE_PAYYes — redirect to pay_urlNot recommended
GOOGLE_PAYYes — redirect to pay_urlNot recommended
CASH_APPYes — redirect to pay_urlNot recommended
PAYPALYes — redirect to pay_urlNot recommended

Direct payments post everything in one call. For wallets you then redirect the customer to the returned pay_url. Checkout payments return a checkout_url where the customer enters their card.

Direct card payments put card data on your servers
Sending card.card_number and card.cvc through your backend brings your systems into PCI DSS scope. Unless you already operate a PCI-validated environment, use Checkout for cards — no card data touches your infrastructure.

Create a payment

POST/api/v1/payments/create

The unified entry point. StablePay routes the request according to payment_method. These fields apply to every method:

FieldTypeRequiredDescription
payment_methodstringYesOne of CARD, CASH_APP, PAYPAL, APPLE_PAY, GOOGLE_PAY. Routes the request.
merchant_order_nostringYesYour order number. Unique on your side; used for idempotency.
trans_amount.currencystringYes3-letter uppercase currency, e.g. USD.
trans_amount.valuestringYesAmount as a decimal string, e.g. 99.99.
notify_urlstringYesURL that receives the signed result notification.
return_urlstringNoWhere the customer's browser returns after payment.
trade_info.goods_namestringYesProduct name.
trade_info.descriptionstringNoProduct description.
metadatastringNoOpaque passthrough, returned unchanged in notifications.
client_ipstringNoClient IP as recorded by your server.

Direct card payment

When payment_method=CARD, add the card, billing address, device IP, and optionally browser details for risk screening.

FieldTypeRequiredDescription
payer.emailstringNoPayer email.
payer.mobilestringNoPayer mobile number.
payer.user_namestringNoPayer name.
payer.user_agentstringNoPayer browser user agent.
payer.ext_typestringNoMethod-specific extra field.
payer.payer_idstringNoWallet-side payer identifier.
card.card_numberstringYesPrimary account number, digits only.
card.cardholder_namestringYesName as printed on the card.
card.exp_monthintYesExpiry month, 1–12.
card.exp_yearintYesExpiry year, 4 digits.
card.cvcstringYesCVV / CVC.
billing_address.countrystringYes2-letter country code, e.g. US.
billing_address.first_namestringNoFirst name.
billing_address.last_namestringNoLast name.
billing_address.emailstringNoEmail.
billing_address.phonestringNoPhone.
billing_address.statestringNoState / province.
billing_address.citystringNoCity.
billing_address.addressstringNoStreet address.
billing_address.street_numberstringNoStreet number.
billing_address.postal_codestringNoPostal code.
billing_address.documentstringNoLocal document ID where required.
shipping_address.*objectNoSame shape as billing_address. If provided, full shipping-address validation applies.
device_ipstringYesPublic IP of the customer's device.
browser.acceptstringNoBrowser Accept header.
browser.user_agentstringNoBrowser user agent.
browser.accept_languagestringNoBrowser language.
browser.java_enabledboolNoWhether Java is enabled.
browser.color_depthstringNoScreen color depth.
browser.screen_heightstringNoScreen height.
browser.screen_widthstringNoScreen width.
browser.time_zone_offsetstringNoTimezone offset in minutes.
browser.refererstringNoReferer.
{
  "payment_method": "CARD",
  "merchant_order_no": "M202606240001",
  "trans_amount": {
    "currency": "USD",
    "value": "99.99"
  },
  "notify_url": "https://merchant.example.com/callback/payment",
  "return_url": "https://merchant.example.com/pay/success",
  "trade_info": {
    "goods_name": "VIP Membership",
    "description": "Monthly subscription"
  },
  "metadata": "biz=member&uid=10001",
  "card": {
    "card_number": "4111111111111111",
    "cardholder_name": "JOHN DOE",
    "exp_month": 12,
    "exp_year": 2028,
    "cvc": "123"
  },
  "billing_address": {
    "country": "US",
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "phone": "15551234567",
    "state": "CA",
    "city": "San Francisco",
    "address": "Market Street",
    "street_number": "1355",
    "postal_code": "94103"
  },
  "device_ip": "203.0.113.10",
  "client_ip": "203.0.113.10"
}

Direct wallet payment

For CASH_APP, PAYPAL, APPLE_PAY and GOOGLE_PAY, the only additional fields are the optional payer details. Wallet payments do not use the checkout flow.

FieldTypeRequiredDescription
payer.emailstringNoPayer email.
payer.mobilestringNoPayer mobile number.
payer.user_namestringNoPayer name.
payer.user_agentstringNoPayer browser user agent.
payer.ext_typestringNoMethod-specific extra field.
payer.payer_idstringNoWallet-side payer identifier.
{
  "payment_method": "PAYPAL",
  "merchant_order_no": "M202606240003",
  "trans_amount": {
    "currency": "USD",
    "value": "49.99"
  },
  "notify_url": "https://merchant.example.com/callback/payment",
  "return_url": "https://merchant.example.com/pay/success",
  "trade_info": {
    "goods_name": "Gift Card",
    "description": "PayPal checkout"
  },
  "metadata": "src=paypal",
  "payer": {
    "email": "buyer@example.com",
    "payer_id": "PAYER123456"
  },
  "client_ip": "203.0.113.10"
}

Response

FieldTypeDescription
payment_methodstringPayment method.
order_nostringStablePay order number.
merchant_order_nostringYour order number.
statusstringPENDING, SUCCESS or FAILED.
trans_amountobjectAmount and currency.
psp_order_nostringStablePay processing reference; may be empty.
next_actionstringREDIRECT, SUCCESS or FAILED.
pay_urlstringWallet redirect URL. Present when next_action is REDIRECT.
created_atstringRFC 3339 creation time.
200 · response
{
  "code": 0,
  "msg": "success",
  "data": {
    "payment_method": "PAYPAL",
    "order_no": "O202606240003",
    "merchant_order_no": "M202606240003",
    "status": "PENDING",
    "trans_amount": {
      "currency": "USD",
      "value": "49.99"
    },
    "psp_order_no": "SPR_PP_123456",
    "next_action": "REDIRECT",
    "pay_url": "https://wallet.example.com/redirect/pay_abc123",
    "created_at": "2026-06-24T10:03:00Z"
  }
}
  • When next_action is REDIRECT, send the customer to pay_url immediately.
  • When it is SUCCESS (possible for direct card payments), the charge is already complete — but keep handling the notification as the final record.
  • code=2006 means the amount is outside the current amount limits — see amount limits.

Checkout payment

POST/api/v1/payments/checkout

Creates a pending card order and returns a hosted checkout page. Compared with a direct payment there is no card, no billing_address and no device_ip — the customer enters those on the checkout page. Checkout currently supports payment_method=CARD only; use the direct endpoint for wallets.

FieldTypeRequiredDescription
payment_methodstringYesMust be CARD.
merchant_order_nostringYesYour order number. Unique; used for idempotency.
trans_amountobjectYescurrency and value, as above.
notify_urlstringYesURL that receives the signed result notification.
return_urlstringNoWhere the customer returns after payment.
trade_infoobjectYesgoods_name (required) and description.
metadatastringNoOpaque passthrough.
payerobjectNoPayer information (same fields as direct payments).
client_ipstringNoClient IP.
{
  "payment_method": "CARD",
  "merchant_order_no": "M202606240002",
  "trans_amount": {
    "currency": "USD",
    "value": "49.99"
  },
  "notify_url": "https://merchant.example.com/callback/payment",
  "return_url": "https://merchant.example.com/pay/success",
  "trade_info": {
    "goods_name": "VIP Membership",
    "description": "Monthly subscription"
  },
  "metadata": "biz=member&uid=10001",
  "payer": {
    "email": "buyer@example.com"
  },
  "client_ip": "203.0.113.10"
}
FieldTypeDescription
payment_methodstringAlways CARD.
order_nostringStablePay order number.
merchant_order_nostringYour order number.
statusstringInitially PENDING.
trans_amountobjectAmount and currency.
psp_order_nostringStablePay processing reference; empty until the customer pays.
next_actionstringCHECKOUT_REQUIRED — redirect the customer.
tokenstringCheckout token.
checkout_urlstringHosted checkout page URL.
created_atstringRFC 3339 creation time.
200 · response
{
  "code": 0,
  "msg": "success",
  "data": {
    "payment_method": "CARD",
    "order_no": "O202606240002",
    "merchant_order_no": "M202606240002",
    "status": "PENDING",
    "trans_amount": {
      "currency": "USD",
      "value": "49.99"
    },
    "psp_order_no": "",
    "next_action": "CHECKOUT_REQUIRED",
    "token": "ck_5c4f0f53c0e94d11",
    "checkout_url": "https://cashier.example.com/pay/ck_5c4f0f53c0e94d11",
    "created_at": "2026-06-24T10:05:00Z"
  }
}

Redirect the customer to checkout_url. After payment they return to return_url and the result is posted to notify_url.

Query a payment

POST/api/v1/payments/query

Provide exactly one identifier.

FieldTypeRequiredDescription
order_nostringOne of twoStablePay order number.
merchant_order_nostringOne of twoYour order number.
{
  "merchant_order_no": "M202606240001"
}
FieldTypeDescription
payment_methodstringPayment method.
order_nostringStablePay order number.
merchant_order_nostringYour order number.
statusstringPENDING, SUCCESS or FAILED.
trans_amountobjectAmount and currency.
paid_atstringPayment completion time.
created_atstringCreation time.
psp_order_nostringStablePay processing reference.
masked_card_numberstringe.g. 411111******1111. Usually empty for wallets.
trade_infoobjectProduct information as submitted.
metadatastringYour passthrough value.
200 · response
{
  "code": 0,
  "msg": "success",
  "data": {
    "payment_method": "CARD",
    "order_no": "O202606240001",
    "merchant_order_no": "M202606240001",
    "status": "SUCCESS",
    "trans_amount": {
      "currency": "USD",
      "value": "99.99"
    },
    "paid_at": "2026-06-24T10:01:23Z",
    "created_at": "2026-06-24T10:00:00Z",
    "psp_order_no": "SPR_123456",
    "masked_card_number": "411111******1111",
    "trade_info": {
      "goods_name": "VIP Membership",
      "description": "Monthly subscription"
    },
    "metadata": "biz=member&uid=10001"
  }
}
Query is for reconciliation
Notifications are the source of truth for status changes. Use query to reconcile, to recover after downtime, or when a notification has not arrived in the expected window.