Use the SavaPay API from your server to create merchants, create payment requests, check payment status, issue refunds, and manage webhook settings.
Base URL
https://api.savapay.io/v1Approved pilot merchants receive separate test-environment access during onboarding. Never send test credentials to the production URL.
Before each request
- Send your secret API key in the request header, except for merchant creation.
- Add an Idempotency-Key header (max 64 characters) when a request creates, changes, cancels, or refunds something.
- Send money as whole cents. Send 1299 for $12.99.
Reading responses
A successful response contains the result of your request. An unsuccessful response contains a short machine-readable code your system can use to decide what to do next.
Error codes
| Code | HTTP | Meaning |
|---|---|---|
invalid_request | 400 | Malformed or missing input |
authentication_required | 401 | Missing or invalid API key |
forbidden | 403 | Key lacks scope or merchant is not active |
not_found | 404 | Resource not found or not owned |
idempotency_conflict | 409 | Key reused with a different request |
invalid_state | 409 | Resource is not in a valid state for the action |
rate_limited | 429 | Too many requests |
internal_error | 500 | Unexpected server failure |
See Errors and retries for safe recovery guidance.
Create a merchant
POST /v1/merchants is public and requires no API key. It creates a merchant and issues the first API key. The key is returned once. A new merchant is pending and cannot process payments until it submits KYC and an administrator activates it.
{ "businessName": "Acme", "email": "acme@x.com", "settlementUid": "uid_1" }Response 201:
{
"merchant": { "id": "m_1abc", "businessName": "Acme", "status": "pending" },
"apiKey": "sp_live_..."
}Submit KYC information
POST /v1/merchants/{id}/kyc submits business information. An automated check runs and the merchant moves to pending_review regardless of the result; an administrator makes the final decision through dual review.
Response 200:
{ status: "pending_review", automatedCheck: { passed, score, reasons } }Upload a KYC document
POST /v1/merchants/{id}/kyc/documents accepts multipart/form-data. Send documentType and document. JPEG, PNG, WEBP, and PDF files up to 8 MB are stored privately in Cloud Storage and are never public.
Create a payment request
POST /v1/payment-intents creates a request when your customer is ready to check out. SavaPay returns a checkout link for that payment. Send an idempotency key such as checkout-order-123. Do not mark the order paid until you confirm its status.
{
"amount": 1299,
"currency": "USD",
"merchantReference": "order-123",
"description": "Acme widget",
"webhookUrl": "https://merchant.example.com/savapay/webhook"
}Response 201:
{
"id": "pi_1abc",
"status": "created",
"amount": 1299,
"currency": "USD",
"fee": 40,
"total": 1339,
"checkoutUrl": "https://pay.savapay.io/checkout/<token>",
"expiresAt": "2026-09-14T00:30:00Z",
"merchantReference": "order-123"
}Check a payment request
GET /v1/payment-intents/{id} returns the current intent, including status and timestamped statusHistory. Use it to confirm payment before fulfilment.
Cancel a payment request
POST /v1/payment-intents/{id}/cancel cancels an unpaid created or pending_customer intent.
Issue a refund
POST /v1/refunds requests a refund for a succeeded payment.
{ "paymentIntentId": "pi_1abc", "amount": 1299 }List payments
GET /v1/payments lists payments with cursor pagination. It supports limit (maximum 100) and cursor. Responses contain data and nextCursor; nextCursor is absent when no results remain.
Reconcile a payment
GET /v1/payment-intents/{id}/reconcile returns intentId, status, and ledgerMatched.
Register a webhook destination
POST /v1/webhook-endpoints registers a destination and requires webhooks:write scope. It returns a signingSecret used to verify deliveries.
Manage API keys
POST /v1/api-keys issues an additional scoped key whose secret is shown once. DELETE /v1/api-keys/{keyHash} revokes one. Only a hash is stored.
Not part of /v1
POST /merchant-payments/checkout/{id}/approve is the Firebase-authenticated customer approval of the locked amount. PATCH /merchant-payments/admin/merchants/{id}/status is administrator-only; merchant API keys never grant administrator access.