Download collection
Request early access

Developer documentation

SAVI Platform integration hub

Guides for product and engineering teams, plus a full API reference for your backend, test environment, authentication, endpoints, and webhooks.

Go to Platform
Download collection
OverviewQuick startTest environmentAPI keys

Getting Started

  • Overview
  • Quick start
  • Test environment
  • API keys

Guides

  • Platform architecture
  • Payment operations
  • Seller onboarding
  • Platform journey
  • Seller verification

APIs

  • API introduction
  • Authentication
  • Error responses
  • Endpoint reference
  • Postman collection

Webhooks

  • Events & verification
  • Verify integration

Overview

Welcome to SAVI developer documentation. We guide platform teams through KYB onboarding, seller registration, payments, and settlement, all from your backend via REST.

SAVI provides embedded payment and payout infrastructure for Saudi digital platforms. Your customers and sellers stay on your app; your server connects to SAVI using secret API keys over HTTPS.

Documentation structure

  • Guides, conceptual flows with diagrams for product and engineering alignment.
  • APIs, base URL, authentication, parameter tables, and request examples.
  • Webhooks, event types, signature verification, and integration testing.

Quick start

Follow these steps to connect your platform, the same onboarding flow used by marketplace partners.

  1. 1

    Register your platform

    Open a SAVI platform account for your company. This is a one-time step for the marketplace operator, not for individual sellers.

    Platform login →
  2. 2

    Complete KYB and get activated

    Submit your business documents in the platform dashboard. After SAVI compliance approves KYB, your account becomes active and you can create API credentials.

    KYB in dashboard →
  3. 3

    Create test API keys

    Generate a test secret key (sk_test_...) from API Keys in the dashboard. Use it while building, test and live data are kept separate.

    API Keys →
  4. 4

    Connect your backend

    Register sellers, create payments, and register webhooks from your server using the integration endpoints in this guide.

    Endpoint reference →
  5. 5

    Verify, then switch to live

    Run the verification checklist below. When you are ready for real money, create a live key (sk_live_...) and update your production environment.

    Verification checklist →

Test environment

SAVI provides a sandbox for integration testing. Test mode does not move real money or affect live seller records.

Sandbox

Use sk_test_ keys while building. The same API base URL serves both test and live, your key prefix selects the mode.

Base URL

https://savi-platform-backend-production.up.railway.app
Health check
AspectTest modeLive mode
When to useWhile building and QA, before accepting real customer payments.When your integration is production-ready and you accept real money.
API key prefixsk_test_sk_live_
Data isolationTest sellers, payments, and payouts are separate from live records.Real sellers, payments, and bank settlements.
Payment processingSimulated payment flow, no real card or bank network charges.Real payment capture and settlement through SAVI.
Compliance checksKYB is still required; seller KYC may use simplified test behaviour.Full compliance and payout rules apply.

API keys

Secret keys authenticate every server-side request. Manage them in the platform dashboard after KYB approval.

Build with test keys, launch with live keys

  • Test: sk_test_, sandbox, no real money.
  • Live: sk_live_, production only after go-live approval.
  • Webhooks: signing secrets are separate, not your API key.
Key typePrefixClient-safeDescription
Test secret keysk_test_NoServer-only credential for development and QA. Create one in the platform dashboard after KYB approval. Use it for ping, merchant registration, payments, and webhook testing.
Live secret keysk_live_NoServer-only credential for production. Available after your platform is approved for live mode. Never embed in mobile apps, browsers, or public repositories.

Protect your keys

  • Store keys in a secrets manager or server environment variables, never in source code checked into git.
  • Use test keys (sk_test_) until your integration is verified end-to-end.
  • Each key is shown only once when created. Copy it immediately; you cannot retrieve the full value later.
  • Revoke and recreate a key immediately if it is exposed in logs, email, or a public repo.
  • Webhook signing secrets are separate from API keys, manage them under Webhooks in the dashboard.

Create

