Skip to main content
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

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 CodeError Type
400BadRequestError
401AuthenticationError
403PermissionDeniedError
404NotFoundError
422UnprocessableEntityError
429RateLimitError
>=500InternalServerError
N/AAPIConnectionError

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:
  1. Via the FINGO_PAY_LOG environment variable
  2. 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:
LevelDescription
debugShow debug messages, info, warnings, and errors
infoShow info messages, warnings, and errors
warnShow warnings and errors (default)
errorShow only errors
offDisable 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,
  },
});

Requirements

TypeScript >= 4.9 is supported.
The following runtimes are supported:
RuntimeVersion
Web browsersUp-to-date Chrome, Firefox, Safari, Edge, and more
Node.js20 LTS or later (non-EOL) versions
Denov1.28.0 or higher
Bun1.0 or later
Cloudflare WorkersLatest
Vercel Edge RuntimeLatest
Jest28 or greater with the “node” environment
Nitrov2.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