Quick Start
Pick your platform, install two packages (Sanwo core + a provider), and start accepting payments.
Installation & first checkout
Section titled “Installation & first checkout”npm i @sanwohq/web @sanwohq/paystackimport { createSanwo } from "@sanwohq/web";import { paystack } from "@sanwohq/paystack";
const sanwo = createSanwo(paystack({ publicKey: "pk_test_xxx" }));
const result = await sanwo({ amount: 500000, // 5,000.00 NGN in kobo currency: "NGN", customer: { email: "customer@example.com" },});
if (result.status === "successful") { console.log("Payment ref:", result.reference);}npm i @sanwohq/react @sanwohq/paystackimport { SanwoReactProvider, useSanwoCheckout } from "@sanwohq/react";import { paystack } from "@sanwohq/paystack";
// Wrap your appfunction App() { return ( <SanwoReactProvider provider={paystack({ publicKey: "pk_test_xxx" })}> <Checkout /> </SanwoReactProvider> );}
function Checkout() { const checkout = useSanwoCheckout();
const pay = async () => { const result = await checkout({ amount: 500000, currency: "NGN", customer: { email: "customer@example.com" }, });
if (result.status === "successful") { console.log("Payment ref:", result.reference); } };
return <button onClick={pay}>Pay NGN 5,000</button>;}npm i @sanwohq/vue @sanwohq/paystackRegister the plugin in your entry file:
import { createApp } from "vue";import { SanwoPlugin } from "@sanwohq/vue";import { paystackProvider } from "@sanwohq/paystack";import App from "./App.vue";
const app = createApp(App);
app.use(SanwoPlugin, { provider: paystackProvider, publicKey: "pk_test_xxx",});
app.mount("#app");Then use the composable in any component:
<script setup>import { useSanwoCheckout } from "@sanwohq/vue";
const { checkout, isLoading } = useSanwoCheckout();
async function pay() { const result = await checkout({ amount: 500000, currency: "NGN", customer: { email: "customer@example.com" }, });
if (result.status === "successful") { console.log("Payment ref:", result.reference); }}</script>
<template> <button @click="pay" :disabled="isLoading"> {{ isLoading ? "Processing…" : "Pay NGN 5,000" }} </button></template>npm i @sanwohq/svelte @sanwohq/paystackCreate the context in your root layout:
<script> import { createSanwoContext } from "@sanwohq/svelte"; import { paystackProvider } from "@sanwohq/paystack";
createSanwoContext({ provider: paystackProvider, publicKey: "pk_test_xxx", });</script>
<slot />Then use the store in any component:
<script> import { createSanwoCheckout } from "@sanwohq/svelte";
const store = createSanwoCheckout();
async function pay() { const result = await store.checkout({ amount: 500000, currency: "NGN", customer: { email: "customer@example.com" }, });
if (result.status === "successful") { console.log("Payment ref:", result.reference); } }</script>
<button on:click={pay} disabled={$store.isLoading}> {$store.isLoading ? "Processing…" : "Pay NGN 5,000"}</button>npm i @sanwohq/web @sanwohq/paystackAngular uses @sanwohq/web directly — no framework wrapper needed.
import { Component, OnDestroy } from "@angular/core";import { createSanwo, type SanwoInstance } from "@sanwohq/web";import { paystackProvider } from "@sanwohq/paystack";
@Component({ selector: "app-checkout", standalone: true, template: ` <button (click)="pay()" [disabled]="isLoading"> {{ isLoading ? 'Processing…' : 'Pay NGN 5,000' }} </button> `,})export class CheckoutComponent implements OnDestroy { private sanwo: SanwoInstance; isLoading = false;
constructor() { this.sanwo = createSanwo({ provider: paystackProvider, publicKey: "pk_test_xxx", }); }
async pay() { this.isLoading = true; const result = await this.sanwo({ amount: 500000, currency: "NGN", customer: { email: "customer@example.com" }, }); this.isLoading = false;
if (result.status === "successful") { console.log("Payment ref:", result.reference); } }
ngOnDestroy() { this.sanwo.destroy(); }}npm i @sanwohq/react-native @sanwohq/paystackimport { SanwoProvider, useSanwoCheckout } from "@sanwohq/react-native";import { paystack } from "@sanwohq/paystack";
function App() { return ( <SanwoProvider provider={paystack({ publicKey: "pk_test_xxx" })}> <Checkout /> </SanwoProvider> );}
function Checkout() { const checkout = useSanwoCheckout();
const pay = async () => { const result = await checkout({ amount: 500000, currency: "NGN", customer: { email: "customer@example.com" }, });
if (result.status === "successful") { alert(`Paid! Ref: ${result.reference}`); } };
return <Button title="Pay NGN 5,000" onPress={pay} />;}flutter pub add sanwo_flutter sanwo_paystackimport 'package:sanwo_flutter/sanwo_flutter.dart';import 'package:sanwo_paystack/sanwo_paystack.dart';
final sanwo = Sanwo( provider: Paystack(publicKey: 'pk_test_xxx'),);
final result = await sanwo.checkout( CheckoutOptions( amount: 500000, // 5,000.00 NGN in kobo currency: 'NGN', customer: Customer(email: 'customer@example.com'), ),);
if (result.status == CheckoutStatus.successful) { print('Payment ref: ${result.reference}');}Add the Swift package from https://github.com/Sanwohq/ios in Xcode (File > Add Package Dependencies).
import Sanwoimport SanwoPaystack
let sanwo = Sanwo(provider: Paystack(publicKey: "pk_test_xxx"))
let result = try await sanwo.checkout( amount: 500000, // 5,000.00 NGN in kobo currency: "NGN", customer: Customer(email: "customer@example.com"))
switch result.status {case .successful: print("Payment ref: \(result.reference)")case .cancelled: print("User cancelled")case .failed(let error): print("Failed: \(error)")case .pending: print("Pending: \(result.reference)")}Add JitPack to your settings.gradle.kts:
dependencyResolutionManagement { repositories { maven { url = uri("https://jitpack.io") } }}Add the dependency:
implementation("com.github.Sanwohq.android:sanwo:1.0.0")import com.sanwohq.android.Sanwoimport com.sanwohq.android.paystack.Paystack
val sanwo = Sanwo(provider = Paystack(publicKey = "pk_test_xxx"))
val result = sanwo.checkout( amount = 500000, // 5,000.00 NGN in kobo currency = "NGN", customer = Customer(email = "customer@example.com"))
when (result.status) { Status.SUCCESSFUL -> println("Payment ref: ${result.reference}") Status.CANCELLED -> println("User cancelled") Status.FAILED -> println("Failed: ${result.error}") Status.PENDING -> println("Pending: ${result.reference}")}composer require sanwohq/laravelPublish the config and set your keys in .env:
php artisan vendor:publish --tag=sanwo-configSANWO_PROVIDER=paystackSANWO_PUBLIC_KEY=pk_test_xxxSANWO_CURRENCY=NGNAdd the script tag to your layout, then use the checkout component or the programmatic API:
<x-sanwo-scripts />
<button id="pay-btn">Pay NGN 5,000</button>
<script> var sanwo = Sanwo.create({ provider: 'paystack', publicKey: '{{ env("SANWO_PUBLIC_KEY") }}', });
document.getElementById('pay-btn').addEventListener('click', async function() { var result = await sanwo.checkout({ amount: 500000, currency: 'NGN', customer: { email: 'customer@example.com' }, });
if (result.status === 'successful') { console.log('Payment ref:', result.reference); } });</script>dotnet add package SanwoRegister Sanwo in Program.cs:
builder.Services.AddSanwo(options =>{ options.Provider = "paystack"; options.PublicKey = "pk_test_xxx"; options.Currency = "NGN";});Add @addTagHelper *, Sanwo to _ViewImports.cshtml, then add the script tag to your layout and use the programmatic API:
<sanwo-scripts />
<button id="pay-btn">Pay NGN 5,000</button>
<script> var sanwo = Sanwo.create({ provider: 'paystack', publicKey: '@Configuration["Sanwo:PublicKey"]', });
document.getElementById('pay-btn').addEventListener('click', async function() { var result = await sanwo.checkout({ amount: 500000, currency: 'NGN', customer: { email: 'customer@example.com' }, });
if (result.status === 'successful') { console.log('Payment ref:', result.reference); } });</script>CheckoutOptions
Section titled “CheckoutOptions”All platforms share the same checkout options:
| Field | Type | Required | Description |
|---|---|---|---|
amount |
number |
Yes | Amount in minor units (kobo, cents, paise). 500000 = 5,000.00 NGN. |
currency |
string |
Yes | ISO 4217 currency code ("NGN", "USD", "INR", etc.). |
customer |
{ email: string } |
Yes | Customer info. email is always required. |
reference |
string |
No | Your own transaction reference. Sanwo generates one if omitted. |
metadata |
Record<string, unknown> |
No | Arbitrary key-value data passed through to the provider. |
description |
string |
No | Human-readable description of the charge. |
sanwoProviderOptions |
object |
No | Provider-specific overrides. Escape hatch for options Sanwo doesn’t abstract. |
CheckoutResult
Section titled “CheckoutResult”The result is a discriminated union on status:
// Payment succeeded{ status: "successful", reference: string, providerResponse: unknown }
// User closed the checkout{ status: "cancelled" }
// Something went wrong{ status: "failed", error: string }
// Payment initiated but not yet confirmed (e.g. bank transfer){ status: "pending", reference: string }Always check result.status before accessing other fields.
Next steps
Section titled “Next steps”- Choose a provider to see supported regions, currencies, and payment methods.
- Explore your platform’s SDK guide under SDKs in the sidebar for advanced usage.