{"_id":"@banxa-official/javascript-native-payments-sdk","_rev":"2-125530b8f4813633d28cf538efa0f3b0","name":"@banxa-official/javascript-native-payments-sdk","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@banxa-official/javascript-native-payments-sdk","version":"1.0.0","keywords":["banxa","payments","crypto","web-components","typescript"],"author":{"name":"Banxa"},"license":"MIT","_id":"@banxa-official/javascript-native-payments-sdk@1.0.0","maintainers":[{"name":"banxasystem","email":"system@banxa.com"}],"dist":{"shasum":"3ca7f7642a7b25f9770fa74f6031a26f04ed94b0","tarball":"https://registry.npmjs.org/@banxa-official/javascript-native-payments-sdk/-/javascript-native-payments-sdk-1.0.0.tgz","fileCount":14,"integrity":"sha512-ZH/nYbM+XPUKldW0TCHigEFnEvZRiHdjwI2kB5Zhu/l0aC7YQhoS0crg11IEl7OMaygSE9uzXJRiId0G/iJQXQ==","signatures":[{"sig":"MEUCIF51IcgFI/k1GHSyfEwsjXeyhBFvu/LOm4X2b9xPpwKcAiEAk0X1MF8cT21A2UiygcyUDslk5Tb0eF5jY7bmAbAavVQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":257506},"main":"./dist/api.js","types":"./dist/api.d.ts","module":"./dist/api.mjs","exports":{".":{"types":"./dist/api.d.ts","import":"./dist/api.mjs","require":"./dist/api.js"},"./api":{"types":"./dist/api.d.ts","import":"./dist/api.mjs","require":"./dist/api.js"},"./web":{"types":"./dist/web.d.ts","import":"./dist/web.mjs","require":"./dist/web.js"}},"gitHead":"cc0697be9de6e7bc3a97271a23e5532e0af8cdeb","scripts":{"dev":"tsup --watch","lint":"eslint src","test":"vitest","build":"tsup","format":"prettier --write \"src/**/*.ts\"","test:run":"npm run build && vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check \"src/**/*.ts\""},"_npmUser":{"name":"banxasystem","email":"system@banxa.com"},"_npmVersion":"11.7.0","description":"TypeScript SDK for Banxa merchant partners to use Primer SDK for native payments","directories":{},"sideEffects":["./dist/web.js","./dist/web.mjs"],"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","eslint":"^9.0.0","vitest":"^1.2.0","prettier":"^3.0.0","happy-dom":"^20.9.0","@eslint/js":"^9.0.0","typescript":"^5.3.3","@types/node":"^20.11.0","@primer-io/primer-js":"^1.3.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"@primer-io/primer-js":"^1.3.0"},"peerDependenciesMeta":{"@primer-io/primer-js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/javascript-native-payments-sdk_1.0.0_1783486548464_0.48724124967950644","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@banxa-official/javascript-native-payments-sdk","version":"1.0.1","description":"TypeScript SDK for Banxa merchant partners to use Primer SDK for native payments","main":"./dist/api.js","module":"./dist/api.mjs","types":"./dist/api.d.ts","sideEffects":["./dist/web.js","./dist/web.mjs"],"exports":{".":{"types":"./dist/api.d.ts","import":"./dist/api.mjs","require":"./dist/api.js"},"./api":{"types":"./dist/api.d.ts","import":"./dist/api.mjs","require":"./dist/api.js"},"./web":{"types":"./dist/web.d.ts","import":"./dist/web.mjs","require":"./dist/web.js"}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest","test:run":"npm run build && vitest run","typecheck":"tsc --noEmit","lint":"eslint src","format":"prettier --write \"src/**/*.ts\"","format:check":"prettier --check \"src/**/*.ts\""},"keywords":["banxa","payments","crypto","web-components","typescript"],"author":{"name":"Banxa"},"license":"MIT","peerDependencies":{"@primer-io/primer-js":"^1.3.0"},"peerDependenciesMeta":{"@primer-io/primer-js":{"optional":true}},"devDependencies":{"@eslint/js":"^9.0.0","@primer-io/primer-js":"^1.3.0","@types/node":"^20.11.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","eslint":"^9.0.0","happy-dom":"^20.9.0","prettier":"^3.0.0","tsup":"^8.0.1","typescript":"^5.3.3","vitest":"^1.2.0"},"gitHead":"a91d570d679e096e6cd031230594d4ef5e3da21c","_id":"@banxa-official/javascript-native-payments-sdk@1.0.1","_nodeVersion":"23.9.0","_npmVersion":"11.7.0","dist":{"integrity":"sha512-hsXN2j5KZqueo5KmUPyg/bdI4U4hXJcfbJjNfA+L9UV89Sk7l6OEFDylibXqwQmj9avJmhDSZfnfdmGwp7x94w==","shasum":"a5e16e6cc39cb23e7ae1f9efc843df613f24a36e","tarball":"https://registry.npmjs.org/@banxa-official/javascript-native-payments-sdk/-/javascript-native-payments-sdk-1.0.1.tgz","fileCount":14,"unpackedSize":261468,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDjB52qOlLVDVQgphLnCTslrSQh4T8gLIhN1COC2KaMvAiB1o4Ex+E06N8irFw/hNekCpxZ8EAUB6bTUO9htSIGZrA=="}]},"_npmUser":{"name":"banxasystem","email":"system@banxa.com"},"directories":{},"maintainers":[{"name":"banxasystem","email":"system@banxa.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/javascript-native-payments-sdk_1.0.1_1785374546588_0.5007653377601895"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-08T04:55:48.264Z","modified":"2026-07-30T01:22:26.936Z","1.0.0":"2026-07-08T04:55:48.602Z","1.0.1":"2026-07-30T01:22:26.734Z"},"author":{"name":"Banxa"},"license":"MIT","keywords":["banxa","payments","crypto","web-components","typescript"],"description":"TypeScript SDK for Banxa merchant partners to use Primer SDK for native payments","maintainers":[{"name":"banxasystem","email":"system@banxa.com"}],"readme":"# Banxa Native Payments SDK\n\nA TypeScript SDK for Banxa merchant partners integrating [Primer](https://primer.io) native payments. It provides a **Node-safe REST client** for the Banxa v2 API and **browser web components** for native Primer checkout and hosted Banxa checkout.\n\n## Features\n\n- **Backend API client** (`BanxaApiClient`) — Node-safe; no DOM or web component code on import\n- **Native checkout** (`<banxa-primer-checkout>`) — configurable Primer checkout layouts\n- **Hosted checkout** (`<banxa-hosted-checkout>`) — iframe fallback when native payments are not ready\n- **Buy flow helper** (`runBuyCheckoutFlow`) — eligibility check, order creation, and automatic UI selection\n- **x-api-key authentication** for all Banxa API requests\n- **TypeScript** types for Banxa API and Primer checkout\n- **Dual module output** (ESM + CJS) with separate `/api` and `/web` entry points\n\n## Installation\n\n```bash\nnpm install @banxa/native-payments-sdk\n```\n\nFor the checkout web component, install the Primer peer dependency:\n\n```bash\nnpm install @primer-io/primer-js\n```\n\n## Entry points\n\n| Import | Environment | Exports |\n|--------|-------------|---------|\n| `@banxa/native-payments-sdk` | Node / server | Same as `/api` |\n| `@banxa/native-payments-sdk/api` | Node / server | `BanxaApiClient`, `BanxaApiError`, Banxa API types |\n| `@banxa/native-payments-sdk/web` | Browser | `registerBanxaCheckout`, `registerBanxaPrimerCheckout`, `registerBanxaHostedCheckout`, `BanxaPrimerCheckout`, `BanxaHostedCheckout`, `runBuyCheckoutFlow`, `loadPrimerSdk`, `isPrimerLoaded`, `DEFAULT_CARD_FORM_HTML`, `PrimerPaymentMethodTypes`, checkout + Primer types |\n\nThe web entry does **not** auto-register custom elements. Call `registerBanxaCheckout()` (or register components individually) before using them in HTML.\n\n## Quick start\n\n### 1. Backend — create an order\n\n```typescript\nimport { BanxaApiClient } from '@banxa/native-payments-sdk';\n\nconst client = new BanxaApiClient({\n  apiKey: process.env.BANXA_API_KEY!,\n  partner: process.env.BANXA_PARTNER!,\n  environment: 'sandbox', // 'sandbox' | 'production'\n});\n\nconst order = await client.createOrder({\n  externalCustomerId: 'user-123',\n  fiat: 'AUD',\n  crypto: 'USDT',\n  fiatAmount: '100', // or cryptoAmount — at least one is required\n  walletAddress: '0x1234567890abcdef...',\n  redirectUrl: 'https://yoursite.com/order-complete',\n  paymentMethodId: 'debit-credit-card', // optional\n  blockchain: 'TRON', // optional\n});\n\n// Native payments: use the Primer token from the create-order response\nconst nativeToken = order.nativeToken;\n```\n\n`createOrder` calls `POST /v2/buy` with camelCase JSON matching the [Banxa v2 buy order API](https://docs.banxa.com/products/hosted-checkout/openapi/other/create-a-buy-order).\n\n### 2. Frontend — render checkout\n\n```html\n<script type=\"module\">\n  import { registerBanxaPrimerCheckout } from '@banxa/native-payments-sdk/web';\n\n  registerBanxaPrimerCheckout();\n</script>\n\n<banxa-primer-checkout id=\"checkout\" locale=\"en\"></banxa-primer-checkout>\n\n<script type=\"module\">\n  const response = await fetch('/api/create-order', { method: 'POST', /* ... */ });\n  const { nativeToken } = await response.json();\n\n  const checkout = document.getElementById('checkout');\n  checkout.clientToken = nativeToken;\n\n  checkout.addEventListener('banxa:payment-success', (event) => {\n    console.log('Payment successful!', event.detail);\n  });\n\n  checkout.addEventListener('banxa:payment-failure', (event) => {\n    console.error('Payment failed:', event.detail);\n  });\n</script>\n```\n\nSet `client-token` via the `clientToken` property (or attribute) after your backend returns `nativeToken` from `createOrder`.\n\n## API reference\n\n### `BanxaApiClient`\n\n```typescript\nclass BanxaApiClient {\n  constructor(config: {\n    apiKey: string;\n    partner: string;\n    environment: 'sandbox' | 'staging' | 'production';\n  });\n\n  // GET /fiats/{orderType} + GET /crypto/{orderType} (default orderType: 'buy')\n  getCurrencies(orderType?: 'buy' | 'sell'): Promise<CurrencyResponse>;\n  getFiatCurrencies(orderType?: 'buy' | 'sell'): Promise<FiatCurrency[]>;\n  getCryptoCurrencies(orderType?: 'buy' | 'sell'): Promise<CryptoCurrency[]>;\n\n  // GET /countries\n  getCountries(): Promise<Country[]>;\n\n  // GET /payment-methods?…\n  getPaymentMethods(source?: string, target?: string, country?: string): Promise<PaymentMethodResponse>;\n\n  // GET /quotes/{orderType}?…\n  getQuote(request: QuoteRequest, orderType?: 'buy' | 'sell'): Promise<Quote>;\n\n  // POST /eligibility (same body as POST /buy + orderTypeId)\n  checkOrderEligibility(request: CreateOrderRequest, orderType?: 'buy' | 'sell'): Promise<OrderEligibilityResponse>;\n\n  // POST /buy\n  createOrder(request: CreateOrderRequest): Promise<Order>;\n\n  // GET /orders/{orderId}\n  getOrder(orderId: string): Promise<Order>;\n}\n```\n\nAPI failures throw `BanxaApiError` with `statusCode`, optional `responseBody`, and optional `errors` (`BanxaApiErrorItem[]`).\n\n### `CreateOrderRequest`\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `externalCustomerId` | Yes | Your customer reference (same value as identity/eligibility flows) |\n| `fiat` | Yes | Fiat currency code (e.g. `AUD`, `USD`) |\n| `crypto` | Yes | Crypto currency code (e.g. `USDT`, `BTC`) |\n| `walletAddress` | Yes | Customer wallet address |\n| `redirectUrl` | Yes | URL after checkout completes, fails, or is cancelled |\n| `fiatAmount` | One of* | Fiat amount to buy |\n| `cryptoAmount` | One of* | Crypto amount to buy |\n| `paymentMethodId` | No | Pre-select payment method (e.g. `debit-credit-card`) |\n| `blockchain` | No | Blockchain network for the crypto token |\n| `walletAddressTag` | No | Memo/tag for wallets that require it |\n| `externalOrderId` | No | Your order reference |\n| `discountCode` | No | Promotion / discount code |\n| `email` | No | Pre-fill customer email |\n| `metadata` | No | Opaque string returned on order lookup |\n| `subPartnerId` | No | Channel identifier (exchange, wallet, web, etc.) |\n\n\\*Provide `fiatAmount` or `cryptoAmount`. If both are set, Banxa uses `cryptoAmount`.\n\n### `OrderEligibilityResponse` (`POST /eligibility`)\n\nUses the same request body as `createOrder` plus `orderTypeId` (`buy` or `sell`). Check `paymentReady` before native Primer checkout — when `false`, use hosted checkout (`checkoutUrl`) instead.\n\n| Field | Description |\n|-------|-------------|\n| `eligible` | Whether the order context is eligible |\n| `paymentReady` | When `true`, customer can use native Primer checkout |\n| `requirements` | Outstanding KYC/compliance requirements (when not payment-ready) |\n| `message` | Optional human-readable detail |\n\n### `QuoteRequest`\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `fiat` | Yes | Fiat currency code |\n| `crypto` | Yes | Crypto currency code |\n| `blockchain` | Yes | Blockchain network |\n| `paymentMethodId` | Yes | Payment method ID |\n| `fiatAmount` | One of* | Fiat amount |\n| `cryptoAmount` | One of* | Crypto amount |\n| `externalCustomerId` | No | Customer reference for pricing |\n| `ipAddress` | No | User IP for geo validation |\n| `discountCode` | No | Discount code |\n\n### `Order` (create-order response)\n\nCommon fields from `POST /buy`:\n\n| Field | Description |\n|-------|-------------|\n| `id` | Banxa order ID |\n| `nativeToken` | Primer client token for `<banxa-primer-checkout>` (native payments) |\n| `checkoutUrl` | Hosted checkout URL (when not using native Primer flow) |\n| `fiat`, `fiatAmount`, `crypto`, `cryptoAmount`, `blockchain` | Order amounts and assets |\n| `externalCustomerId`, `externalId` | Customer / external references |\n\n`getOrder` may also return legacy snake_case fields (`status`, `source`, `target`, etc.).\n\n### Currency types (v2)\n\n`FiatCurrency`: `id`, `description`, `symbol`, optional `supportedPaymentMethods`\n\n`CryptoCurrency`: `id`, `description`, optional `blockchains`\n\n## Web component\n\n### Registration\n\n```typescript\nimport { registerBanxaCheckout } from '@banxa/native-payments-sdk/web';\n\nregisterBanxaCheckout(); // registers <banxa-primer-checkout> and <banxa-hosted-checkout>\n```\n\nOr register individually:\n\n```typescript\nimport { registerBanxaPrimerCheckout, registerBanxaHostedCheckout } from '@banxa/native-payments-sdk/web';\n```\n\n### Eligibility-aware buy flow\n\nWhen `checkOrderEligibility` returns `paymentReady: false`, use hosted checkout in an iframe instead of native Primer. `runBuyCheckoutFlow` handles this automatically:\n\n```typescript\nimport { BanxaApiClient } from '@banxa/native-payments-sdk';\nimport { runBuyCheckoutFlow } from '@banxa/native-payments-sdk/web';\n\nconst client = new BanxaApiClient({ apiKey, partner, environment: 'sandbox' });\nconst container = document.getElementById('checkout')!;\n\nconst { mode, order, element } = await runBuyCheckoutFlow({\n  client,\n  request: {\n    externalCustomerId: 'user-123',\n    fiat: 'AUD',\n    crypto: 'USDT',\n    fiatAmount: '100',\n    walletAddress: '0xabc',\n    redirectUrl: `${window.location.origin}/checkout/return`,\n    paymentMethodId: 'debit-credit-card',\n  },\n  container,\n});\n\nif (mode === 'primer') {\n  element.addEventListener('banxa:payment-success', () => { /* ... */ });\n} else {\n  element.addEventListener('banxa:checkout-success', () => { /* hosted iframe completed */ });\n}\n```\n\n| `paymentReady` | `nativeToken` | Result |\n|----------------|---------------|--------|\n| `true` | present | `<banxa-primer-checkout>` (native Primer) |\n| `false` or no token | `checkoutUrl` present | `<banxa-hosted-checkout>` (iframe) |\n\n`runBuyCheckoutFlow` options:\n\n| Option | Description |\n|--------|-------------|\n| `skipEligibilityCheck` | Skip `POST /eligibility` and assume payment-ready |\n| `primerCheckoutOptions` | Pass-through for `locale`, `merchantDomain`, `layoutMode`, `checkoutLayout`, `checkoutTemplate`, `loaderDisabled`, `customStyles` on native checkout |\n\nUse the same `redirectUrl` on your checkout page origin so the iframe can detect return navigation when Banxa redirects after KYC or payment.\n\n### `<banxa-primer-checkout>`\n\n| Attribute | Description |\n|-----------|-------------|\n| `client-token` | **Required.** Primer client token (`order.nativeToken` from `createOrder`) |\n| `locale` | Locale string (e.g. `en`) |\n| `merchant-domain` | Merchant domain passed to Primer as `options.merchantDomain` |\n| `layout-mode` | `preset` (default), `auto`, or `custom` |\n| `payment-methods` | Comma-separated Primer types for preset mode (e.g. `PAYMENT_CARD,APPLE_PAY`) |\n| `loader-disabled` | Disable the loading placeholder |\n| `custom-styles` | CSS string injected into the component shadow root |\n\n### Properties\n\n| Property | Description |\n|----------|-------------|\n| `clientToken` | Get/set `client-token` attribute |\n| `locale` | Get/set locale |\n| `merchantDomain` | Get/set `merchant-domain` attribute |\n| `layoutMode` | Get/set `layout-mode` |\n| `paymentMethods` | Get/set `payment-methods` |\n| `checkoutLayout` | Programmatic `CheckoutLayoutConfig` (merged with attributes) |\n| `checkoutTemplate` | Raw HTML for custom layout mode |\n| `loaderDisabled` | Get/set loading placeholder |\n| `customStyles` | Get/set custom CSS |\n\n### Methods\n\n| Method | Description |\n|--------|-------------|\n| `refreshSession()` | Delegates to Primer `primerJS.refreshSession()` when available |\n\n### Events\n\nPrimer events are re-emitted on the host element with a `banxa:` prefix:\n\n| Event | Description |\n|-------|-------------|\n| `banxa:ready` | Checkout ready |\n| `banxa:payment-start` | Payment started |\n| `banxa:payment-success` | Payment succeeded |\n| `banxa:payment-failure` | Payment failed |\n| `banxa:payment-cancel` | Payment cancelled |\n| `banxa:state-change` | Primer SDK state changed |\n| `banxa:methods-update` | Available payment methods updated |\n| `banxa:card-success` / `banxa:card-error` | Card validation events |\n| `banxa:bin-data-available` / `banxa:bin-data-loading-change` | Card BIN lookup events |\n| `checkout-error` | SDK failed to load or initialize (not prefixed) |\n\nEvent `detail` objects are sanitized for JSON serialization (DOM nodes and circular references are replaced with string placeholders).\n\nUse native `addEventListener` on the element.\n\n### Layout modes\n\n| Mode | Behavior |\n|------|----------|\n| `preset` (default) | Builds markup from `paymentMethods` (default: card + Apple Pay). Card payments use a standalone `<primer-card-form>` with slotted fields from `DEFAULT_CARD_FORM_HTML`. |\n| `auto` | Omits the payments slot so Primer renders all session payment methods. |\n| `custom` | Uses `checkoutTemplate`, `checkoutLayout.mainHtml`, or a `<template slot=\"checkout-layout\">` child for full control. |\n\nPreset mode renders each configured method individually when a card is included (so the card form markup is applied). When no card is present and all entries are simple presets, a `<primer-payment-method-container>` is used instead.\n\nCustom card forms (`cardFormHtml`) must use Primer hosted input components only — raw HTML inputs cannot host PCI card data. In preset mode, `cardFormHtml` is ignored with a console warning; use `custom` layout mode or the checkout-layout slot instead.\n\n### Layout example\n\n```typescript\nimport { registerBanxaPrimerCheckout, PrimerPaymentMethodTypes } from '@banxa/native-payments-sdk/web';\n\nregisterBanxaPrimerCheckout();\n\nconst checkout = document.querySelector('banxa-primer-checkout');\ncheckout.checkoutLayout = {\n  mode: 'preset',\n  paymentMethods: [\n    { type: PrimerPaymentMethodTypes.PAYMENT_CARD },\n    { type: PrimerPaymentMethodTypes.APPLE_PAY },\n  ],\n};\n```\n\nOr supply a full template via the checkout-layout slot:\n\n```html\n<banxa-primer-checkout client-token=\"…\">\n  <template slot=\"checkout-layout\">\n    <primer-checkout>\n      <primer-main slot=\"main\">\n        <div slot=\"payments\"><!-- your Primer markup --></div>\n      </primer-main>\n    </primer-checkout>\n  </template>\n</banxa-primer-checkout>\n```\n\n### `<banxa-hosted-checkout>`\n\nEmbeds Banxa hosted checkout (`order.checkoutUrl`) in an iframe. Use when eligibility is not payment-ready or when the order has no `nativeToken`.\n\n| Attribute | Description |\n|-----------|-------------|\n| `checkout-url` | **Required.** Hosted checkout URL from `createOrder` |\n| `return-url` | Redirect URL base for success, failure, and cancel detection |\n| `return-url-success` | Optional override for success detection |\n| `return-url-failure` | Optional override for failure detection |\n| `return-url-cancelled` | Optional override for cancel detection |\n| `iframe-title` | Accessible iframe title (default: `Banxa checkout`) |\n| `custom-styles` | CSS injected into the shadow root |\n\n| Event | Description |\n|-------|-------------|\n| `banxa:checkout-success` | Iframe navigated to return success URL |\n| `banxa:checkout-failure` | Iframe navigated to return failure URL |\n| `banxa:checkout-cancelled` | Iframe navigated to return cancel URL |\n\n## Complete integration example\n\n```typescript\n// server.ts\nimport express from 'express';\nimport { BanxaApiClient } from '@banxa/native-payments-sdk';\n\nconst app = express();\napp.use(express.json());\n\nconst banxa = new BanxaApiClient({\n  apiKey: process.env.BANXA_API_KEY!,\n  partner: process.env.BANXA_PARTNER!,\n  environment: 'production',\n});\n\napp.post('/api/create-order', async (req, res) => {\n  const { userId, amount, fiatCurrency, cryptoCurrency, walletAddress } = req.body;\n\n  try {\n    const order = await banxa.createOrder({\n      externalCustomerId: userId,\n      fiat: fiatCurrency,\n      crypto: cryptoCurrency,\n      fiatAmount: amount,\n      walletAddress,\n      paymentMethodId: 'debit-credit-card',\n      redirectUrl: `${process.env.FRONTEND_URL}/order-complete`,\n    });\n\n    res.json({\n      orderId: order.id,\n      nativeToken: order.nativeToken,\n    });\n  } catch (error) {\n    const message = error instanceof Error ? error.message : 'Order creation failed';\n    res.status(500).json({ error: message });\n  }\n});\n```\n\n```html\n<!-- checkout.html -->\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Crypto Checkout</title>\n  <script type=\"module\">\n    import { registerBanxaPrimerCheckout } from '@banxa/native-payments-sdk/web';\n    registerBanxaPrimerCheckout();\n  </script>\n  <style>\n    banxa-primer-checkout {\n      display: block;\n      max-width: 500px;\n      margin: 0 auto;\n    }\n  </style>\n</head>\n<body>\n  <h1>Complete Your Purchase</h1>\n  <banxa-primer-checkout id=\"checkout\" locale=\"en\"></banxa-primer-checkout>\n\n  <script type=\"module\">\n    async function startCheckout() {\n      const response = await fetch('/api/create-order', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({\n          userId: 'user-123',\n          amount: '100',\n          fiatCurrency: 'AUD',\n          cryptoCurrency: 'USDT',\n          walletAddress: '0x...',\n        }),\n      });\n\n      if (!response.ok) throw new Error('Failed to create order');\n\n      const { nativeToken } = await response.json();\n      const checkout = document.getElementById('checkout');\n      checkout.clientToken = nativeToken;\n\n      checkout.addEventListener('banxa:payment-success', () => {\n        window.location.href = '/success';\n      });\n\n      checkout.addEventListener('banxa:payment-failure', (event) => {\n        const detail = event.detail;\n        const message = detail?.error?.message ?? detail?.errorMessage ?? 'Payment failed';\n        alert('Payment failed: ' + message);\n      });\n    }\n\n    startCheckout().catch(console.error);\n  </script>\n</body>\n</html>\n```\n\n## Environment URLs\n\n| Environment | Base URL |\n|-------------|----------|\n| Sandbox | `https://api.banxa-sandbox.com/{partner}/v2` |\n| Production | `https://api.banxa.com/{partner}/v2` |\n\n## Development\n\n```bash\nnpm run build        # Build dist/api.* and dist/web.*\nnpm run typecheck    # TypeScript check\nnpm run test:run     # Build + run tests\nnpm run lint         # ESLint\nnpm run format:check # Prettier\n```\n\nCI runs build, typecheck, lint, format check, and tests on push/PR (see `.github/workflows/ci.yml`).\n\n## License\n\nMIT","readmeFilename":"README.md"}