A modern, type-safe TypeScript SDK for the GoCardless Bank Account Data API v2.
- 🎯 Type-Safe: Full TypeScript support with auto-generated types from OpenAPI spec
- 🔄 Automatic Token Management: Handles JWT token generation, refresh, and expiry
- 🔁 Smart Retry Logic: Configurable retry with linear/exponential backoff
- ⚡ Modern API: Clean, Promise-based interface
- 🪝 Interceptors: Request/response transformation hooks
- 📦 Tree-Shakeable: ESM and CJS builds with minimal bundle size
- ✅ Well Tested: 91.7% test coverage with 156+ tests
npm install gocardless-open-bankingpnpm add gocardless-open-bankingyarn add gocardless-open-bankingimport { GoCardlessClient } from 'gocardless-open-banking';
// Initialize the client
const client = new GoCardlessClient({
secretId: process.env.GOCARDLESS_SECRET_ID!,
secretKey: process.env.GOCARDLESS_SECRET_KEY!,
});
// List available institutions in the UK
const institutions = await client.institutions.list('GB');
// Create an end-user agreement
const agreement = await client.agreements.create({
institution_id: 'SANDBOXFINANCE_SFIN0000',
max_historical_days: 90,
access_valid_for_days: 90,
access_scope: ['balances', 'details', 'transactions'],
});
// Create a requisition for account access
const requisition = await client.requisitions.create({
redirect: 'https://your-app.com/callback',
institution_id: 'SANDBOXFINANCE_SFIN0000',
agreement: agreement.id,
reference: 'user-123',
user_language: 'en',
});
// After user completes authorization, get account details
const accounts = requisition.accounts;
const accountId = accounts[0];
// Get account balances
const balances = await client.accounts.balances(accountId);
// Get account transactions
const transactions = await client.accounts.transactions(accountId, {
dateFrom: '2024-01-01',
dateTo: '2024-12-31',
});The SDK automatically handles authentication using your GoCardless API credentials. Tokens are cached and automatically refreshed when needed.
- Sign up at GoCardless Bank Account Data
- Navigate to User Secrets in the dashboard
- Create a new secret pair
- Copy your
Secret IDandSecret Key
GOCARDLESS_SECRET_ID=your_secret_id
GOCARDLESS_SECRET_KEY=your_secret_keyList and retrieve information about supported banking institutions.
// List institutions for a specific country
const ukBanks = await client.institutions.list('GB');
const germanBanks = await client.institutions.list('DE');
// Get details for a specific institution
const institution = await client.institutions.get('SANDBOXFINANCE_SFIN0000');
console.log(institution.name); // "Sandbox Finance"
console.log(institution.countries); // ["GB"]Manage end-user agreements that define data access permissions.
// Create a new agreement
const agreement = await client.agreements.create({
institution_id: 'SANDBOXFINANCE_SFIN0000',
max_historical_days: 90,
access_valid_for_days: 90,
access_scope: ['balances', 'details', 'transactions'],
});
// List all agreements with pagination
const agreements = await client.agreements.list({
limit: 20,
offset: 0,
});
// Get a specific agreement
const agreementDetails = await client.agreements.get(agreement.id);
// Accept an agreement
const acceptedAgreement = await client.agreements.accept(agreement.id, {
user_agent: 'Mozilla/5.0...',
ip_address: '192.168.1.1',
});
// Delete an agreement
await client.agreements.delete(agreement.id);Create and manage requisitions to obtain end-user consent for account access.
// Create a requisition
const requisition = await client.requisitions.create({
redirect: 'https://your-app.com/callback',
institution_id: 'SANDBOXFINANCE_SFIN0000',
agreement: agreementId,
reference: 'user-123',
user_language: 'en',
});
// Direct user to the authorization link
console.log(requisition.link); // User completes authorization here
// List all requisitions
const requisitions = await client.requisitions.list({
limit: 10,
offset: 0,
});
// Get requisition details (after user authorization)
const requisitionDetails = await client.requisitions.get(requisition.id);
console.log(requisitionDetails.status); // "LN" (Linked)
console.log(requisitionDetails.accounts); // ["account-id-1", "account-id-2"]
// Delete a requisition
await client.requisitions.delete(requisition.id);Access account metadata, balances, details, and transactions.
const accountId = 'account-id-from-requisition';
// Get account metadata
const account = await client.accounts.get(accountId);
console.log(account.iban);
console.log(account.status);
console.log(account.owner_name);
// Get account balances
const balances = await client.accounts.balances(accountId);
balances.balances.forEach((balance) => {
console.log(`${balance.balanceType}: ${balance.balanceAmount.amount} ${balance.balanceAmount.currency}`);
});
// Get account details
const details = await client.accounts.details(accountId);
console.log(details.account.name);
console.log(details.account.currency);
// Get transactions without filters
const allTransactions = await client.accounts.transactions(accountId);
// Get transactions with date filters
const filteredTransactions = await client.accounts.transactions(accountId, {
dateFrom: '2024-01-01',
dateTo: '2024-03-31',
});
// Process transactions
filteredTransactions.transactions.booked.forEach((tx) => {
console.log(`${tx.bookingDate}: ${tx.transactionAmount.amount} ${tx.transactionAmount.currency}`);
console.log(`Debtor: ${tx.debtorName || 'N/A'}`);
console.log(`Creditor: ${tx.creditorName || 'N/A'}`);
});const client = new GoCardlessClient({
// Required
secretId: 'your-secret-id',
secretKey: 'your-secret-key',
// Optional
baseUrl: 'https://bankaccountdata.gocardless.com', // Default
timeout: 30000, // Request timeout in ms (default: 30000)
// Retry configuration
retry: {
maxRetries: 2, // Maximum retry attempts (default: 2)
retryableStatusCodes: [429], // Status codes to retry (default: [429])
backoff: 'linear', // 'linear' or 'exponential' (default: 'linear')
initialDelayMs: 1000, // Initial retry delay (default: 1000)
maxDelayMs: 30000, // Maximum retry delay (default: 30000)
respectRetryAfter: true, // Honor Retry-After header (default: true)
},
// Request/response interceptors
interceptors: {
request: [
async (config) => {
// Modify request config
console.log(`Making request to: ${config.url}`);
return config;
},
],
response: [
async (response) => {
// Modify response
console.log(`Received response: ${response.status}`);
return response;
},
],
},
});Linear Backoff (default):
- Retry delay increases linearly: 1s, 2s, 3s...
- Predictable and suitable for most use cases
Exponential Backoff:
- Retry delay doubles each time: 1s, 2s, 4s, 8s...
- Better for handling rate limits and server congestion
const client = new GoCardlessClient({
secretId: process.env.GOCARDLESS_SECRET_ID!,
secretKey: process.env.GOCARDLESS_SECRET_KEY!,
retry: {
maxRetries: 3,
backoff: 'exponential',
initialDelayMs: 1000,
maxDelayMs: 60000,
},
});The GoCardless API enforces rate limits to ensure fair usage. The SDK provides comprehensive rate limiting support to help you stay within limits.
The API returns rate limit information in response headers:
-
General Rate Limits:
X-RateLimit-Limit: Total requests allowed per dayX-RateLimit-Remaining: Remaining requests for todayX-RateLimit-Reset: Unix timestamp when the limit resets
-
Account Success Rate Limits (for successful account data requests):
X-RateLimit-Account-Success-Limit: Total successful account requests allowed per dayX-RateLimit-Account-Success-Remaining: Remaining successful requestsX-RateLimit-Account-Success-Reset: Unix timestamp when the account limit resets
// Make a request
const institutions = await client.institutions.list('GB');
// Check rate limit status
const rateLimit = client.getLastRateLimitInfo();
if (rateLimit?.general) {
console.log(`Requests remaining: ${rateLimit.general.remaining}/${rateLimit.general.limit}`);
const resetDate = new Date(rateLimit.general.reset * 1000);
console.log(`Limit resets at: ${resetDate.toISOString()}`);
}
if (rateLimit?.accountSuccess) {
console.log(`Account success requests remaining: ${rateLimit.accountSuccess.remaining}/${rateLimit.accountSuccess.limit}`);
}For real-time rate limit monitoring, use the onRateLimit callback:
const client = new GoCardlessClient({
secretId: process.env.GOCARDLESS_SECRET_ID!,
secretKey: process.env.GOCARDLESS_SECRET_KEY!,
// Called whenever rate limit headers are received
onRateLimit: (rateLimit) => {
if (rateLimit.general) {
console.log(`[Rate Limit] ${rateLimit.general.remaining}/${rateLimit.general.limit} requests remaining`);
// Alert when approaching limit
if (rateLimit.general.remaining < 10) {
console.warn('Warning: Approaching rate limit!');
}
}
if (rateLimit.accountSuccess) {
console.log(`[Account Limit] ${rateLimit.accountSuccess.remaining}/${rateLimit.accountSuccess.limit} remaining`);
}
},
});When you exceed the rate limit, the API returns a 429 Too Many Requests error:
import { GoCardlessAPIError } from 'gocardless-open-banking';
try {
const accounts = await client.accounts.get('account-id');
} catch (error) {
if (error instanceof GoCardlessAPIError && error.code === 'RATE_LIMIT_EXCEEDED') {
// Get retry-after time from error detail
const retryAfter = error.getRetryAfter();
if (retryAfter) {
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
// Retry the request
const accounts = await client.accounts.get('account-id');
}
// Check rate limit info from the error
if (error.rateLimit?.general) {
const resetDate = new Date(error.rateLimit.general.reset * 1000);
console.log(`Rate limit resets at: ${resetDate.toISOString()}`);
}
}
}-
Monitor Rate Limits Proactively:
const rateLimit = client.getLastRateLimitInfo(); if (rateLimit?.general?.remaining && rateLimit.general.remaining < 100) { console.warn('Low rate limit remaining, consider throttling requests'); }
-
Implement Exponential Backoff:
const client = new GoCardlessClient({ secretId: process.env.GOCARDLESS_SECRET_ID!, secretKey: process.env.GOCARDLESS_SECRET_KEY!, retry: { maxRetries: 3, backoff: 'exponential', // Better for rate limits respectRetryAfter: true, // Honor API's retry-after time }, });
-
Batch Requests Efficiently:
// Use pagination to limit requests const requisitions = await client.requisitions.list({ limit: 100, // Get more data per request offset: 0, });
The SDK throws GoCardlessAPIError for all API-related errors.
import { GoCardlessAPIError } from 'gocardless-open-banking';
try {
const account = await client.accounts.get('invalid-id');
} catch (error) {
if (error instanceof GoCardlessAPIError) {
console.error(`Error: ${error.message}`);
console.error(`Status: ${error.statusCode}`);
console.error(`Code: ${error.code}`);
console.error(`Detail: ${error.detail}`);
// Handle specific error codes
switch (error.code) {
case 'ACCOUNT_NOT_FOUND':
console.log('Account does not exist');
break;
case 'RATE_LIMIT_EXCEEDED':
const retryAfter = error.getRetryAfter();
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
break;
case 'AUTHENTICATION_FAILED':
console.log('Invalid credentials');
break;
default:
console.log('Unknown error occurred');
}
} else {
// Network or other errors
console.error('Unexpected error:', error);
}
}| Code | Status | Description |
|---|---|---|
ACCOUNT_NOT_FOUND |
404 | Account ID does not exist |
REQUISITION_NOT_FOUND |
404 | Requisition ID does not exist |
AGREEMENT_NOT_FOUND |
404 | Agreement ID does not exist |
VALIDATION_ERROR |
400 | Invalid request data |
AUTHENTICATION_FAILED |
401 | Invalid credentials |
PAYMENT_REQUIRED |
402 | Free usage limit exceeded |
FORBIDDEN |
403 | Access denied |
IP_NOT_WHITELISTED |
403 | IP address not allowed |
CONFLICT |
409 | Account suspended or processing delay |
RATE_LIMIT_EXCEEDED |
429 | Too many requests |
INTERNAL_SERVER_ERROR |
500 | Server error |
BAD_GATEWAY |
502 | Bad gateway |
SERVICE_UNAVAILABLE |
503 | Service temporarily unavailable |
GATEWAY_TIMEOUT |
504 | Gateway timeout |
The SDK is written in TypeScript and includes comprehensive type definitions.
import type {
Account,
AccountBalance,
AccountTransactions,
Requisition,
EndUserAgreement,
Integration,
} from 'gocardless-open-banking';
// All API responses are fully typed
const account: Account = await client.accounts.get(accountId);
const balances: AccountBalance = await client.accounts.balances(accountId);
const transactions: AccountTransactions = await client.accounts.transactions(accountId);Modify requests before they're sent:
const client = new GoCardlessClient({
secretId: process.env.GOCARDLESS_SECRET_ID!,
secretKey: process.env.GOCARDLESS_SECRET_KEY!,
interceptors: {
request: [
// Add custom headers
async (config) => {
config.headers['X-Custom-Header'] = 'value';
return config;
},
// Log requests
async (config) => {
console.log(`[${config.method}] ${config.url}`);
return config;
},
],
},
});Transform responses before they're returned:
const client = new GoCardlessClient({
secretId: process.env.GOCARDLESS_SECRET_ID!,
secretKey: process.env.GOCARDLESS_SECRET_KEY!,
interceptors: {
response: [
// Log responses
async (response) => {
console.log(`Response status: ${response.status}`);
return response;
},
],
},
});Adjust timeout for specific operations:
const client = new GoCardlessClient({
secretId: process.env.GOCARDLESS_SECRET_ID!,
secretKey: process.env.GOCARDLESS_SECRET_KEY!,
timeout: 60000, // 60 seconds for slow connections
});Creates a new GoCardless client instance.
Parameters:
config.secretId(string, required): Your GoCardless Secret IDconfig.secretKey(string, required): Your GoCardless Secret Keyconfig.baseUrl(string, optional): API base URL (default:https://bankaccountdata.gocardless.com)config.timeout(number, optional): Request timeout in ms (default: 30000)config.retry(object, optional): Retry configurationconfig.interceptors(object, optional): Request/response interceptors
List all supported institutions in a country.
Get details for a specific institution.
List all agreements with optional pagination.
Get a specific agreement.
Create a new end-user agreement.
client.agreements.accept(agreementId: string, data: EnduserAcceptanceDetailsRequest): Promise<EndUserAgreement>
Accept an agreement.
Delete an agreement.
List all requisitions with optional pagination.
Get a specific requisition.
Create a new requisition.
Delete a requisition.
Get account metadata.
Get account balances.
Get account details.
Get account transactions with optional date filters.
Options:
dateFrom(string, optional): Start date (YYYY-MM-DD)dateTo(string, optional): End date (YYYY-MM-DD)
The SDK includes comprehensive test coverage:
# Run tests
pnpm test
# Run tests with coverage
pnpm coverage
# Run tests in watch mode
pnpm test:uiContributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See Releases for release history.