@afriex/payment-batches
Version:
Bulk payouts to bank accounts and mobile money wallets with the Afriex Business API
164 lines (101 loc) • 6.3 kB
Markdown
# /payment-batches
Payment batch service for the Afriex SDK. Save a list of recipients with the amount each one is paid, then pay all of them in one call.
## Installation
```bash
npm install /payment-batches @afriex/core
# or
pnpm add /payment-batches @afriex/core
```
## Usage
```typescript
import { AfriexClient } from "@afriex/core";
import { PaymentBatchService } from "@afriex/payment-batches";
const client = new AfriexClient({
apiKey: "your-api-key",
});
const paymentBatches = new PaymentBatchService(client.getHttpClient());
// 1. Create an empty batch, funded from the USD wallet
const batch = await paymentBatches.create({
name: "June payroll",
sourcePaymentMethod: { currencyCode: "USD" },
});
// 2. Add the recipients
const added = await paymentBatches.addRecipients(batch.id, [
{
channel: "BANK_ACCOUNT",
accountName: "Ada Obi",
accountNumber: "0123456789",
countryCode: "NG",
institution: { institutionCode: "000013", institutionName: "GTBank" },
amount: { value: "20000", currencyCode: "NGN" },
},
{
channel: "MOBILE_MONEY",
accountName: "Wanjiru Kamau",
accountNumber: "254712345678",
countryCode: "KE",
institution: { institutionCode: "MPESA", institutionName: "M-Pesa" },
amount: { value: "1000", currencyCode: "KES" },
},
]);
console.log(added.successes, added.errors); // keyed by account number
// 3. Start the payouts
const run = await paymentBatches.withdraw(batch.id);
console.log(run.successes, run.errors); // keyed by recipientId
// 4. Retry only the payouts that failed
const sessions = await paymentBatches.listSessions(batch.id, { limit: 1 });
await paymentBatches.withdraw(batch.id, { sessionId: sessions.data[0].id });
```
Every payout is converted from the currency of the wallet the batch is funded from. The payouts settle asynchronously, so configure a webhook URL before you call `withdraw()` and follow each one through `TRANSACTION.UPDATED`.
## API Reference
### `create(request: PaymentBatchRequest): Promise<PaymentBatch>`
Create an empty batch.
**Endpoint:** `POST /payment-batch`
**Required:** `name`, `sourcePaymentMethod.currencyCode`
**Optional:** `sourcePaymentMethod.channel`. The only value is `WALLET`, which is also the default.
### `get(batchId: string): Promise<PaymentBatch>`
Get a batch by ID.
### `list(params?: PaymentBatchListParams): Promise<PaymentBatchListResponse>`
List batches. Pages start at `0`, and `limit` is between `1` and `100`.
**Returns:** `{ data, page, total }`. Each item carries `meta.memberCount`, the number of recipients in the batch.
### `update(batchId: string, request: PaymentBatchRequest): Promise<PaymentBatch>`
Replace the name and the funding method of a batch.
**Required:** `name`, `sourcePaymentMethod.currencyCode`. The batch is replaced whole, so send both even when only one changes.
### `delete(batchId: string): Promise<void>`
Delete a batch.
### `addRecipient(batchId: string, recipient: PaymentBatchRecipientRequest): Promise<SavedPaymentBatchRecipient>`
Add one recipient.
**Endpoint:** `POST /payment-batch/{batchId}/recipients`
**Required:** `channel`, `accountName`, `accountNumber`, `countryCode`, `amount.value`, `amount.currencyCode`, and `institution` for every channel except `UPI` and `INTERAC`
**Returns:** the saved account. Its `id` is the `paymentMethodId` of the recipient, not its `recipientId`.
An account that is already in the batch is answered with `409 DUPLICATE_REQUEST`.
### `addRecipients(batchId: string, recipients: PaymentBatchRecipientRequest[]): Promise<PaymentBatchOutcomes>`
Add several recipients. Each one is added independently, so the call succeeds even when some of them fail.
**Endpoint:** `POST /payment-batch/{batchId}/recipients/bulk`
**Returns:** `{ successes, errors }`, both keyed by account number. Check `errors` on every call.
### `listRecipients(batchId: string, params?: PaymentBatchListParams): Promise<PaymentBatchRecipientListResponse>`
List the recipients of a batch. Each one carries its `recipientId` and its `paymentMethodId`.
### `updateRecipient(batchId: string, recipientId: string, request: UpdatePaymentBatchRecipientRequest): Promise<SavedPaymentBatchRecipient>`
Replace the account details and the amount of a recipient.
**Required:** the same fields as `addRecipient()`. The recipient is replaced whole: a request that carries only the new amount is rejected.
**Optional:** `paymentMethodId`, to update the saved account in place.
### `removeRecipient(batchId: string, recipientId: string): Promise<void>`
Remove a recipient from the batch. The saved account is kept as a payment method.
### `withdraw(batchId: string, params?: WithdrawPaymentBatchParams): Promise<PaymentBatchOutcomes>`
Start the payouts for a batch.
**Endpoint:** `POST /payment-batch/{batchId}/withdraw`
**Optional:** `sessionId`, the id of an earlier run. Only the recipients that failed in that run are paid.
**Returns:** `{ successes, errors }`, both keyed by `recipientId`.
Every call without a `sessionId` is a new run and pays every recipient again. A call made while a run of the same batch is still in progress is refused with `409`.
### `listSessions(batchId: string, params?: PaymentBatchListParams): Promise<PaymentBatchSessionListResponse>`
List the runs of a batch. `meta.results` on each run holds the result for every recipient, keyed by `recipientId`.
## Key permissions
| Methods | Permission |
| ----------------------------------------------------------------------------------------- | ----------------------------- |
| `list`, `get`, `listRecipients` | `PAYMENT_METHOD.READ` |
| `create`, `update`, `delete`, `addRecipient`, `addRecipients`, `updateRecipient`, `removeRecipient` | `PAYMENT_METHOD.CREATE` |
| `withdraw` | `TRANSACTION.WITHDRAW.CREATE` |
| `listSessions` | `TRANSACTION.HISTORY.READ` |
A key without the permission is answered with `401`.
## License
MIT