Package Exports
- @myazahq/pos-sdk
- @myazahq/pos-sdk/webhook
Readme
@myazahq/pos-sdk
Accept crypto payments in your storefront with a single method call — no webhooks, no Web3 setup required. Powered by Gridlog.
Install
npm install @myazahq/pos-sdk
# yarn add @myazahq/pos-sdk
# pnpm add @myazahq/pos-sdkWorks with React, Next.js, Vue, Svelte, Nuxt, Vite, and plain JavaScript.
How it works
new MyazaPOS() → sdk.init() → sdk.checkout()That's the entire integration. checkout() opens a built-in modal that handles network selection, displays a wallet address and QR code, and polls for payment status — all automatically. You just listen for events and fulfil the order.
Quick Start
import { MyazaPOS } from '@myazahq/pos-sdk';
const sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
await sdk.init();
// Listen for the payment you care about
sdk.on('payment.confirmed', ({ session }) => {
fulfillOrder(session.id);
});
// Open the full checkout UI — one line
await sdk.checkout({ amount: 5000, currency: 'NGN' });SSR frameworks (Next.js, Nuxt): The SDK manipulates the DOM and must only run in the browser. Wrap it in
useEffect(React) oronMounted(Vue) — see Framework Examples.
sdk.checkout() — Start here
checkout() is the primary method. Call it when your customer clicks "Pay". It handles the full payment flow end-to-end:
- Fetches supported networks in the background (the modal opens instantly while this loads).
- Shows a network & token selector modal, pre-filled with the amount.
- Once the customer confirms, transitions to the payment modal — wallet address, QR code, live countdown.
- Polls for payment status and fires events at every stage.
- Closes itself on success, failure, or cancellation.
// Minimal — shows the full network/token selector
await sdk.checkout({ amount: 5000, currency: 'NGN' });
// With bank payout — Gridlog sends fiat to this account after payment
await sdk.checkout({
amount: 5000,
currency: 'NGN',
payoutAccountNumber: '0123456789',
payoutNetworkId: 'bank-network-uuid', // from sdk.getBanks()
});Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
amount |
number |
required | Fiat amount (e.g. 5000). |
currency |
string |
'NGN' |
Fiat currency code. |
payoutAccountNumber |
string |
— | Bank account for fiat payout after payment. |
payoutNetworkId |
string |
— | Bank network ID from getBanks(). Required when payoutAccountNumber is set. |
Returns null if the customer closes the modal without paying, or a PaymentSession object otherwise.
Payout to a bank account
To route the fiat payout to a specific bank account, look up the bank and verify the account number first:
// 1. List banks that support NGN payouts
const banks = await sdk.getBanks('NGN');
// → [{ id, name, networkId, currency, country, available }, ...]
// 2. Confirm the account holder before charging the customer
const account = await sdk.resolveAccount(banks[0].networkId, '0123456789');
if (!account.matched) {
// Account not found — show an error to the user
return;
}
console.log('Account holder:', account.accountName); // "John Doe"
// 3. Pass verified details into checkout
await sdk.checkout({
amount: 5000,
currency: 'NGN',
payoutAccountNumber: account.accountNumber,
payoutNetworkId: account.networkId,
});Both payoutAccountNumber and payoutNetworkId are optional, but they must be provided together — one without the other will be rejected.
Events
Register handlers with sdk.on() before calling checkout().
sdk.on('payment.created', ({ session }) => {
// Payment session opened — address is ready
console.log('Send', session.token, 'to', session.address);
});
sdk.on('payment.received', ({ sessionId }) => {
// Crypto arrived — payout is processing
});
sdk.on('payment.confirmed', ({ session }) => {
// Payout complete — safe to fulfil the order
fulfillOrder(session.id);
});
sdk.on('payment.failed', ({ sessionId, reason }) => {
console.error('Payment failed:', reason);
});
sdk.on('payment.expired', ({ sessionId }) => {
// Session timed out — customer can try again
});
sdk.on('payment.cancelled', ({ sessionId }) => {
// Customer closed the modal
});Configuration
const sdk = new MyazaPOS({
merchantId: 'YOUR_MERCHANT_ID', // required
merchantName: 'My Store', // shown in the checkout modal header
isSandbox: false, // true → use Gridlog sandbox (testing only)
pollIntervalMs: 120_000, // how often to poll for status (default: 2 min)
maxPollDurationMs: 900_000, // give up polling after this long (default: 15 min)
theme: {
primaryColor: '#6366f1', // buttons and highlights
backgroundColor: '#ffffff', // modal background
textColor: '#1a1a2e', // all text
borderRadius: 12, // corner radius in px
fontFamily: 'Inter, sans-serif',
logoUrl: 'https://your-site.com/logo.png', // must be HTTPS
colorScheme: 'light', // 'light' | 'dark' | 'system'
customCss: '.myaza-cancel-btn { display: none; }',
},
});For advanced config (fraud rules, plugins, multi-tenant, observability) see MAINTAINERS.md.
Sandbox vs Production
// Sandbox — safe for development and testing
const sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID', isSandbox: true });
// Production — the default
const sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });| API base URL | Config | |
|---|---|---|
| Production | https://secureapi.gridlog.io/api/v1 |
isSandbox: false (default) |
| Sandbox | https://sandbox.secureapi.gridlog.io/api/v1 |
isSandbox: true |
| Custom | Your own URL | apiBaseUrl: 'https://...' |
apiBaseUrl takes precedence over isSandbox when both are set.
When isSandbox: true, the SDK logs a warning immediately at construction time so you cannot accidentally ship a sandbox config to production.
Framework Examples
React
import { useEffect, useRef } from 'react';
import { MyazaPOS } from '@myazahq/pos-sdk';
export function PayButton({ amount }: { amount: number }) {
const sdkRef = useRef<MyazaPOS | null>(null);
useEffect(() => {
const sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
sdk.init().then(() => { sdkRef.current = sdk; });
sdk.on('payment.confirmed', ({ session }) => fulfillOrder(session.id));
return () => { void sdk.terminate(); };
}, []);
return (
<button onClick={() => sdkRef.current?.checkout({ amount, currency: 'NGN' })}>
Pay with Crypto
</button>
);
}Next.js (App Router)
'use client';
import { useEffect, useRef } from 'react';
import { MyazaPOS } from '@myazahq/pos-sdk';
export function PayButton({ amount }: { amount: number }) {
const sdkRef = useRef<MyazaPOS | null>(null);
useEffect(() => {
const sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
sdk.init().then(() => { sdkRef.current = sdk; });
return () => { void sdk.terminate(); };
}, []);
return (
<button onClick={() => sdkRef.current?.checkout({ amount, currency: 'NGN' })}>
Pay with Crypto
</button>
);
}For Next.js Pages Router or anywhere you need lazy loading:
const { MyazaPOS } = await import('@myazahq/pos-sdk');Vue 3
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import { MyazaPOS } from '@myazahq/pos-sdk';
const props = defineProps<{ amount: number }>();
let sdk: MyazaPOS | null = null;
onMounted(async () => {
sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
await sdk.init();
sdk.on('payment.confirmed', ({ session }) => fulfillOrder(session.id));
});
onUnmounted(() => { sdk?.terminate(); });
</script>
<template>
<button @click="sdk?.checkout({ amount: props.amount, currency: 'NGN' })">
Pay with Crypto
</button>
</template>Nuxt 3
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import type { MyazaPOS as TSDK } from '@myazahq/pos-sdk';
let sdk: TSDK | null = null;
onMounted(async () => {
const { MyazaPOS } = await import('@myazahq/pos-sdk');
sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
await sdk.init();
});
onUnmounted(() => { sdk?.terminate(); });
</script>Svelte / SvelteKit
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import type { MyazaPOS as TSDK } from '@myazahq/pos-sdk';
export let amount: number;
let sdk: TSDK | null = null;
onMount(async () => {
const { MyazaPOS } = await import('@myazahq/pos-sdk');
sdk = new MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
await sdk.init();
});
onDestroy(() => { sdk?.terminate(); });
</script>
<button on:click={() => sdk?.checkout({ amount, currency: 'NGN' })}>
Pay with Crypto
</button>CDN (no build step)
<script src="https://cdn.jsdelivr.net/npm/@myazahq/pos-sdk/dist/index.umd.js"></script>
<script>
const sdk = new MyazaPOS.MyazaPOS({ merchantId: 'YOUR_MERCHANT_ID' });
sdk.init().then(() => {
document.getElementById('pay-btn').addEventListener('click', () => {
sdk.checkout({ amount: 5000, currency: 'NGN' });
});
sdk.on('payment.confirmed', ({ session }) => {
window.location.href = '/order-complete?id=' + session.id;
});
});
</script>Server-Side Verification
Always verify payment status from your server before fulfilling an order. Never trust client-side events alone.
// Your backend — keep the Bearer token server-side only
const res = await fetch(`https://secureapi.gridlog.io/api/v1/pos/sessions/${sessionId}`, {
headers: { Authorization: `Bearer YOUR_GRIDLOG_BEARER_TOKEN` },
});
const session = await res.json();
if (session.status === 'paid_out') {
await fulfillOrder(session.id);
}Store your Bearer token in a secret manager (e.g. AWS Secrets Manager, Doppler) — never expose it in client-side code or commit it to source control.
All SDK Methods
| Method | Returns | Description |
|---|---|---|
sdk.init() |
Promise<this> |
Initialise the SDK. Call once before anything else. |
sdk.checkout(params) |
Promise<PaymentSession | null> |
Start here. Opens the full checkout UI. |
sdk.createSession(params) |
Promise<PaymentSession> |
Low-level. Opens the payment modal directly when you already know the chain and token. Requires chain and token. |
sdk.getBanks(currency) |
Promise<Bank[]> |
List banks available for fiat payout (e.g. 'NGN'). |
sdk.resolveAccount(networkId, accountNumber) |
Promise<BankAccountResolution> |
Confirm an account holder name before charging. |
sdk.getNetworks() |
Promise<SupportedNetwork[]> |
List supported blockchains and tokens. |
sdk.getExchangeRate(currency, coin) |
Promise<ExchangeRate> |
Current exchange rate for a currency/token pair. |
sdk.on(event, handler) |
this |
Subscribe to an SDK event. |
sdk.once(event, handler) |
this |
Subscribe once — unsubscribes automatically after firing. |
sdk.off(event, handler) |
this |
Unsubscribe. |
sdk.use(plugin) |
this |
Register a plugin at runtime. |
sdk.registerMerchant(config) |
this |
Register a merchant for multi-tenant operation. |
sdk.getState() |
SDKState |
Current state machine state. |
sdk.terminate() |
Promise<void> |
Clean shutdown — cancels session, closes modal, uninstalls plugins. |
Maintainers
Architecture details, plugin authoring, fraud config, multi-tenant setup, CI/CD, and build instructions: MAINTAINERS.md.
Licence
MIT © Myaza