Platform dashboard → API Keys → create a key with Test or Live mode. Name it for the environment (e.g. "Staging backend").

Copy once

The full secret is displayed a single time. Save it in your deployment secrets before closing the dialog.

Revoke

Revoke a compromised or unused key from the dashboard. Requests with a revoked key are rejected immediately.

Go live

Create a live key, update production environment variables, register production webhook URLs, and retire test keys from production servers.

Platform architecture

Public guide, how actors connect before you write integration code.

How SAVI fits your platform

Customer

Your app

Checkout

Your platform

Backend + UI

API key

SAVI

Payments & payouts

Settlement

Seller

Receives payout

Customer

Your app

Checkout

Your platform

Backend + UI

API key

SAVI

Payments & payouts

Settlement

Seller

Receives payout

Your customers and sellers never leave your application. Your backend talks to SAVI over HTTPS using server credentials.

Payment operations

End-to-end flow from customer checkout to seller settlement.

Payment operations flow
CustomerPlatform
1. Places order
PlatformSAVI
2. POST /v1/payments
SAVIPlatform
3. payment.completed webhook
SAVISeller
4. Split & settle funds

Your server creates the payment. SAVI captures funds, notifies your webhook endpoint, and routes the seller share according to your agreement.

Implementation tip

Your backend creates the payment; your webhook handler confirms success. Do not mark orders paid until payment.completed is verified.

Seller onboarding

Two verification paths, choose based on whether your platform already verified the seller.

Seller onboarding paths

Path 1

  1. ① POST /v1/merchants
  2. ② PUT …/kyc/attestation
  3. ③ POST …/bank-account
  4. ④ merchant.verified webhook

Path 2

  1. ① POST /v1/merchants (savi)
  2. ② Seller completes KYC on SAVI
  3. ③ POST …/bank-account
  4. ④ merchant.verified webhook

Path 1 keeps sellers on your app. Path 2 sends selected sellers to complete verification on SAVI.

Platform journey

Business lifecycle from KYB to settlement.

  1. 1

    Register your business on SAVI

    Your company opens a platform account on SAVI. This is a one-time step for the marketplace operator, not for individual sellers.

  2. 2

    Complete KYB (Know Your Business)

    Submit company documents through the SAVI platform dashboard, commercial registration, authorized signatory, and compliance attestation. KYB confirms your business is eligible to operate payments through SAVI.

  3. 3

    SAVI review and activation

    SAVI compliance reviews your KYB submission. Once approved, your platform status becomes active and you can create API credentials.

  4. 4

    Bring your sellers onto SAVI

    Each seller on your platform gets a record in SAVI so payments can be split and settled correctly. How identity is verified depends on your setup, see Seller verification below.

  5. 5

    Accept customer payments

    When a buyer checks out on your platform, your server creates a payment in SAVI. Funds are captured and split according to your platform agreement.

  6. 6

    Settle sellers

    Depending on your payout configuration, SAVI may release funds automatically after payment or on a schedule. Your platform receives webhook notifications at each stage.

Seller verification

Detailed comparison of Path 1 (platform verified) and Path 2 (SAVI verified).

Path 1

Your platform already verified the seller

Recommended for marketplaces and platforms with their own KYC

The seller stays on your app. They do not need to register again on SAVI or complete a second identity check.

  • You already collect identity and business documents during seller signup on your platform.
  • You are comfortable attesting to SAVI that the seller passed your compliance checks.
  • You want a single onboarding experience for sellers.

Path 2

SAVI verifies the seller directly

When your platform has not completed seller KYC

The seller is invited to complete verification on SAVI: typically through the merchant portal (identity check and document upload). They may receive an email invite from your platform or from SAVI.

  • You create the seller record on your platform but have not finished KYC yet.
  • You prefer SAVI to hold the identity verification step.
  • A seller failed or skipped verification on your side and needs to complete it on SAVI.

Does every seller need a SAVI login?

No. Path 1 is designed so sellers never need to visit SAVI. Path 2 uses the merchant portal only for sellers who must complete verification on SAVI.

