Create Whitelabel Checkout

Overview

Create a checkout and initiate payment in a single API request. This endpoint is designed for headless or embedded checkout flows where you handle the payment UI yourself instead of redirecting to SyncPay's hosted page.

Use this endpoint when:

  • Building a custom checkout experience within your app
  • You want full control over the payment UI
  • Creating embedded payment flows
  • Building mobile app integrations

Key difference from standard checkout: This endpoint returns payment instructions directly instead of a checkout URL.


Authentication

Type: API Key (required)

Required Headers

Header Required Description
Authorization Yes Format: Bearer sk_test_... or Bearer sk_live_...
Content-Type Yes Must be application/json

Request

Method & Path

POST /api/v1/payments/whitelabel

Request Body

{
  "pricing": {
    "base_currency": "USD",
    "amount": "50.00"
  },
  "customer_email": "customer@example.com",
  "customer_name": "John Doe",
  "quote_id": "quote_1a2b3c4d5e6f",
  "payment_method": "bank_transfer",
  "phone_number": "+2348012345678",
  "bank_account_number": "0123456789",
  "success_url": "https://yoursite.com/payment/success",
  "cancel_url": "https://yoursite.com/payment/cancelled",
  "metadata": {
    "order_id": "ORD-12345"
  },
  "expires_in_minutes": 60
}

Request Fields

Field Type Required Description
pricing object Yes Pricing configuration (same as standard checkout)
pricing.base_currency string Yes Base currency code
pricing.amount string Yes Amount in base currency
pricing.local_pricing object No Currency-specific amounts (USD base only)
customer_email string Yes Customer's email address
customer_name string No Customer's full name
quote_id string Yes Quote ID from Create Quote
payment_method string Yes Payment method ID (required if not in quote)
phone_number string Conditional Required for mobile money payments
bank_account_number string Conditional Required for bank transfer payments
success_url string No Success redirect URL
cancel_url string No Cancel redirect URL
metadata object No Custom metadata (max 20 keys, 10KB)
expires_in_minutes integer No Expiration time (1-1440, default: 60)

Dependencies & Prerequisites

This endpoint requires several steps before use:

Required Steps (in order):

  1. Get payment methods - Use List Payment Methods
  2. Create a quote - Use Create Quote to get quote_id
  3. Collect payment details - Get customer's phone number or bank account
  4. Call this endpoint - Create and initiate payment in one request

Links:


Example Use Case

Scenario: Your fintech application enables peer-to-peer money transfers. Users need to send money directly within your app without being redirected to an external payment page. You want to maintain your brand experience while processing bank transfers, showing payment instructions directly in your interface, and handling the complete payment flow natively.

Implementation Flow:

// Step 1: Get a quote for the payment
const quoteResponse = await fetch('https://api.usesyncpay.com/api/v1/payments/quotes', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_abc123xyz...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    pricing: {
      base_currency: 'USD',
      amount: '100.00'
    },
    payment_method: 'bank_transfer',
    to_currency: 'NGN',
    customer_email: 'user@example.com'
  })
});

const quote = await quoteResponse.json();

// Step 2: Show customer the quote amount (NGN 150,000)
displayQuote({
  amount: quote.amount,
  currency: quote.currency,
  exchangeRate: quote.exchange_rate
});

// Step 3: Customer enters bank account number in your UI
const bankAccount = await getUserBankAccount(); // "0123456789"

// Step 4: Create whitelabel checkout and initiate payment
const paymentResponse = await fetch('https://api.usesyncpay.com/api/v1/payments/whitelabel', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_abc123xyz...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    pricing: {
      base_currency: 'USD',
      amount: '100.00'
    },
    customer_email: 'user@example.com',
    customer_name: 'Jane Doe',
    quote_id: quote.quote_id,
    payment_method: 'bank_transfer',
    bank_account_number: bankAccount,
    metadata: {
      transaction_id: 'TXN-789'
    }
  })
});

const payment = await paymentResponse.json();

// Step 5: Display payment instructions to customer
displayPaymentInstructions({
  status: payment.status,
  amount: payment.amount,
  currency: payment.currency,
  instructions: payment.payment_instructions,
  reference: payment.provider_reference
});

Response

200 – Success

Returns payment details and instructions for the customer.

{
  "checkout_id": "chk_1a2b3c4d5e6f",
  "charge_id": "chr_9x8y7z6w5v",
  "status": "PENDING",
  "amount": "150000.00",
  "currency": "NGN",
  "payment_method": "bank_transfer",
  "payment_provider": null,
  "provider_reference": "REF-12345",
  "payment_instructions": {
    "type": "bank_transfer",
    "bank_name": "Access Bank",
    "account_number": "9876543210",
    "account_name": "SyncPay Collections",
    "reference": "REF-12345",
    "instructions": "Transfer NGN 150,000 to the account above using the reference code"
  },
  "expires_at": "2026-01-24T15:30:00.000Z",
  "created_at": "2026-01-24T14:30:00.000Z"
}

Response Fields

Field Type Description
checkout_id string Checkout session ID
charge_id string Charge/payment ID for tracking
status string Payment status (PENDING, AWAITING_PAYMENT, etc.)
amount string Amount customer should pay
currency string Payment currency
payment_method string Payment method used
payment_provider string|null Payment provider (not exposed for security)
provider_reference string Transaction reference ID
payment_instructions object Instructions to display to customer
expires_at string ISO 8601 timestamp for payment expiration
created_at string ISO 8601 timestamp of creation

