Getting Started
Two calls: start Light KYC with the buyer’s identity, then create a payment and redirect to hosted checkout. Phone, address and birthdate belong on KYC start only.
API Access
Create a sandbox key (sdk_…) in the merchant portal after registration. Live keys (pk_…) activate after KYB approval.
https://stixpay.com
Send X-API-Key on every request. Environment comes from the key prefix — do not send a sandbox body flag.
| Key | Use |
|---|---|
sdk_… | Test — KYC auto-approved, Test Gateway only |
pk_… | Live — production KYC + providers |
secret_… | Webhook signing only (not an API key) |
Try it in the API Console. Full schema: openapi.yaml.
How a payment works
-
1
POST /api/kyc/start— create the customer and start Light KYC (auto-approved withsdk_…). -
2
POST /api/payment/create— samecustomer_email+ payment fields. Receiveredirect_url. -
3
Redirect the buyer to
redirect_url(hosted checkout). -
4
Listen for
payment.succeeded/payment.failed/payment.reversed, or pollGET /api/payment/{payment_id}/status.
KYC is per customer (shared across merchants) and must be approved on the same key plane (sandbox vs live). Without Light KYC approved, create payment returns HTTP 422 kyc_required. Sandbox KYC does not affect the live profile.
1 — Start KYC
Creates the StixPay customer if needed and starts Light KYC. Send all identity fields here.
Body
| Field | Description |
|---|---|
customer_email | Buyer email |
customer_first_name | First name |
customer_lastname | Last name |
customer_phone | E.164, e.g. +33611223344 |
birthdate | YYYY-MM-DD |
customer_address | Street address |
postal_code | Postal / ZIP |
city | City |
country | ISO alpha-2, e.g. FR, US, CA. USA → US, CAN → CA. |
customer_state | Required when country is US, CA, AU, or MX (on-ramp rails need province or state). Subdivision code — US: CA, NY · CA: ON, MB, QC · AU: NSW, VIC · MX: 2–3 letter code. Also accepts ISO 3166-2 (CA-MB, US-CA, AU-NSW). Aliases: state, state_of_residence. |
level | light |
Request
POST /api/kyc/start
Content-Type: application/json
X-API-Key: sdk_your_test_key
{
"customer_email": "[email protected]",
"customer_first_name": "Jane",
"customer_lastname": "Doe",
"customer_phone": "+33611223344",
"birthdate": "1990-01-15",
"customer_address": "1 rue de Rivoli",
"postal_code": "75001",
"city": "Paris",
"country": "FR",
"level": "light"
}
Response (sandbox)
HTTP 200
{
"success": true,
"already_approved": true,
"customer_user_id": 1842,
"customer_created": true,
"kyc_state": "verified_light",
"set_password_url": "https://stixpay.com/customer/set_password.php?token=…",
"environment": "test"
}
State / province required for US, CA, AU, MX — send customer_state (or state / state_of_residence). Examples: "country": "US", "customer_state": "CA" · "country": "CA", "customer_state": "MB" · "country": "AU", "customer_state": "NSW". ISO forms like CA-MB are accepted and normalized. Other countries (e.g. FR) do not need customer_state.
New customers get a set-password link by email; hosted checkout can also finish password setup.
Poll KYC: GET /api/kyc/[email protected]
2 — Create payment
Same API key plane as KYC start. Returns payment_id + redirect_url. Do not send phone, address, postal code, city or birthdate.
Body
| Field | Description |
|---|---|
amount | Amount > 0 |
currency | e.g. EUR |
payment_method | Optional. How the buyer pays on hosted checkout (card, Apple Pay, bank transfer, …). Alias: checkout_payment_method. Default: credit_card. See values below. Do not send with product_id (NFT). |
merchant_order_id | Unique per merchant |
customer_email | Same email as KYC start |
store_name | Store label |
success_url | Absolute URL |
failure_url | Absolute URL |
provider_code | Optional. Lock the on-ramp provider (codes enabled for your merchant — see dashboard / admin). |
payment_method — values & limits
It tells StixPay which checkout rail to open for the buyer (card form, Apple Pay, SEPA, PayPal, …). It is independent of KYC. Availability still depends on the on-ramp provider, the buyer’s country/currency, and methods enabled for your merchant.
Min / max below are indicative per-transaction BUY limits for the method’s primary fiat. Live ceilings can differ by partner, KYC tier, and jurisdiction — StixPay enforces the synced provider limits at checkout.
| Value | Meaning | Min | Max | Currency |
|---|---|---|---|---|
credit_card | Debit / credit card (default) | 10 | 15,000 | EUR / USD |
apple_pay | Apple Pay | 10 | 15,000 | EUR / USD |
google_pay | Google Pay | 10 | 15,000 | EUR / USD |
open_banking | SEPA / open banking transfer | 10 | 30,000 | EUR |
paypal | PayPal | — | — | EUR (provider sync) |
ideal | iDEAL (NL) | 10 | 30,000 | EUR |
sofort | Sofort | 10 | 30,000 | EUR (typ.) |
klarna_paynow | Klarna Pay Now | 125 | 50,000 | SEK |
gbp_bank_transfer | GBP bank transfer | 10 | 3,000 | GBP |
ach_bank_transfer | ACH bank transfer (US) | 10 | 30,000 | USD |
payid_bank_transfer | PayID bank transfer (AU) | 20 | 1,500 | AUD |
npp_bank_transfer | NPP bank transfer (AU) | 20 | 5,000 | AUD |
interac | Interac (CA) | 20 | 10,000 | CAD |
pix | Pix (BR) | 50 | 25,000 | BRL |
spei | SPEI (MX) | 1,200 | 35,000 | MXN |
khipu | Khipu | 30,000 | 6,000,000 | CLP |
zar_bank_transfer | ZAR bank transfer (ZA) | 200 | 80,000 | ZAR |
pse | PSE (CO) | — | — | COP (provider sync) |
vietqr | VietQR / QR wallet | 200,000 | 2,500,000 | VND |
Common aliases are accepted (e.g. card → credit_card, sepa → open_banking). If omitted or empty, StixPay uses credit_card. Card / Apple Pay / Google Pay ceilings also vary by fiat (e.g. GBP card max 12,500; CAD Interac max 10,000).
Request
POST /api/payment/create
Content-Type: application/json
X-API-Key: sdk_your_test_key
{
"amount": 19.99,
"currency": "EUR",
"payment_method": "credit_card",
"merchant_order_id": "ORDER_123",
"customer_email": "[email protected]",
"store_name": "Example Store",
"success_url": "https://shop.example/success",
"failure_url": "https://shop.example/failed"
}
Response
HTTP 200
{
"success": true,
"payment_id": "9021",
"merchant_order_id": "ORDER_123",
"redirect_url": "https://stixpay.com/customer/checkout.php?token=…",
"expires_at": "2026-09-01 10:00:00"
}
Redirect the buyer to redirect_url.
If KYC is missing
HTTP 422
{
"success": false,
"error": "kyc_required",
"message": "Customer Light KYC is not approved for the test (sandbox) environment…"
}
Payment status
- pending — created; buyer has not finished checkout
- pending_topup — on hosted checkout / paying
- succeeded — paid (
payment.succeeded) - failed — not paid (
payment.failed), or cancelled / refunded by the payment provider after a firstpayment.succeeded(payment.reversed) - expired — not completed in time
Lookups (GET)
All require X-API-Key except health.
Opaque KYC state for a customer you started. Query: customer_email (or customer_user_id).
GET /api/kyc/[email protected] X-API-Key: sdk_your_test_key
Full payment object for a payment_id returned by create payment.
Lightweight status for polling after redirect.
Paginated list. Query: page, per_page, status, q (search order id / email / payment id).
Merchant balance breakdown (available / hold / reserve, EUR).
Indicative FX quote. Query: amount, currency (required).
GET /api/quote?amount=19.99¤cy=EUR X-API-Key: sdk_your_test_key
Reference FX rate table.
Public platform status (no API key).
Webhooks
Register your URL in Merchant → Webhooks and select the events to receive. Verify X-Webhook-Signature (HMAC-SHA256 of the raw body with your secret_…). Respond with HTTP 200.
Envelope: { id, type, created, data }.
Payments & KYC
| Event | When |
|---|---|
customer.kyc.updated | Customer Light KYC state changed |
payment.succeeded | Payment completed |
payment.failed | Payment failed |
payment.reversed | The payment provider cancelled or refunded an order after payment.succeeded was sent (card captured, then compliance refusal or refund). Treat the order as not paid. data.reason gives the cause (provider_cancelled, provider_declined, provider_refunded, provider_expired, customer_cancelled). Endpoints subscribed to payment.failed but not to this event receive payment.failed with data.reversal = true instead. |
payment_intent.canceled | Payment cancelled before completion |
refund.completed | Refund completed |
Payouts
| Event | When |
|---|---|
payout.completed | Merchant payout to your bank / crypto wallet completed |
payout.failed | Merchant payout failed |
transaction_payout_success | On-ramp settlement / USDC payout for a paid transaction succeeded |
Test delivery: POST /api/webhook/test or “Send test” in the portal.