What is the minimum data sent through the API?

Seller ID in your system, business name, and contact email. Additional fields such as commercial registration or document references are optional depending on your compliance agreement.

Can we use both paths for different sellers?

Yes. Most sellers can follow Path 1 if your platform verified them. Individual sellers who need direct verification can follow Path 2.

API introduction

Technical reference for your backend integration.

The SAVI Platform API is RESTful. All requests use HTTPS and return JSON. Authenticate with your platform secret key on every server-side call using Authorization: Bearer sk_test_... or sk_live_...

Integration endpoints (this guide) do not include platformId in the path, your platform is bound to the API key. Dashboard endpoints under /v1/platforms/{platformId}/... require a JWT from platform login and are not used for server integrations.

Two modes exist, test and live, controlled by your API key prefix (sk_test_ vs sk_live_). Objects created in one mode are not visible in the other.

Resource IDs are CUID strings (e.g. cmqqi2r9r0055ql1m18np1wxd), not prefixed identifiers.

Amounts are expressed in halalas unless noted otherwise. 1 SAR = 100 halalas.

Base URL

https://savi-platform-backend-production.up.railway.app/v1

Integration routes vs dashboard routes

Server integrations authenticate with your secret API key (sk_test_ or sk_live_). These routes do not include platformId in the URL, your platform is inferred from the key. Call GET /v1/integration/ping to read your platformId.

Routes under /v1/platforms/{platformId}/... are for the SAVI platform dashboard (JWT login). Do not use those paths from your backend integration code.

HTTPS required

All API calls must use HTTPS. Requests over plain HTTP are rejected. Never send secret keys from browser or mobile client code.

Quick reference

GET/v1/integration/ping

Verify your API key and confirm your platform is active.

POST/v1/merchants

Register a seller when they join your platform.

PUT/v1/merchants/:id/kyc/attestation

Path 1 only, confirm your platform verified this seller.

POST/v1/merchants/:id/bank-account

Store the seller’s IBAN for future payouts.

POST/v1/payments

Create a payment when a customer checks out.

Authentication

Send your full secret key on every server-side request using the Bearer scheme.

Use Authorization: Bearer sk_test_... or Authorization: Bearer sk_live_.... Paste the complete key value, including the sk_test_ or sk_live_ prefix.

Example request
curl -s "https://savi-platform-backend-production.up.railway.app/v1/integration/ping" \
  -H "Authorization: Bearer sk_test_YOUR_KEY"

Error responses

Failed requests return JSON with a consistent error envelope. Use request_id when contacting SAVI support.

