JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 36
  • Score
    100M100P100Q94792F
  • License MIT

Production-grade crypto POS payment SDK — accepts any crypto token in React, Next.js, Vue, Svelte, or plain JS

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-sdk

Works 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) or onMounted (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:

  1. Fetches supported networks in the background (the modal opens instantly while this loads).
  2. Shows a network & token selector modal, pre-filled with the amount, your merchant name, and a live exchange rate for each token.
  3. Once the customer confirms, transitions to the payment modal — wallet address, QR code, live countdown.
  4. Polls for payment status and fires events at every stage.
  5. Closes itself on success, failure, or cancellation.

You can call checkout() (or createSession()) multiple times on the same SDK instance — no page reload or re-initialisation required. Each call resets the payment state automatically.

// 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