mayarin

TypeScript quickstart

Create a payment link from a server using the existing @mayarin/sdk package.

Install

bun add @mayarin/sdk

Use the server entry point with a secret key minted from the Mayarin dashboard — dashboard-testnet.mayarin.xyz for testnet, dashboard.mayarin.xyz for mainnet, under API keys. See getting a key. Never place an sk_ key in a browser bundle.

Create a client

import { createMayarin } from "@mayarin/sdk";

const secretKey = process.env.MAYARIN_SECRET_KEY;
if (secretKey === undefined) {
  throw new Error("MAYARIN_SECRET_KEY is required");
}

const mayarin = createMayarin({
  baseUrl: "https://api.mayarin.xyz",
  secretKey,
});
const link = await mayarin.commerce.paymentLinks.create({
  kind: "fixed",
  merchant: {
    id: "merchant_123",
    name: "Northwind Coffee",
    city: "Singapore",
    countryCode: "SG",
  },
  amount: { amount: "18.50", asset: "SGD" },
});

console.log(link.url);

Redirect the buyer to link.url. The hosted checkout owns asset selection, wallet interaction or deposit instructions, and live payment status.

Idempotency

The SDK generates an Idempotency-Key for every write. When your system already has a stable order identifier, pass it explicitly:

const link = await mayarin.commerce.paymentLinks.create(input, {
  idempotencyKey: "order-4711",
});

Reusing the key with the same request returns the original result. Reusing it with different parameters returns a conflict.

Handle errors

import { isMayarinApiError } from "@mayarin/sdk";

try {
  await mayarin.payment.get("pi_01KZ...");
} catch (error) {
  if (isMayarinApiError(error) && error.retryable) {
    // Retry with bounded backoff.
  }
  throw error;
}

Every SDK failure is a MayarinApiError with a stable code, HTTP status, and retryable flag — see errors and retries for every code.

A complete integration

apps/demo is this quickstart grown into a working storefront: catalog seeding, a thin server holding the secret key, link minting with a deterministic idempotency key, a verified webhook endpoint, and a status page. It runs against a local API or the hosted testnet.