HTTPMeaningTypical cause
400Validation errorRequest body or query parameters failed validation.
401Authentication failedMissing, invalid, or revoked API key.
403ForbiddenValid credentials but the action is not allowed for this platform or merchant.
404Not foundResource does not exist or is not visible in your current test/live mode.
422Unprocessable entityRequest is syntactically valid but cannot be processed (e.g. merchant not ready).
400 Validation error, example
{
  "error": {
    "code": "validation_error",
    "message": "amountHalalas must be at least 100",
    "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
401 Authentication failed, example
{
  "error": {
    "code": "Unauthorized",
    "message": "Invalid or revoked API key",
    "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Endpoint reference

Detailed parameter tables, request bodies, and curl examples for each integration endpoint.

IntegrationGET/v1/integration/ping

Verify API key connectivity

Health-check for your integration credentials. Call this first after creating a test key to confirm authentication and that your platform account is active. The response includes your platformId for logging and support.

Response
{
  "ok": true,
  "platformId": "cmqqi2r9r0055ql1m18np1wxd",
  "mode": "test",
  "message": "SAVI API key authenticated successfully"
}
Example request
curl -s -X GET "https://savi-platform-backend-production.up.railway.app/v1/integration/ping" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json"
MerchantsPOST/v1/merchants

Register a seller

Creates a merchant record linked to your platform (inferred from your API key). Use verificationPath to choose Path 1 (platform attestation) or Path 2 (SAVI verifies the seller).

Parameters

FieldTypeRequiredDescription
externalIdstringRequiredYour internal seller ID, must be unique per platform.
businessNamestringRequiredShop or business display name.
contactEmailstringRequiredSeller contact email.
crNumberstringOptionalCommercial registration number.
verificationPathstringOptionalplatform (Path 1) or savi (Path 2). Defaults to platform.
kycAttestationobjectOptionalOptional inline attestation when creating with Path 1.
Request body
{
  "externalId": "seller-ordro-001",
  "businessName": "Fatima Trading Co.",
  "contactEmail": "seller@example.com",
  "verificationPath": "platform"
}
Response
{
  "id": "cmqqi2s0a0056ql1m19abc2xyz",
  "externalId": "seller-ordro-001",
  "businessName": "Fatima Trading Co.",
  "status": "pending",
  "kycStatus": "pending"
}
Example request
curl -s -X POST "https://savi-platform-backend-production.up.railway.app/v1/merchants" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "externalId": "seller-ordro-001", "businessName": "Fatima Trading Co.", "contactEmail": "seller@example.com", "verificationPath": "platform"}'
KYCPUT/v1/merchants/:merchantId/kyc/attestation

Submit platform KYC attestation (Path 1)

Confirms your platform has verified the seller. Required for Path 1 before the seller can receive payments.

Parameters

FieldTypeRequiredDescription
merchantIdpath string (CUID)RequiredSAVI merchant id from POST /v1/merchants.
verifiedbooleanRequiredMust be true when attesting.
verifiedAtISO8601 stringRequiredWhen your platform completed verification.
methodstringRequiredYour verification method label, e.g. "platform_kyc_v2".
externalRefstringRequiredYour internal KYC case or ticket reference.
Request body
{
  "verified": true,
  "verifiedAt": "2026-06-12T10:00:00.000Z",
  "method": "platform_kyc",
  "externalRef": "KYC-2026-00142"
}
Example request
curl -s -X PUT "https://savi-platform-backend-production.up.railway.app/v1/merchants/cmqqi2s0a0056ql1m19abc2xyz/kyc/attestation" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "verified": true, "verifiedAt": "2026-06-12T10:00:00.000Z", "method": "platform_kyc", "externalRef": "KYC-2026-00142"}'
MerchantsPOST/v1/merchants/:merchantId/bank-account

Add seller bank account (IBAN)

Stores the seller IBAN for payouts. Required before funds can be settled to the seller bank account.

Parameters

FieldTypeRequiredDescription
merchantIdpath string (CUID)RequiredSAVI merchant id.
ibanstringRequiredSaudi IBAN (15–34 characters).
accountHolderNamestringRequiredName on the bank account.
bankNamestringOptionalBank name for display.
Request body
{
  "iban": "SA0380000000608010167519",
  "accountHolderName": "Fatima Al-Rashid",
  "bankName": "Al Rajhi Bank"
}
Example request
curl -s -X POST "https://savi-platform-backend-production.up.railway.app/v1/merchants/cmqqi2s0a0056ql1m19abc2xyz/bank-account" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "iban": "SA0380000000608010167519", "accountHolderName": "Fatima Al-Rashid", "bankName": "Al Rajhi Bank"}'
KYCGET/v1/merchants/:merchantId/kyc/status

Get seller KYC status

Poll whether a seller is ready for payments and payouts. Prefer webhooks (merchant.verified) over polling in production.

Response
{
  "merchantId": "cmqqi2s0a0056ql1m19abc2xyz",
  "status": "verified",
  "canReceivePayments": true,
  "canReceivePayouts": true
}
Example request
curl -s -X GET "https://savi-platform-backend-production.up.railway.app/v1/merchants/cmqqi2s0a0056ql1m19abc2xyz/kyc/status" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json"
PaymentsPOST/v1/payments

Create a payment

Initiates a customer checkout payment linked to a seller. Amount is in halalas (1 SAR = 100 halalas). Supports optional Idempotency-Key header for safe retries.

Parameters

FieldTypeRequiredDescription
merchantIdstring (CUID)RequiredSeller SAVI merchant id.
amountHalalasintegerRequiredAmount in halalas. Minimum 100 (1.00 SAR).
currencystringOptionalDefaults to SAR.
descriptionstringRequiredOrder or payment description shown in records.
externalOrderIdstringOptionalYour order reference for reconciliation.
returnUrlstring (URL)OptionalRedirect URL after payment if applicable.
Idempotency-KeyheaderOptionalUnique key per payment attempt, replays return the same result.
Request body
{
  "merchantId": "cmqqi2s0a0056ql1m19abc2xyz",
  "amountHalalas": 15000,
  "description": "Order #ORD-8842",
  "externalOrderId": "ORD-8842"
}
Response
{
  "id": "cmqqi2t1b0057ql1m20def3uvw",
  "status": "pending",
  "amountHalalas": 15000,
  "currency": "SAR",
  "merchantId": "cmqqi2s0a0056ql1m19abc2xyz"
}

Note: Listen for payment.completed or payment.failed webhooks instead of polling status.

Example request
curl -s -X POST "https://savi-platform-backend-production.up.railway.app/v1/payments" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "merchantId": "cmqqi2s0a0056ql1m19abc2xyz", "amountHalalas": 15000, "description": "Order #ORD-8842", "externalOrderId": "ORD-8842"}'
PayoutsGET/v1/merchants/:merchantId/balance

