Link Integration Guide
Connect your users to their biller accounts in 3 steps: create a link token, open the Connect SDK, and exchange the token for persistent access.
1
Create a Link Token
Your server creates a short-lived link token that identifies the user and the biller they want to connect. Send this token to your frontend to initialize the Connect SDK.
POST /link/token/create
const response = await fetch('https://sandbox.api.billerapi.com/link/token/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Client-ID': process.env.BILLERAPI_CLIENT_ID,
'X-Client-Secret': process.env.BILLERAPI_CLIENT_SECRET,
},
body: JSON.stringify({
client_id: process.env.BILLERAPI_CLIENT_ID,
client_user_id: 'user_123',
biller_id: 'test_electric_company',
consents: ['bills'],
}),
});
const { link_token } = await response.json();
// Send link_token to your frontendRequest body
JSON
{
"client_id": "string",
"client_user_id": "string",
"biller_id": "string (optional)",
"consents": ["bills"]
}Response
JSON
{
"success": true,
"link_token": "string",
"expires_at": "string"
}Note
Link tokens expire after 30 minutes. Create a new one for each linking session — do not cache or reuse them.
2
Open the Connect SDK
Pass the link token to the Connect SDK on your frontend. The SDK handles credential entry, account discovery, and consent — then returns a public token in the onSuccess callback.
Initialize and open Connect
JavaScript
import { BillButler } from '@billerapi/connect-sdk';
const billbutler = new BillButler({
clientId: 'your_client_id',
environment: 'sandbox',
});
const handler = billbutler.create({
linkToken: linkToken, // from your server
onSuccess: async (publicToken, metadata) => {
console.log('Account linked!', metadata.institutionName);
// Exchange the public token on your server
const res = await fetch('/api/exchange-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ publicToken }),
});
const { access_token } = await res.json();
// Store access_token — you'll need it to fetch bills
},
onExit: (error) => {
if (error) console.error('Error:', error.code);
},
});
handler.open();React component example
React
import React, { useState, useCallback, useRef } from 'react';
import { BillButler } from '@billerapi/connect-sdk';
const LinkButton = ({ userId, onSuccess }) => {
const [isLoading, setIsLoading] = useState(false);
const billbutlerRef = useRef(
new BillButler({
clientId: process.env.NEXT_PUBLIC_BILLERAPI_CLIENT_ID,
environment: 'sandbox',
})
);
const handleLink = useCallback(async () => {
setIsLoading(true);
try {
// Get link token from your server
const response = await fetch('/api/create-link-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId })
});
const { linkToken } = await response.json();
// Open Connect SDK
const handler = billbutlerRef.current.create({
linkToken,
onSuccess: async (publicToken, metadata) => {
await fetch('/api/exchange-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ publicToken }),
});
onSuccess?.(metadata);
},
onExit: (error) => {
if (error) console.error(error.code);
setIsLoading(false);
},
});
handler.open();
} catch (error) {
console.error('Error creating link token:', error);
setIsLoading(false);
}
}, [userId, onSuccess]);
return (
<button
onClick={handleLink}
disabled={isLoading}
className="bg-primary text-primary-foreground px-6 py-3 rounded-lg"
>
{isLoading ? 'Connecting...' : 'Link Account'}
</button>
);
};
export default LinkButton;Sandbox test credentials
Use account number
4242424242 with any username and password. This always succeeds. See the Getting Started guide for the full sandbox reference table.3
Exchange the Public Token
Send the public token from the onSuccess callback to your server, then exchange it for a long-lived access token. Store the access token securely — you'll use it for all subsequent API calls on this linked account.
POST /link/token/exchange
const response = await fetch('https://sandbox.api.billerapi.com/link/token/exchange', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Client-ID': process.env.BILLERAPI_CLIENT_ID,
'X-Client-Secret': process.env.BILLERAPI_CLIENT_SECRET,
},
body: JSON.stringify({
client_id: process.env.BILLERAPI_CLIENT_ID,
public_token: publicToken,
}),
});
const { access_token, biller_id, link_id } = await response.json();
// Store access_token securely — use it to fetch billsRequest body
JSON
{
"client_id": "string",
"public_token": "string"
}Response
JSON
{
"success": true,
"access_token": "string",
"biller_id": "string",
"link_id": "string"
}Note
Public tokens are single-use and expire after 30 minutes. Always exchange them immediately after receiving the
onSuccess callback.