This library provides convenient access to the Fingo Pay REST API from server-side TypeScript or JavaScript. It is generated with Stainless.
Installation
Install the Fingo Pay TypeScript SDK using your preferred package manager:
npm install @fingoafrica/fingo-pay
pnpm add @fingoafrica/fingo-pay
yarn add @fingoafrica/fingo-pay
bun add @fingoafrica/fingo-pay
Quick start
Initialize the SDK with your API key and make your first request:
import FingoPay from '@fingoafrica/fingo-pay';
const client = new FingoPay({
apiKey: process.env['FINGO_PAY_API_KEY'], // This is the default and can be omitted
});
const acceptedResponse = await client.mpesa.createCharge({
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
});
console.log(acceptedResponse.data);
Never expose your secret API key in client-side code or version control. Use environment variables.
Request & response types
This library includes TypeScript definitions for all request params and response fields. Import and use them for full type safety:
import FingoPay from '@fingoafrica/fingo-pay';
const client = new FingoPay({
apiKey: process.env['FINGO_PAY_API_KEY'],
});
const params: FingoPay.MpesaCreateChargeParams = {
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
};
const acceptedResponse: FingoPay.AcceptedResponse = await client.mpesa.createCharge(params);
Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
Handling errors
When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of APIError will be thrown:
const acceptedResponse = await client.mpesa
.createCharge({
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
})
.catch(async (err) => {
if (err instanceof FingoPay.APIError) {
console.log(err.status); // 400
console.log(err.name); // BadRequestError
console.log(err.headers); // {server: 'nginx', ...}
} else {
throw err;
}
});
Error codes
| Status Code | Error Type |
|---|
| 400 | BadRequestError |
| 401 | AuthenticationError |
| 403 | PermissionDeniedError |
| 404 | NotFoundError |
| 422 | UnprocessableEntityError |
| 429 | RateLimitError |
| >=500 | InternalServerError |
| N/A | APIConnectionError |
Retries
Certain errors are automatically retried 2 times by default, with a short exponential backoff. The following errors are retried:
- Connection errors (e.g., network connectivity problems)
- 408 Request Timeout
- 409 Conflict
- 429 Rate Limit
-
=500 Internal errors
Configure or disable retries using the maxRetries option:
// Configure the default for all requests:
const client = new FingoPay({
maxRetries: 0, // default is 2
});
// Or, configure per-request:
await client.mpesa.createCharge(
{
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
},
{
maxRetries: 5,
}
);
Timeouts
Requests time out after 1 minute by default. Configure this with the timeout option:
// Configure the default for all requests:
const client = new FingoPay({
timeout: 20 * 1000, // 20 seconds (default is 1 minute)
});
// Override per-request:
await client.mpesa.createCharge(
{
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
},
{
timeout: 5 * 1000,
}
);
On timeout, an APIConnectionTimeoutError is thrown. Requests that time out will be retried twice by default.
Advanced usage
Accessing raw response data
The “raw” Response returned by fetch() can be accessed through the .asResponse() method on the APIPromise type. This method returns as soon as the headers for a successful response are received and does not consume the response body, allowing custom parsing or streaming logic.
Use .withResponse() to get the raw Response along with the parsed data:
const client = new FingoPay();
// Access raw response without consuming body
const response = await client.mpesa
.createCharge({
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
})
.asResponse();
console.log(response.headers.get('X-My-Header'));
console.log(response.statusText);
// Get both parsed data and raw response
const { data: acceptedResponse, response: raw } = await client.mpesa
.createCharge({
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
})
.withResponse();
console.log(raw.headers.get('X-My-Header'));
console.log(acceptedResponse.data);
Logging
All log messages are intended for debugging only. The format and content of log messages may change between releases.
Log levels
Configure the log level in two ways:
- Via the
FINGO_PAY_LOG environment variable
- Using the
logLevel client option (overrides the environment variable)
import FingoPay from '@fingoafrica/fingo-pay';
const client = new FingoPay({
logLevel: 'debug', // Show all log messages
});
Available log levels, from most to least verbose:
| Level | Description |
|---|
debug | Show debug messages, info, warnings, and errors |
info | Show info messages, warnings, and errors |
warn | Show warnings and errors (default) |
error | Show only errors |
off | Disable all logging |
At the debug level, all HTTP requests and responses are logged, including headers and bodies. Some authentication-related headers are redacted, but sensitive data in request and response bodies may still be visible.
Custom logger
Provide a custom logger instead of the default globalThis.console. Most logging libraries are supported, including pino, winston, bunyan, consola, signale, and @std/log.
import FingoPay from '@fingoafrica/fingo-pay';
import pino from 'pino';
const logger = pino();
const client = new FingoPay({
logger: logger.child({ name: 'FingoPay' }),
logLevel: 'debug',
});
Making custom/undocumented requests
Undocumented endpoints
Make requests to undocumented endpoints using client.get, client.post, and other HTTP verbs:
await client.post('/some/path', {
body: { some_prop: 'foo' },
query: { some_query_arg: 'bar' },
});
Undocumented request params
Use // @ts-expect-error for undocumented parameters:
client.mpesa.createCharge({
amount: 150000,
merchantTransactionId: 'invoice_48291',
phoneNumber: '+254712345678',
// @ts-expect-error baz is not yet public
baz: 'undocumented option',
});
Customizing the fetch client
By default, this library expects a global fetch function. You can polyfill it globally or pass a custom one:
import FingoPay from '@fingoafrica/fingo-pay';
import fetch from 'my-fetch';
const client = new FingoPay({ fetch });
Fetch options
Provide custom fetch options when instantiating the client or making a request:
import FingoPay from '@fingoafrica/fingo-pay';
const client = new FingoPay({
fetchOptions: {
// `RequestInit` options
},
});
Configuring proxies
Provide custom fetchOptions to add runtime-specific proxy options:
import FingoPay from '@fingoafrica/fingo-pay';
import * as undici from 'undici';
const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
const client = new FingoPay({
fetchOptions: {
dispatcher: proxyAgent,
},
});
import FingoPay from '@fingoafrica/fingo-pay';
const client = new FingoPay({
fetchOptions: {
proxy: 'http://localhost:8888',
},
});
import FingoPay from 'npm:@fingoafrica/fingo-pay';
const httpClient = Deno.createHttpClient({
proxy: { url: 'http://localhost:8888' },
});
const client = new FingoPay({
fetchOptions: {
client: httpClient,
},
});
Requirements
TypeScript >= 4.9 is supported.
The following runtimes are supported:
| Runtime | Version |
|---|
| Web browsers | Up-to-date Chrome, Firefox, Safari, Edge, and more |
| Node.js | 20 LTS or later (non-EOL) versions |
| Deno | v1.28.0 or higher |
| Bun | 1.0 or later |
| Cloudflare Workers | Latest |
| Vercel Edge Runtime | Latest |
| Jest | 28 or greater with the “node” environment |
| Nitro | v2.6 or greater |
React Native is not supported at this time. The jsdom environment in Jest is also not supported.
Semantic versioning
This package generally follows SemVer conventions, though certain backwards-incompatible changes may be released as minor versions:
- Changes that only affect static types, without breaking runtime behavior
- Changes to library internals which are technically public but not intended or documented for external use
- Changes that we do not expect to impact the vast majority of users in practice