@tender-cash/js-sdk
v1.0.0
Published
[](https://badge.fury.io/js/%40tender-cash%2Fjs-sdk) [](https://opensource.org/licenses/MIT)
Readme
@tender-cash/js-sdk
React SDK for integrating Tender Cash checkout in your app.
Packaging Contract
The package ships with explicit dual-module exports and generated types:
import->dist/index.mjsrequire->dist/index.cjstypes->dist/types/index.d.ts
This contract is enforced by release validation (check:package-shape) before publish.
Installation
Using yarn:
yarn add @tender-cash/js-sdkUsing npm:
npm install @tender-cash/js-sdkExports
TenderSdk(recommended component)TenderAgentSdk(deprecated alias ofTenderSdk)TenderProps(recommended props type)TenderAgentProps(deprecated alias ofTenderProps)TenderRef(recommended ref type)TenderAgentRef(deprecated alias ofTenderRef)onFinishResponse
Quick Start
Use TenderSdk (recommended).TenderAgentSdk is still exported as a backward-compatible alias.
import { TenderSdk, onFinishResponse } from "@tender-cash/js-sdk";
function PaymentComponent() {
const handleEventResponse = (response: onFinishResponse) => {
console.log("SDK Response:", response);
};
return (
<TenderSdk
accessId="YOUR_ACCESS_ID"
fiatCurrency="USD"
env="test"
onEventResponse={handleEventResponse}
amount={150}
referenceId="unique-payment-reference-123"
paymentExpirySeconds={1800}
/>
);
}When referenceId and amount are provided as props, the modal auto-opens on mount.
Next.js and SSR Notes
TenderSdk is a browser-only widget and should be loaded on the client in SSR frameworks.
Recommended in Next.js App Router:
"use client";
import dynamic from "next/dynamic";
const TenderSdk = dynamic(
() => import("@tender-cash/js-sdk").then((mod) => mod.TenderSdk),
{ ssr: false }
);The SDK entrypoint avoids DOM access at module load time, but rendering the widget still requires a browser runtime.
API Reference
Component Props (TenderProps)
Applies to both TenderSdk and TenderAgentSdk.
Required Props
| Prop | Type | Description |
|----------------|------------------------------------|-------------|
| accessId | string | Your Tender Cash merchant access ID. |
| fiatCurrency | string | Fiat currency code, e.g. USD, EUR, NGN. |
| env | "sandbox" \| "test" \| "live" \| "local" | SDK environment. |
Optional Props
| Prop | Type | Description |
|-----------------------|------------------------------------|-------------|
| onEventResponse | (data: onFinishResponse) => void | Called when payment state updates. |
| referenceId | string | Payment reference ID (required for auto-open mode). |
| amount | number | Payment amount in fiat (required for auto-open mode). |
| paymentExpirySeconds| number | Payment expiry in seconds. |
| meta | PaymentMeta | Optional metadata forwarded to the payment initiation API (e.g. { customerEmail }). |
| theme | "light" \| "dark" | Modal theme. |
| closeModal | () => void | Callback fired when modal is closed. |
| confirmationInterval| number | Payment validation polling interval in ms. Defaults to 5000. |
| apiBaseUrl | string | Override for the Tender API base URL (defaults per env). |
| apiRequest | TenderApiRequest | Optional backend proxy function for Tender API calls (keeps secrets server-side). |
Backend proxy (apiRequest)
For production integrations you can route Tender API calls through your own backend:
async function apiRequest({ path, method = "GET", body }) {
const response = await fetch("/your/tender/proxy", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path, method, body }),
});
if (!response.ok) {
throw new Error("Tender request failed.");
}
return response.json();
}Ref Usage
import { useRef } from "react";
import { TenderSdk, TenderRef } from "@tender-cash/js-sdk";
function PaymentComponent() {
const tenderRef = useRef<TenderRef>(null);
const openPayment = () => {
tenderRef.current?.initiatePayment({
amount: 150,
referenceId: "unique-payment-reference-123",
paymentExpirySeconds: 1800,
meta: { customerEmail: "[email protected]" }, // optional
});
};
const closePayment = () => {
tenderRef.current?.dismiss();
};
return (
<>
<button onClick={openPayment}>Open Payment</button>
<button onClick={closePayment}>Close Modal</button>
<TenderSdk
ref={tenderRef}
accessId="YOUR_ACCESS_ID"
fiatCurrency="USD"
env="test"
/>
</>
);
}Ref Methods (TenderRef)
| Method | Description |
|-------------------|-------------|
| initiatePayment | Opens the modal and initiates a payment. |
| dismiss | Closes the modal. |
Callback Shape (onFinishResponse)
interface onFinishResponse {
status: "partial-payment" | "completed" | "overpayment" | "pending" | "error" | "cancelled" | "failed";
message: string;
data: IPaymentData | undefined;
}Features
- Coin ordering and recommended networks driven by the Tender API (
priority/recommendedfields); a network shows as recommended only when the API flags it - Shadow DOM style isolation
- Auto-open mode with direct props
- Programmatic control via ref
- Expiry countdown uses absolute timestamps for accurate background-tab behavior
- TypeScript support
Migration Notes
If you are upgrading from older naming:
TenderAgentProps->TenderPropsTenderAgentRef->TenderRefTenderAgentSdk->TenderSdk(old name still works)
Release Validation
Before publish, the SDK is validated with:
- unit tests (
yarn test) - library build (
yarn build) - package export/tarball shape checks (
yarn check:package-shape) - Next.js consumer smoke build (
yarn smoke:next)