Get seller balance

Returns available, reserved, and total payable balance for a seller wallet display.

Response
{
  "merchantId": "cmqqi2s0a0056ql1m19abc2xyz",
  "balanceHalalas": 45000,
  "reservedHalalas": 5000,
  "availableHalalas": 40000,
  "currency": "SAR"
}
Example request
curl -s -X GET "https://savi-platform-backend-production.up.railway.app/v1/merchants/cmqqi2s0a0056ql1m19abc2xyz/balance" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json"
PayoutsPOST/v1/merchants/:merchantId/payouts

Create a manual payout

Dispatches funds to the seller IBAN. Only required when your platform controls payout timing. Skip if SAVI auto-settles on your behalf.

Parameters

FieldTypeRequiredDescription
amountHalalasintegerRequiredAmount to pay out in halalas.
Idempotency-KeyheaderOptionalPrevents duplicate payouts on retry.
Request body
{ "amountHalalas": 40000 }

Note: Use POST /v1/merchants/:merchantId/payouts, not POST /v1/platforms/:platformId/payouts (that path does not exist).

Note: Listen for payout.sent or payout.failed webhooks for final status.

Example request
curl -s -X POST "https://savi-platform-backend-production.up.railway.app/v1/merchants/cmqqi2s0a0056ql1m19abc2xyz/payouts" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amountHalalas": 40000 }'

Optional endpoints

POST/v1/merchants (verificationPath: savi)

Path 2, register a seller who will complete KYC on SAVI.

GET/v1/merchants/:id/kyc/status

Check whether a seller is ready to receive payments or payouts.

GET/v1/merchants/:id/balance

Display available balance in your seller wallet or admin tools.

POST/v1/merchants/:id/payouts

Release funds manually when your platform controls payout timing.

Field mapping

Your platformSAVI fieldWhen needed
Seller ID in your systemexternalIdRequired at registration
Business or shop namebusinessNameRequired at registration
Seller contact emailcontactEmailRequired at registration
Commercial registrationcrNumberOptional
Your internal KYC referencekycAttestation.externalRefOptional
Seller IBANbankAccount.ibanRequired before payout
Your order referencepayments.externalOrderIdOptional at checkout

Postman collection

Import a pre-built collection to test the full integration flow without writing code first.

Download

