Skip to main content

npm / yarn

npm install @ozura/elements
Pre-release builds: The staging branch publishes automatically to the next dist-tag on every push. To test unreleased changes before they reach latest:
npm install @ozura/elements@next
The next tag does not affect production installs — npm install @ozura/elements always resolves latest.Frame file sync: @next packages are built with NODE_ENV=staging, which bakes in the staging iframe URL (lively-hill-097170c0f.azurestaticapps.net) as frameBaseUrl. The staging Azure SWA is deployed from the same staging branch push that triggers the npm publish — so the @next SDK and the staging frame files are always in sync.
Then import in your JavaScript or TypeScript:
import { OzVault, OzError, createFetchWaxKey } from '@ozura/elements';
For React components:
import {
  OzElements,
  useOzElements,
  OzCard,
  OzCardNumber,
  OzExpiry,
  OzCvv,
  OzBankCard,
  OzBankAccountNumber,
  OzBankRoutingNumber,
  createFetchWaxKey,
} from '@ozura/elements/react';
@ozura/elements/react requires React 17 or later as a peer dependency. If React is not already in your project, install it first:
npm install react react-dom
For server-side usage (Node.js, Deno, Bun):
import { Ozura, OzuraError, getClientIp, createCardSaleHandler, createMintWaxHandler } from '@ozura/elements/server';

CDN (Script Tag)

The Ozura CDN blocks localhost origins. If you load the CDN script on http://localhost, the browser will reject it with a CORS error (No 'Access-Control-Allow-Origin' header). The CDN is for deployed origins only. See Local Development below.
If you’re not using a bundler, load the UMD build directly from the Ozura CDN:
<script src="https://elements.ozura.com/oz-elements.umd.js"></script>
<script>
  const { OzVault, createFetchWaxKey } = window.OzElements;

  OzVault.create({
    pubKey: 'YOUR_PUB_KEY',
    fetchWaxKey: createFetchWaxKey('/api/mint-wax'),
  }).then(vault => {
    // vault is ready
  });
</script>
Or use the ESM build with a native module script:
<script type="module">
  import { OzVault, createFetchWaxKey } from 'https://elements.ozura.com/oz-elements.esm.js';

  const vault = await OzVault.create({
    pubKey: 'YOUR_PUB_KEY',
    fetchWaxKey: createFetchWaxKey('/api/mint-wax'),
  });
</script>

Local Development

The CDN blocks localhost. For local development you have two options depending on how you load the SDK: If your project uses a bundler (webpack, Vite, Next.js, etc.), @ozura/elements is imported directly from node_modules — no CDN involved, no workaround needed. The iframes load from elements.ozura.com at runtime, but that uses <iframe src> which is not subject to the same CORS restriction.
npm install @ozura/elements

CDN script tag on localhost

If you want to use the CDN <script> tag during local development, you need to serve the SDK file from the same origin as your page. Install the npm package and add a single route to your local server:
app.get('/oz-elements.esm.js', (_, res) =>
  res.sendFile('node_modules/@ozura/elements/dist/oz-elements.esm.js', { root: '.' })
);
Then change the <script src> in your HTML from:
<script src="https://elements.ozura.com/oz-elements.esm.js"></script>
to:
<script src="/oz-elements.esm.js"></script>
The iframes (/frame/tokenizer-frame.js, /frame/element-frame.js) still load from elements.ozura.com — they are fetched via <iframe src>, not fetch, so CORS does not apply.

TypeScript

The package ships with full TypeScript definitions — no @types package needed. Import types directly:
import type {
  OzVault,
  OzElement,
  OzError,
  VaultOptions,
  ElementOptions,
  ElementType,
  BankElementType,
  ElementStyleConfig,
  ElementChangeEvent,
  TokenizeOptions,
  TokenResponse,
  CardMetadata,
  BillingDetails,
  BillingAddress,
  BankTokenizeOptions,
  BankTokenResponse,
  BankAccountMetadata,
  FontSource,
  Appearance,
  AppearanceVariables,
  OzTheme,
  CardSaleRequest,
  CardSaleResponseData,
} from '@ozura/elements';
For server-side code:
import type {
  OzuraConfig,
  MintWaxKeyOptions,
  MintWaxKeyResult,
  CardSaleInput,
  CardSaleHandlerOptions,
  ListTransactionsInput,
  ListTransactionsResult,
} from '@ozura/elements/server';

Pub Key for Local Development

Production pub keys have domain restrictions and will not work on localhost. The vault rejects tokenization requests from unregistered origins. OzVault.create() will fail — and without a try/catch, the failure is silent. Use the test pub key below for all local development.
Use this pub key for local and CI environments:
pk_prod_jys4le1jgncomgda_L8HbeakKLNRWdBXoX5A6QJUYOlhUkNle
This key has no domain restrictions and is safe for localhost. Do not use it with real card data or in production. For a production pub key tied to your domain, contact ammar@ozura.com. Backend credentials for local testing: The test pub key handles frontend tokenization. For a full charge flow on localhost (hitting /api/charge with a real card sale), you need valid vault API key + merchant credentials — these are production credentials. Ozura does not currently offer a separate sandbox environment for charge flows. Contact ammar@ozura.com for guidance on local charge testing.
Production frame versioning: The production npm package (latest) loads iframe frame files from https://elements.ozura.com. These files are updated when main is deployed — all merchants receive the new frames immediately, regardless of which npm version they have installed. Ozura maintains backward compatibility in the frame ↔ SDK postMessage protocol across patch and minor releases. If you need to pin frame behavior, pass an explicit frameBaseUrl pointing to a specific deployment.

