@myazahq/pos-sdk
v1.0.7
Published
Production-grade crypto POS payment SDK — accepts any crypto token in React, Next.js, Vue, Svelte, or plain JS
Downloads
810
Maintainers
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. init() fetches your merchant profile automatically (name, logo) and 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(); // fetches merchant profile + validates config
// 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 and your merchant name.
- 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
isSandbox: false, // true → use Gridlog sandbox (testing only)
pollIntervalMs: 5_000, // how often to poll for status (default: 5 sec)
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; }',
},
});Merchant name: You do not need to configure your store name. The SDK fetches it automatically from your Gridlog merchant profile during
init()and displays it in the checkout modal header.
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/sdk/pos/sessions/${sessionId}?merchantId=<merchantId>`,
const data = await res.json();
if (data.data.status === 'paid_out') {
await fulfillOrder(data.data.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. Fetches merchant profile. 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