Payment Instructions Format

The payment_instructions object varies by payment method:

Bank Transfer Instructions

{
  "type": "bank_transfer",
  "bank_name": "Access Bank",
  "account_number": "9876543210",
  "account_name": "SyncPay Collections",
  "reference": "KORA-REF-12345",
  "instructions": "Transfer NGN 150,000 to the account above using the reference code"
}

Mobile Money Instructions

{
  "type": "mobile_money",
    "provider": "MTN",  // Mobile money provider (customer-facing)
  "phone_number": "+233200123456",
  "reference": "MM-REF-12345",
  "instructions": "Send GHS 620 to the number above with reference MM-REF-12345"
}

Crypto Wallet Instructions

{
  "type": "crypto",
  "network": "TRC20",
  "wallet_address": "TXY7GhbJ9kLmN3oPqR5sTuV8wXyZ1aB2cD",
  "amount": "50.00",
  "currency": "USDT",
  "reference": "CRYPTO-REF-12345",
  "instructions": "Send exactly 50.00 USDT (TRC20) to the address above"
}

400 – Bad Request

Validation errors or invalid combinations.

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request parameters",
    "details": {
      "quote_id": "Quote expired or not found. Please get a new quote.",
      "payment_method": "payment_method does not match the quote"
    }
  }
}

Common causes:

  • Quote expired (quotes are valid for 30 seconds)
  • Missing required payment details (phone_number for mobile money, bank_account_number for bank transfer)
  • payment_method doesn't match the quote
  • payment_rail doesn't match the quote
  • Invalid quote ID

401 – Unauthorized

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid API key"
  }
}

Payment Methods & Required Fields

Different payment methods require different fields:

Bank Transfer

Required fields:

  • bank_account_number - Customer's bank account

Mobile Money

Required fields:

  • phone_number - Customer's mobile money number (with country code)

Cryptocurrency

Required fields:

  • quote_id - Must include wallet details

Optional fields:

  • None (wallet address is in quote)

Important Notes

Quote Requirement

Unlike standard checkout, whitelabel checkout requires a valid quote:

  • Quotes expire after 30 seconds
  • If quote expires, you'll get a 400 error
  • Generate a new quote and retry

Why? Whitelabel checkout needs locked-in rates and payment details from the quote.

Payment Reconciliation

Payments are reconciled using the provider_reference (transaction reference):

  • Customer must include this reference when making payment
  • Without the reference, payment may be delayed or lost
  • Display the reference prominently in your UI

Status Updates

The initial status is usually PENDING or AWAITING_PAYMENT:


Handling Different Payment Flows

Flow 1: Immediate Payment (Mobile Money)

// 1. Create whitelabel checkout
const payment = await createWhitelabelCheckout({
  payment_method: 'mobile_money',
  phone_number: '+233200123456',
  // ...
});

// 2. Customer receives mobile money prompt on their phone
// 3. Customer approves payment on their phone
// 4. You receive webhook notification
// 5. Update your UI based on webhook

Flow 2: Manual Transfer (Bank Transfer)

// 1. Create whitelabel checkout
const payment = await createWhitelabelCheckout({
  payment_method: 'bank_transfer',
  bank_account_number: '0123456789',
  // ...
});

// 2. Display bank account details to customer
displayBankDetails({
  bankName: payment.payment_instructions.bank_name,
  accountNumber: payment.payment_instructions.account_number,
  reference: payment.payment_instructions.reference,
  amount: payment.amount
});

// 3. Customer makes manual bank transfer
// 4. Payment is detected and processed
// 5. You receive webhook notification
// 6. Update customer's order status

Flow 3: Crypto Payment

// 1. Create whitelabel checkout
const payment = await createWhitelabelCheckout({
  payment_method: 'crypto',
  // ...
});

// 2. Display wallet address and amount
displayCryptoPayment({
  address: payment.payment_instructions.wallet_address,
  amount: payment.payment_instructions.amount,
  currency: payment.payment_instructions.currency,
  network: payment.payment_instructions.network
});

// 3. Customer sends crypto to address
// 4. Blockchain confirms transaction
// 5. You receive webhook notification

Testing

Test Mode Behavior

In test mode (sk_test_...):

  • Whitelabel checkouts are created successfully
  • Payment instructions are returned (simulated)
  • Webhook events are still sent for testing

Simulating Payment Success

To test successful payments in test mode:

  1. Create whitelabel checkout
  2. Note the charge_id
  3. Contact support to manually mark as paid (for testing)
  4. Or wait for webhook test events

Comparison: Standard vs Whitelabel Checkout

Feature Standard Checkout Whitelabel Checkout
UI SyncPay hosted page Your custom UI
Redirect Yes, to SyncPay No redirect
Quote Optional Required
Payment details Collected by SyncPay Collected by you
Branding SyncPay branding Your branding
Mobile apps Web view required Native integration
Complexity Simple Advanced
Best for Quick integration Custom experiences


Next Steps

After creating a whitelabel checkout:

  1. Display payment instructions to your customer
  2. Set up webhooks to receive payment updates automatically
  3. Poll charge status using Get Charge Status if not using webhooks
  4. Handle payment completion in your application logic