billerapi-react
v1.0.1
Published
React bindings for the BillerAPI Elements SDK — hooks and provider for the connect, add-payment-method, and pay flows
Maintainers
Readme
billerapi-react
React bindings for the BillerAPI Elements SDK (billerapi-js).
Wrap your app in ElementsProvider, then drive each flow with a hook:
useConnect, useAddPaymentMethod, usePay.
The hooks are thin wrappers over the billerapi-js flow factories. The
hosted iframe owns all sensitive UI — card PAN/CVV and credentials never enter
your React context.
Install
pnpm add billerapi-react billerapi-js reactreact (>=16.8) is a peer dependency. billerapi-js is a direct
dependency and provides the underlying SDK.
Setup
Provide a single SDK instance once, near the root of your tree. Keep config
stable (module scope or memoized) so the instance is not recreated each render.
import { ElementsProvider } from 'billerapi-react';
const elementsConfig = { clientId: 'your_client_id' };
export function App() {
return (
<ElementsProvider config={elementsConfig}>
<Checkout />
</ElementsProvider>
);
}Hooks
Every hook returns the same shape:
interface ElementsFlowResult {
open: () => Promise<void>; // open the modal (idempotent)
close: () => void; // close the modal (idempotent)
isOpen: () => boolean; // is the modal open?
ready: boolean; // true once a provider instance is available
error: ElementsError | null; // last open failure (also routed to onExit)
}The modal is closed automatically when the consuming component unmounts.
useConnect
import { useConnect } from 'billerapi-react';
function ConnectButton({ linkToken }: { linkToken: string }) {
const { open, ready, error } = useConnect({
linkToken,
onSuccess: (publicToken, metadata) => {
// exchange publicToken server-side
},
onExit: (err) => {
if (err) console.error(err.code, err.message);
},
});
return (
<>
<button disabled={!ready} onClick={() => void open()}>
Connect account
</button>
{error && <p role="alert">{error.message}</p>}
</>
);
}useAddPaymentMethod
import { useAddPaymentMethod } from 'billerapi-react';
function AddCardButton({ payToken }: { payToken: string }) {
const { open, ready } = useAddPaymentMethod({
payToken,
onSuccess: (paymentMethodId, metadata) => {
// metadata.last_4 / metadata.card_brand available
},
});
return (
<button disabled={!ready} onClick={() => void open()}>
Add card
</button>
);
}usePay
import { usePay } from 'billerapi-react';
function PayButton({ payToken, billId }: { payToken: string; billId?: string }) {
const { open, ready } = usePay({
payToken,
billId,
onSuccess: (paymentAttemptId, metadata) => {
// metadata.bill_id available
},
});
return (
<button disabled={!ready} onClick={() => void open()}>
Pay bill
</button>
);
}Notes
onSuccessis required for every flow;onExit,onLoad,onEvent, andthemeare optional and forwarded straight through tobillerapi-js.- Calling
open()outside anElementsProviderresolves to anerrorwith codeMODAL_OPEN_ERRORand invokesonExitinstead of throwing. - All wire fields (metadata, theme) are snake_case, matching the core SDK's contract; developer-facing options are camelCase.
Escape hatch
Need the raw SDK instance (e.g. for getConfig() or a custom flow)? Use
useElements() inside a provider:
import { useElements } from 'billerapi-react';
const elements = useElements(); // throws if no provider in tree