@ozura/elements/server is the server-side counterpart to the Elements browser SDK. It wraps the OzuraPay API and Vault API with typed methods, automatic field mapping, retry logic, and error handling.
Next.js / Fetch API users: usecreateSessionHandlerinstead ofcreateSessionMiddleware. Both are exported from the same package. See createSessionHandler below.
ESM vs CJS: The package ships both ESM (Both builds are identical in behaviour — only the module format differs.
import) and CommonJS (require) builds. Code examples throughout use ESM import syntax. If your project uses CommonJS (no "type": "module" in package.json, or a .cjs file), swap to require:Node.js requirement:
@ozura/elements/server requires Node.js ≥ 18. Versions below 18 lack the native fetch API the package depends on.Quick Start
merchantId or apiKey:
Configuration
Tokenize-only integrations (create sessions + tokenize cards, no charging) only need
vaultKey. The merchantId and apiKey fields are validated lazily — they are only required when you call cardSale().Methods
cardSale
Charge a tokenized card. Maps theCardSaleInput shape to the OzuraPay API’s flat field format.
cardSale never retries, regardless of the retries config. Financial POSTs are not idempotent — retrying a failed cardSale could cause a double charge. If you receive a 5xx response, check transaction records before retrying manually.5xx de-duplication pattern. If For stricter de-duplication, pass your own
cardSale throws with a 5xx status, the charge may or may not have been processed — the request could have timed out after the processor accepted it. Before retrying or failing the order, query listTransactions to check for a matching charge:orderId in createSession when creating the session. You can filter listTransactions on a wider window and match by correlating your orderId to the transaction metadata.You can pass
tokenResponse.billing directly from the frontend — the browser SDK validates and normalizes it for you.listTransactions
List transactions by date range with pagination. Returns all transaction types.createSession
Creates a short-lived payment session key from the vault. This is the server-side companion tosessionUrl / getSessionKey on the frontend SDK.
revokeSession
Revoke a payment session key. Best-effort — never throws. Call this on all three session-end paths to close the exposure window before the 30-minute vault TTL elapses. The SDK’s proactive/reactive refresh andsessionLimit are defence-in-depth layers — explicit revocation is the primary closure mechanism.
Persisting session state for cancel/revoke
revokeSession(sessionKey) requires the sessionKey — but the browser SDK never exposes the session key to the page (it is kept inside the vault internals for security). To call revokeSession on cancel, your session route must store the mapping when the session is first created.
The sessionId sent by the browser SDK to your session route is a UUID you can use as the lookup key. Store it server-side (e.g. Redis with the session TTL, a DB row, or an in-memory map for simple cases) when you create the session, then look it up when the cancel route fires.
If you do not need explicit revocation (e.g. tokenize-only flows with no cancel path), you can skip persistence entirely. Sessions expire automatically after their TTL (default 30 minutes). The
sessionId the SDK sends is opaque from the browser’s perspective — it is safe to store as a key.Session Route
ThesessionUrl option in the browser SDK expects your backend to expose a POST /api/oz-session route. The SDK ships two factory functions to make this trivial.
createSessionHandler (Next.js / Fetch API)
Creates a handler for the Web Fetch API (Request → Response). Use with Next.js App Router, Remix, Cloudflare Workers, etc.
sessionId from the JSON body (sent automatically by the SDK), calls ozura.createSession(), and responds:
The Elements SDK reads
sessionKey from the 200 response. Any non-200 response causes OzVault.create() to reject with the error field as the message.
createSessionMiddleware (Express / Connect)
Creates an Express-style middleware ((req, res) => void). Requires express.json() (or equivalent body-parser) to be registered before it. The middleware expects req.body.sessionId as a string — any standard JSON body-parser that populates req.body works.
createSessionHandler above: { sessionKey } on success, { error } on failure.
Card Sale Handler Factories
For backends where a dedicated route fully owns the card sale flow (amount from server-side DB, billing from token, IP from request), the SDK ships factory functions that build complete handlers.createCardSaleHandler (Next.js / Fetch API)
createCardSaleMiddleware (Express / Connect)
Both factories also:
- Read
token,cvcSession, andbillingfrom the request body - Reject non-POST methods (
405) and non-JSON content types (415) - Call
getClientIp()to resolve the client IP - On success: return
{ transactionId, amount, cardLastFour, cardBrand } - On OzuraPay API error: return
{ error: string }with the normalized error message and the appropriate HTTP status (4xx/5xx); 429 includes aRetry-Afterheader
Utilities
getClientIp
Extract the client IP address from a server request object. Works across frameworks:What happens if
clientIpAddress is wrong or missing? The OzuraPay API accepts the field without strict validation — it will not reject a cardSale request because the IP is an internal address, 127.0.0.1, or appears blank. The IP is used for fraud scoring and audit logging; an incorrect value weakens fraud detection but does not block the transaction. If getClientIp cannot resolve a real IP (e.g. headers are absent or your proxy uses a non-standard header), the charge will still proceed — but your fraud risk posture degrades. If you are behind a proxy that uses a custom header, extract the IP manually and pass it as a string rather than relying on getClientIp.Error Handling
All methods throwOzuraError on failure.
OzuraError
Retry behavior
listTransactions and createSession automatically retry on 5xx and network errors with exponential backoff (1 s, 2 s, 4 s…). 4xx errors are never retried.
cardSale is never retried — see note above.
Types
CreateSessionOptions
CreateSessionResult
The deprecated
MintWaxKeyOptions and MintWaxKeyResult types are still exported as aliases to the above for backward compatibility.CardSaleInput
CardSaleResponseData
surchargeAmount and tipAmount are only present in the response when non-zero. Handle missing values defensively:ListTransactionsInput
Transaction Types
TransactionType
Narrowing TransactionData
listTransactions() returns TransactionData — a discriminated union. Use transactionType to narrow:
Field name difference:
cardSale() returns billing fields as billingFirstName, billingLastName, etc. Transaction queries return them as firstName, lastName, etc. The SDK types reflect what each endpoint actually returns.Full Example
Express backend handling a card payment end-to-end:Next Steps
Card Elements
Set up the frontend card fields that produce the tokens this SDK consumes.
Error Handling
Normalize vault and payment errors for your users.
API Reference
Full type definitions for all SDK exports.
Installation
Credentials and OzVault.create() setup.