savi-integration.postman_collection.json
  1. 1

    Download the collection

    Import savi-integration.postman_collection.json into Postman (File → Import).

  2. 2

    Set collection variables

    Open the collection Variables tab. Set api_base_url to https://api.savi.sa and secret_key to your sk_test_ key from the platform dashboard.

  3. 3

    Run Integration → Ping

    Send the ping request first. A 200 response confirms your key is valid and stores your platformId in collection variables.

  4. 4

    Follow the folder order

    Merchants → KYC → Payments. Collection scripts store merchantId and paymentId for chained requests.

VariableValue
api_base_urlhttps://savi-platform-backend-production.up.railway.app
secret_keysk_test_... from dashboard

Webhooks

Signed HTTPS callbacks so your backend stays in sync without polling.

Register your endpoint first

Outbound webhooks are available in test and live mode. You must register an HTTPS webhook URL in the platform dashboard before events are delivered, without a URL, events are not sent.
Webhook delivery

SAVI

POST + signature

Your server

Webhook handler

Update state

Your platform

Orders & wallets

SAVI

POST + signature headers

Your server

Webhook handler

Update DB / notify

Your platform

Orders & wallets

SAVI POSTs signed events to your HTTPS endpoint. Verify X-SAVI-Signature before updating order or seller state.

Signing secret ≠ API key

Each webhook endpoint has its own signing secret under Webhooks in the dashboard.
EventWhen fired
payment.completedA customer payment was captured successfully.
payment.failedA payment attempt did not succeed.
merchant.verifiedA seller passed KYC and can receive funds.
payout.sentFunds were dispatched to a seller’s bank account.
payout.failedA payout could not be completed.
Configure webhooks in dashboard →
Verify signature (Node.js)
import crypto from 'crypto';

export function verifySaviWebhook(
  rawBody: string,
  timestamp: string,
  signature: string,
  secret: string,
): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'utf8'),
    Buffer.from(signature, 'utf8'),
  );
}

Verify integration

Complete this checklist before switching to live credentials.

  1. 1

    Confirm API connectivity

    In the platform dashboard, open API Keys and run Test ping. You should receive a success response with your platform ID.

    Open in dashboard →
  2. 2

    Register a test seller

    Call POST /v1/merchants from your server with your sk_test_ key (platform is inferred from the key). For Path 1, follow with KYC attestation and bank account endpoints.

  3. 3

    Create a test payment

    Call POST /v1/payments linked to the test merchant. After registering a webhook URL, confirm your order flow receives payment.completed or payment.failed.

  4. 4

    Validate webhooks

    Register your HTTPS endpoint under Webhooks, then send a test event. Confirm signature verification succeeds in your server logs.

    Open in dashboard →
  5. 5

    Switch to live credentials

    After QA sign-off, create sk_live_ keys, update production secrets, and point webhooks to your production URL.

    Open in dashboard →
Example: register a test seller
curl -s -X POST "https://savi-platform-backend-production.up.railway.app/v1/merchants" \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "your-seller-001",
    "businessName": "Fatima Trading",
    "contactEmail": "seller@example.com"
  }'
  • KYB approved and platform status is active.
  • Live API key created and stored in production secrets (not test keys).
  • Production webhook URL registered with a unique signing secret.
  • Seller onboarding and checkout flows tested end-to-end in test mode.
  • Webhook signature verification implemented and tested.
  • Error handling and idempotency in place for payments and webhooks.

On this page

  • Overview
  • Quick start
  • Test environment
  • API keys

SAVI is the API-first embedded finance platform for Saudi Arabia's digital marketplaces and SMB platforms.

hamamri@savi.sa

Riyadh, Kingdom of Saudi Arabia

Platform

  • Documentation
  • How SAVI Works
  • Products
  • Regulatory

Who we serve

  • Verticals
  • Why SAVI

Company

  • About
  • Get Started
  • Privacy Policy
  • Terms of Service

© 2026 SAVI. All rights reserved. Riyadh, Kingdom of Saudi Arabia.

SAVI is a technology platform. All regulated financial services are delivered through SAVI's network of Saudi-licensed financial partners under SAMA supervision.