Credentials

Which credentials do you need?
GoalRequired credentials
Tokenize card / bank data only (no charging)Vault pub key + Vault API key
Charge cards via OzuraPayAll four credentials
You need credentials from the Ozura Dashboard.
CredentialFormatWhere it livesRequired for
Vault pub keypk_live_… or pk_prod_…Frontend env var (safe to expose)All integrations
Vault API keykey_…Server env var only — never in browserMinting wax keys (all integrations)
Pay API keyak_…Server env var onlyOzuraPay merchants (card charging)
Merchant IDozu_…Server env var onlyOzuraPay merchants (card charging)
If you are not routing payments through OzuraPay you only need the vault pub key (frontend) and vault API key (backend).
The vault API secret must never be sent to the browser. The SDK’s fetchWaxKey mechanism exists specifically so your server can mint a short-lived session credential (wax key) without exposing the secret. See the Server SDK for setup.

Quick Initialization

OzVault.create() is the public factory method — it sets up the vault and calls your fetchWaxKey. It resolves once the wax key is obtained; you can create and mount elements immediately after. The vault is ready to tokenize once onReady fires (or vault.isReady === true).
onReady fires before OzVault.create() resolves. The tokenizer iframe loads concurrently with your fetchWaxKey call, so the callback can fire while await OzVault.create(...) is still pending. At that moment, vault is undefined in the surrounding code. Do not reference vault inside the onReady callback. Declare any readiness flags before calling create() so they are in scope when the callback runs.
Always wrap OzVault.create() in a try/catch. If initialization fails (e.g. pub key blocked, fetchWaxKey threw, backend unreachable) the promise rejects. Without a catch, the failure is a silent unhandled rejection and the fields appear to hang.
import { OzVault, OzError, createFetchWaxKey } from '@ozura/elements';

let vault;
try {
  vault = await OzVault.create({
    pubKey:      'YOUR_PUB_KEY',
    fetchWaxKey: createFetchWaxKey('/api/mint-wax'),
  });
} catch (err) {
  if (err instanceof OzError) {
    // err.errorCode: 'auth' | 'network' | 'timeout' | 'config' | ...
    console.error('Vault init failed:', err.message, err.errorCode);
  }
  // Render a fallback UI — payment fields are not available
  document.getElementById('payment-section').textContent =
    'Payment fields could not load. Please refresh and try again.';
}
createFetchWaxKey(url) is a built-in helper that POSTs { sessionId } to your backend and expects { waxKey } back. See Server SDK — Mint Wax Handler for the matching backend route. createFetchWaxKey is exported from both @ozura/elements and @ozura/elements/react — they are identical re-exports of the same function. Use whichever matches your import context. To write the fetchWaxKey callback manually:
let vault;
try {
  vault = await OzVault.create({
    pubKey: 'YOUR_PUB_KEY',
    fetchWaxKey: async (sessionId) => {
      const res = await fetch('/api/mint-wax', {
        method:  'POST',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify({ sessionId }),
      });
      if (!res.ok) throw new Error(`Mint endpoint returned ${res.status}`);
      const { waxKey } = await res.json();
      return waxKey;
    },
  });
} catch (err) {
  console.error('Vault init failed:', err);
}

OzVault.create() Options

OzVault.create(options: VaultOptions, signal?: AbortSignal): Promise<OzVault>
OptionTypeRequiredDefaultDescription
pubKeystringYour Vault pub key
fetchWaxKey(sessionId: string) => Promise<string>Callback to obtain a session wax key from your backend
frameBaseUrlstringhttps://elements.ozura.comOverride where iframe assets are served from
fontsFontSource[][]Custom web fonts to load inside iframes
appearanceAppearanceGlobal theme and CSS variable overrides
onLoadError() => voidCalled if the vault fails to load within loadTimeoutMs
loadTimeoutMsnumber10000Only relevant when onLoadError is set: ms to wait before calling onLoadError
onWaxRefresh() => voidCalled when the SDK silently re-mints the wax key during a tokenization attempt
onReady() => voidCalled once when the vault is ready (vanilla JS only; in React use useOzElements().ready)
maxTokenizeCallsnumber3Maximum successful createToken calls per wax key before proactive refresh. Must match maxTokenizeCalls in your server-side mintWaxKey call — see Server SDK → mintWaxKey.
Keep maxTokenizeCalls in sync between client and server. If VaultOptions.maxTokenizeCalls on the client differs from the value passed to ozura.mintWaxKey() on your server, the proactive refresh timing will be off. The vault may reject a tokenization attempt before the client expects a refresh, causing a user-visible delay. Both default to 3 — only change one if you change the other.
The optional signal parameter is an AbortSignal for advanced teardown scenarios. The React OzElements provider handles this automatically — vanilla JS integrations rarely need it.

Next Steps

Card Elements

Mount card number, expiry, and CVV fields.

Bank Elements

Mount account number and routing number fields.

React

OzElements provider and pre-built components.

Server SDK

Process payments and query transactions on your backend.