@afriex/sdk 5.1.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +155 -148
- package/dist/cjs/client.d.ts +110 -0
- package/dist/cjs/client.js +231 -0
- package/dist/cjs/core/api-promise.d.ts +25 -0
- package/dist/cjs/core/api-promise.js +49 -0
- package/dist/cjs/core/errors.d.ts +78 -0
- package/dist/cjs/core/errors.js +143 -0
- package/dist/cjs/core/pagination.d.ts +47 -0
- package/dist/cjs/core/pagination.js +70 -0
- package/dist/cjs/core/resource.d.ts +18 -0
- package/dist/cjs/core/resource.js +36 -0
- package/dist/cjs/core/types.d.ts +43 -0
- package/dist/cjs/core/types.js +2 -0
- package/dist/cjs/generated/openapi.d.ts +5750 -0
- package/dist/cjs/generated/openapi.js +6 -0
- package/dist/cjs/index.d.ts +21 -0
- package/dist/cjs/index.js +34 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/resources/balance.d.ts +16 -0
- package/dist/cjs/resources/balance.js +19 -0
- package/dist/cjs/resources/checkout.d.ts +12 -0
- package/dist/cjs/resources/checkout.js +16 -0
- package/dist/cjs/resources/customers.d.ts +27 -0
- package/dist/cjs/resources/customers.js +56 -0
- package/dist/cjs/resources/media.d.ts +24 -0
- package/dist/cjs/resources/media.js +39 -0
- package/dist/cjs/resources/payment-batches.d.ts +41 -0
- package/dist/cjs/resources/payment-batches.js +76 -0
- package/dist/cjs/resources/payment-methods.d.ts +49 -0
- package/dist/cjs/resources/payment-methods.js +95 -0
- package/dist/cjs/resources/rates.d.ts +9 -0
- package/dist/cjs/resources/rates.js +13 -0
- package/dist/cjs/resources/sme-registration.d.ts +24 -0
- package/dist/cjs/resources/sme-registration.js +31 -0
- package/dist/cjs/resources/transactions.d.ts +39 -0
- package/dist/cjs/resources/transactions.js +67 -0
- package/dist/cjs/resources/webhooks.d.ts +43 -0
- package/dist/cjs/resources/webhooks.js +53 -0
- package/dist/cjs/version.d.ts +1 -0
- package/dist/cjs/version.js +5 -0
- package/dist/esm/client.d.ts +110 -0
- package/dist/esm/client.js +227 -0
- package/dist/esm/core/api-promise.d.ts +25 -0
- package/dist/esm/core/api-promise.js +45 -0
- package/dist/esm/core/errors.d.ts +78 -0
- package/dist/esm/core/errors.js +126 -0
- package/dist/esm/core/pagination.d.ts +47 -0
- package/dist/esm/core/pagination.js +65 -0
- package/dist/esm/core/resource.d.ts +18 -0
- package/dist/esm/core/resource.js +30 -0
- package/dist/esm/core/types.d.ts +43 -0
- package/dist/esm/core/types.js +1 -0
- package/dist/esm/generated/openapi.d.ts +5750 -0
- package/dist/esm/generated/openapi.js +5 -0
- package/dist/esm/index.d.ts +21 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/resources/balance.d.ts +16 -0
- package/dist/esm/resources/balance.js +15 -0
- package/dist/esm/resources/checkout.d.ts +12 -0
- package/dist/esm/resources/checkout.js +12 -0
- package/dist/esm/resources/customers.d.ts +27 -0
- package/dist/esm/resources/customers.js +52 -0
- package/dist/esm/resources/media.d.ts +24 -0
- package/dist/esm/resources/media.js +35 -0
- package/dist/esm/resources/payment-batches.d.ts +41 -0
- package/dist/esm/resources/payment-batches.js +72 -0
- package/dist/esm/resources/payment-methods.d.ts +49 -0
- package/dist/esm/resources/payment-methods.js +91 -0
- package/dist/esm/resources/rates.d.ts +9 -0
- package/dist/esm/resources/rates.js +9 -0
- package/dist/esm/resources/sme-registration.d.ts +24 -0
- package/dist/esm/resources/sme-registration.js +27 -0
- package/dist/esm/resources/transactions.d.ts +39 -0
- package/dist/esm/resources/transactions.js +63 -0
- package/dist/esm/resources/webhooks.d.ts +43 -0
- package/dist/esm/resources/webhooks.js +49 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +2 -0
- package/package.json +52 -68
- package/dist/index.d.ts +0 -54
- package/dist/index.js +0 -54
- package/dist/version.d.ts +0 -8
- package/dist/version.js +0 -8
- package/skills/afriex-go-live/SKILL.md +0 -386
- package/skills/afriex-sdk/SKILL.md +0 -275
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@afriex/sdk`. Versions 5.x and earlier were built in the [afriex-sdk](https://github.com/Afri-exchange/afriex-sdk) repository; see its changelog for them.
|
|
4
|
+
|
|
5
|
+
<!-- Entries go below this line, newest first. -->
|
|
6
|
+
|
|
7
|
+
## 6.0.0
|
|
8
|
+
|
|
9
|
+
The SDK now lives next to the API reference and is generated from its OpenAPI spec, so it changes when the API does.
|
|
10
|
+
|
|
11
|
+
### New
|
|
12
|
+
|
|
13
|
+
- A method for every endpoint in the API reference, including `transactions.quote()`.
|
|
14
|
+
- Types for every request, response and webhook event, generated from the spec. Webhook events are a union you can narrow on `event`.
|
|
15
|
+
- `for await` over any list method walks every page. Pages also have `hasNextPage()`, `getNextPage()` and `iterPages()`.
|
|
16
|
+
- `withResponse()` on every call returns the HTTP response and its `requestId`.
|
|
17
|
+
- Per-request options as the last argument: `timeout`, `maxRetries`, `headers` and `signal`.
|
|
18
|
+
- One error class per status, each with `status`, `code`, `details`, `headers` and `requestId`.
|
|
19
|
+
- `afriex.request()` calls an endpoint the SDK doesn't cover yet.
|
|
20
|
+
- `apiKey` defaults to the `AFRIEX_API_KEY` environment variable.
|
|
21
|
+
- ESM and CommonJS builds, no runtime dependencies.
|
|
22
|
+
|
|
23
|
+
### Breaking changes, and how to migrate from 5.x
|
|
24
|
+
|
|
25
|
+
- **One package.** Import everything from `@afriex/sdk`. The SDK no longer uses `@afriex/core`, `@afriex/customers`, `@afriex/transactions` or the other per-resource packages, so remove them from your dependencies.
|
|
26
|
+
- **Node 20 or later.**
|
|
27
|
+
- **Retries are on by default** (`maxRetries: 2`), but only where they are safe: any request on `429`, and `GET` requests and `transactions.create` on timeouts and server errors. `retryConfig` is replaced by `maxRetries`, and `retryableMethods` and `retryableStatusCodes` are gone. See "Retries" in the README.
|
|
28
|
+
- **Configuration.** `customConfig.baseUrl` is now `baseURL`, and `customConfig.timeout` is now `timeout`. `userAgent`, `logLevel` and `enableLogging` are removed. `environment` takes `'sandbox'`; `'staging'` still works.
|
|
29
|
+
- **Errors.** `ApiError` is now `APIError`, with a subclass per status (`NotFoundError`, `ConflictError` and so on). `RateLimitError` extends it. `NetworkError` is now `APIConnectionError`. `ValidationError` is removed: the SDK no longer validates requests itself, and the API's `400` or `422` arrives as `BadRequestError` or `UnprocessableEntityError`.
|
|
30
|
+
- **Return values.** Every method resolves to the response's `data`, except:
|
|
31
|
+
- list methods, which resolve to a page, `{data, total, page}`, as before;
|
|
32
|
+
- `paymentMethods.getInstitutions()` and `paymentMethods.listVirtualAccounts()`, which resolve to the whole response, as before;
|
|
33
|
+
- `paymentMethods.delete()`, which resolves to the whole response.
|
|
34
|
+
|
|
35
|
+
`paymentMethods.resolveAccount()`, `paymentMethods.resolveInstitutionCode()`, `paymentMethods.getCryptoWallet()` and `webhooks.triggerTestWebhook()` used to resolve to the whole response and now resolve to its `data`. `customers.delete()`, `paymentBatches.delete()` and `paymentBatches.removeRecipient()` used to resolve to nothing and now resolve to the response's `data`. `paymentMethods.createVirtualAccount()` resolves to the response's `data` rather than `null` when the account opens later.
|
|
36
|
+
- **Type names** follow the spec and the `<Resource><Action>Params` pattern: `CreateCustomerRequest` is now `CustomerCreateParams`, `ListTransactionsParams` is now `TransactionListParams`, `WebhookPayload` is now `WebhookEvent`, and so on. Field types are exactly what the spec says. Where the spec does not mark a response field as required, its type is optional.
|
|
37
|
+
- **Removed helpers:** `balance.getBalanceForCurrency()`, `rates.getRate()` and `rates.convert()`. Use `balance.getBalance()` and `rates.getRates()`.
|
|
38
|
+
- **Webhooks.** The `WebhookVerifier` class and the `webhookVerifier` property are removed: create the client with `webhookPublicKey` and call `afriex.webhooks.verify()` or `verifyAndParse()`. Both now accept the header value as Node gives it (`string | string[] | undefined`). `verifyAndParse()` throws `WebhookVerificationError`. `triggerTestWebhook()` no longer accepts the deprecated `resourceId`: use `entityId`.
|
|
39
|
+
- `paymentMethods.listPoolAccounts()` is deprecated: use `paymentMethods.getPoolAccount()`.
|
package/README.md
CHANGED
|
@@ -1,199 +1,206 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Afriex TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The official TypeScript and JavaScript client for the [Afriex Business API](https://docs.afriex.com). It is generated from the same OpenAPI spec as the API reference, so its types always match the documented API.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- One package, no runtime dependencies, built on the platform's `fetch`
|
|
6
|
+
- Full types for every request, response and webhook event
|
|
7
|
+
- Retries with backoff where they are safe, timeouts, and typed errors
|
|
8
|
+
- Pagination you can `for await` over
|
|
9
|
+
- ESM and CommonJS, Node 20 or later
|
|
10
|
+
|
|
11
|
+
## Install
|
|
6
12
|
|
|
7
13
|
```bash
|
|
8
14
|
npm install @afriex/sdk
|
|
9
|
-
# or
|
|
10
|
-
pnpm add @afriex/sdk
|
|
11
15
|
```
|
|
12
16
|
|
|
13
|
-
##
|
|
17
|
+
## Usage
|
|
14
18
|
|
|
15
|
-
```
|
|
16
|
-
import {
|
|
17
|
-
// or use the alias
|
|
18
|
-
import { Afriex } from "@afriex/sdk";
|
|
19
|
+
```ts
|
|
20
|
+
import {Afriex} from '@afriex/sdk';
|
|
19
21
|
|
|
20
|
-
const afriex = new
|
|
21
|
-
apiKey:
|
|
22
|
-
environment:
|
|
23
|
-
webhookPublicKey: "-----BEGIN PUBLIC KEY-----...", // optional
|
|
22
|
+
const afriex = new Afriex({
|
|
23
|
+
apiKey: process.env.AFRIEX_API_KEY, // the default, so you can leave it out
|
|
24
|
+
environment: 'sandbox', // or 'production', the default
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
// Customers
|
|
27
27
|
const customer = await afriex.customers.create({
|
|
28
|
-
fullName:
|
|
29
|
-
email:
|
|
30
|
-
phone:
|
|
31
|
-
countryCode:
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Payment Methods
|
|
35
|
-
const paymentMethod = await afriex.paymentMethods.create({
|
|
36
|
-
customerId: customer.customerId,
|
|
37
|
-
channel: "BANK_ACCOUNT",
|
|
38
|
-
accountName: "John Doe",
|
|
39
|
-
accountNumber: "1234567890",
|
|
40
|
-
countryCode: "NG",
|
|
41
|
-
institution: {
|
|
42
|
-
institutionCode: "058",
|
|
43
|
-
institutionName: "GTBank",
|
|
44
|
-
},
|
|
28
|
+
fullName: 'Ada Obi',
|
|
29
|
+
email: 'ada@example.com',
|
|
30
|
+
phone: '+2348012345678',
|
|
31
|
+
countryCode: 'NG',
|
|
45
32
|
});
|
|
46
33
|
|
|
47
|
-
// Transactions
|
|
48
34
|
const transaction = await afriex.transactions.create({
|
|
49
|
-
customerId: customer.customerId
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
sourceCurrency:
|
|
53
|
-
destinationCurrency:
|
|
54
|
-
|
|
55
|
-
meta: {
|
|
56
|
-
idempotencyKey: "quick-start-transaction-1",
|
|
57
|
-
reference: "order-123",
|
|
58
|
-
},
|
|
35
|
+
customerId: customer.customerId!,
|
|
36
|
+
destinationId: 'payment-method-id',
|
|
37
|
+
sourceAmount: '10',
|
|
38
|
+
sourceCurrency: 'USD',
|
|
39
|
+
destinationCurrency: 'NGN',
|
|
40
|
+
meta: {idempotencyKey: crypto.randomUUID(), reference: 'order-456'},
|
|
59
41
|
});
|
|
42
|
+
```
|
|
60
43
|
|
|
61
|
-
|
|
62
|
-
const rate = await afriex.rates.getRate("USD", "NGN");
|
|
44
|
+
Every endpoint in the [API reference](https://docs.afriex.com/api-reference/introduction) has a method, grouped by resource: `customers`, `transactions`, `paymentMethods`, `paymentBatches`, `balance`, `rates`, `checkout`, `media`, `smeRegistration` and `webhooks`. Each endpoint page shows its SDK call.
|
|
63
45
|
|
|
64
|
-
|
|
65
|
-
const balances = await afriex.balance.getBalance({
|
|
66
|
-
currencies: ["USD", "NGN"],
|
|
67
|
-
});
|
|
46
|
+
Keep your API key on your server. The SDK refuses to run in a browser.
|
|
68
47
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
48
|
+
## Configuration
|
|
49
|
+
|
|
50
|
+
| Option | Default | Description |
|
|
51
|
+
| :-- | :-- | :-- |
|
|
52
|
+
| `apiKey` | `AFRIEX_API_KEY` | Your API key, from **Developer → API keys** in the dashboard |
|
|
53
|
+
| `environment` | `'production'` | `'sandbox'` or `'production'`. `'staging'` also means the sandbox |
|
|
54
|
+
| `baseURL` | from `environment` | Overrides the base URL |
|
|
55
|
+
| `timeout` | `30000` | Milliseconds to wait for each attempt |
|
|
56
|
+
| `maxRetries` | `2` | Retries for a failed request. See [Retries](#retries) |
|
|
57
|
+
| `apiVersion` | `'2026-05-18'` | Sent as `x-api-version`. Each SDK release targets one API version |
|
|
58
|
+
| `webhookPublicKey` | none | Verifies webhook signatures. See [Webhooks](#webhooks) |
|
|
59
|
+
| `signRequest` | none | Returns the `x-api-signature` for a request, if your business has [request signing](https://docs.afriex.com/api-reference/authentication#request-signing) enabled |
|
|
60
|
+
| `defaultHeaders` | none | Headers sent with every request |
|
|
61
|
+
| `fetch` | global `fetch` | A `fetch` implementation to use instead |
|
|
62
|
+
|
|
63
|
+
`environment` defaults to production, so set it while you integrate.
|
|
64
|
+
|
|
65
|
+
## Per-request options
|
|
66
|
+
|
|
67
|
+
Every method takes an options object last:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const customer = await afriex.customers.get('customer-id', {
|
|
71
|
+
timeout: 5_000,
|
|
72
|
+
maxRetries: 0,
|
|
73
|
+
signal: AbortSignal.timeout(10_000),
|
|
74
|
+
headers: {'x-correlation-id': 'abc'},
|
|
82
75
|
});
|
|
83
|
-
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Errors
|
|
84
79
|
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
A failed request throws. A response outside 2xx throws an `APIError` subclass that carries the status, the API's error `code` and `details`, the response headers, and the `requestId` to quote to support:
|
|
81
|
+
|
|
82
|
+
| Status | Error |
|
|
83
|
+
| :-- | :-- |
|
|
84
|
+
| 400 | `BadRequestError` |
|
|
85
|
+
| 401 | `AuthenticationError` (wrong key, or a key without this endpoint's permission) |
|
|
86
|
+
| 403 | `PermissionDeniedError` |
|
|
87
|
+
| 404 | `NotFoundError` |
|
|
88
|
+
| 409 | `ConflictError` |
|
|
89
|
+
| 422 | `UnprocessableEntityError` |
|
|
90
|
+
| 429 | `RateLimitError`, with `retryAfter` in seconds |
|
|
91
|
+
| 500 and above | `InternalServerError` |
|
|
92
|
+
| no response | `APIConnectionError`, or `APIConnectionTimeoutError` after the timeout |
|
|
93
|
+
| you aborted | `APIUserAbortError` |
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import {APIError, ConflictError} from '@afriex/sdk';
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
await afriex.transactions.create(params);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error instanceof ConflictError && error.code === 'DUPLICATE_REQUEST') {
|
|
102
|
+
// The idempotency key or reference is taken: look the transaction up.
|
|
103
|
+
const page = await afriex.transactions.list({reference: params.meta?.reference});
|
|
104
|
+
} else if (error instanceof APIError) {
|
|
105
|
+
console.error(error.status, error.code, error.requestId);
|
|
106
|
+
}
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
87
109
|
```
|
|
88
110
|
|
|
89
|
-
|
|
111
|
+
Every error extends `AfriexError`.
|
|
90
112
|
|
|
91
|
-
|
|
92
|
-
| ----------------------- | ---------------------------------------------------------- |
|
|
93
|
-
| `afriex.customers` | Customer CRUD, KYC updates, and document verification |
|
|
94
|
-
| `afriex.transactions` | Create, authorize, list, and track transactions |
|
|
95
|
-
| `afriex.paymentMethods` | Bank, mobile money, crypto wallets, virtual & pool accounts |
|
|
96
|
-
| `afriex.paymentBatches` | Pay many recipients in one call |
|
|
97
|
-
| `afriex.balance` | Organization wallet balances and sandbox top-ups |
|
|
98
|
-
| `afriex.rates` | Exchange rates and conversions |
|
|
99
|
-
| `afriex.checkout` | Hosted checkout sessions (card, virtual account, momo) |
|
|
100
|
-
| `afriex.media` | Upload invoices, payment proofs and documents |
|
|
101
|
-
| `afriex.smeRegistration` | Register the business for dedicated KES virtual accounts |
|
|
102
|
-
| `afriex.webhooks` | Webhook signature verification and sandbox test triggers |
|
|
113
|
+
## Retries
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
unless a `webhookPublicKey` was provided; `afriex.webhookVerifier` is set only when one was.
|
|
115
|
+
The SDK retries a request only when sending it again can't repeat its effect:
|
|
106
116
|
|
|
107
|
-
|
|
117
|
+
- **Every request on `429`.** The API rejects it before doing anything. The SDK waits for `Retry-After`.
|
|
118
|
+
- **`GET` requests,** and **`transactions.create`,** on a timeout, a dropped connection, `408` or a `5xx`. A transaction create is safe to send again because the API refuses a second request with the same `meta.idempotencyKey`. If the first attempt went through, the retry gets `409 DUPLICATE_REQUEST`: look the transaction up by its reference. See [Idempotency](https://docs.afriex.com/api-reference/idempotency).
|
|
108
119
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
Other `POST`, `PATCH` and `DELETE` requests are not retried on errors. The API has no idempotency key for them, so a retry could create a second customer or payment method.
|
|
121
|
+
|
|
122
|
+
Retries wait 0.5 seconds, doubling each time up to 8 seconds, with jitter. Set `maxRetries: 0` to turn them off.
|
|
123
|
+
|
|
124
|
+
## Pagination
|
|
125
|
+
|
|
126
|
+
List methods return the first page as the API sends it, `{data, total, page}`:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const page = await afriex.transactions.list({limit: 100, status: ['SUCCESS']});
|
|
130
|
+
console.log(page.data, page.total);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Iterate the call with `for await` to walk every item across every page:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
for await (const transaction of afriex.transactions.list({limit: 100})) {
|
|
137
|
+
console.log(transaction.transactionId);
|
|
126
138
|
}
|
|
127
139
|
```
|
|
128
140
|
|
|
129
|
-
|
|
141
|
+
A page also has `hasNextPage()`, `getNextPage()` and `iterPages()`.
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
still sent once unless `retryableMethods` lists them. See
|
|
133
|
-
[`@afriex/core`](https://www.npmjs.com/package/@afriex/core) for retries and
|
|
134
|
-
request signing.
|
|
143
|
+
## Webhooks
|
|
135
144
|
|
|
136
|
-
|
|
137
|
-
`https://api.afriex.com/api/v1`.
|
|
145
|
+
Verify a webhook before you act on it. The signature covers the exact bytes Afriex sent, so pass the raw body, not parsed JSON:
|
|
138
146
|
|
|
139
|
-
|
|
147
|
+
```ts
|
|
148
|
+
import express from 'express';
|
|
149
|
+
import {Afriex, WEBHOOK_SIGNATURE_HEADER, WebhookVerificationError} from '@afriex/sdk';
|
|
140
150
|
|
|
141
|
-
|
|
151
|
+
const afriex = new Afriex({webhookPublicKey: process.env.AFRIEX_WEBHOOK_PUBLIC_KEY});
|
|
152
|
+
const app = express();
|
|
142
153
|
|
|
143
|
-
|
|
144
|
-
|
|
154
|
+
app.post('/webhooks/afriex', express.raw({type: 'application/json'}), (req, res) => {
|
|
155
|
+
let event;
|
|
156
|
+
try {
|
|
157
|
+
event = afriex.webhooks.verifyAndParse(req.body, req.headers[WEBHOOK_SIGNATURE_HEADER]);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error instanceof WebhookVerificationError) return res.status(400).send('Invalid signature');
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
145
162
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
} else if (error instanceof ApiError) {
|
|
154
|
-
// Non-2xx response from the API
|
|
155
|
-
} else if (error instanceof NetworkError) {
|
|
156
|
-
// Connection/timeout failure
|
|
163
|
+
switch (event.event) {
|
|
164
|
+
case 'TRANSACTION.UPDATED':
|
|
165
|
+
console.log(event.data.transactionId, event.data.status);
|
|
166
|
+
break;
|
|
167
|
+
case 'CUSTOMER.CREATED':
|
|
168
|
+
console.log(event.data.customerId);
|
|
169
|
+
break;
|
|
157
170
|
}
|
|
158
|
-
|
|
171
|
+
res.sendStatus(200);
|
|
172
|
+
});
|
|
159
173
|
```
|
|
160
174
|
|
|
161
|
-
|
|
175
|
+
`event` is typed by its `event` name. `afriex.webhooks.verify()` returns a boolean instead of throwing. Store each event before you acknowledge it, keyed on `event.id`: see [Duplicates, ordering, and replays](https://docs.afriex.com/api-reference/endpoint/webhooks/introduction#duplicates-ordering-and-replays).
|
|
162
176
|
|
|
163
|
-
|
|
177
|
+
## The raw response
|
|
164
178
|
|
|
165
|
-
|
|
166
|
-
| ------------------------- | ------------------------------------------------------ |
|
|
167
|
-
| `@afriex/core` | Base client, config, HTTP layer, errors, shared types |
|
|
168
|
-
| `@afriex/customers` | Customer management and KYC |
|
|
169
|
-
| `@afriex/transactions` | Transaction handling |
|
|
170
|
-
| `@afriex/payment-methods` | Payment methods, institutions, virtual & pool accounts |
|
|
171
|
-
| `@afriex/payment-batches` | Bulk payouts to a saved list of recipients |
|
|
172
|
-
| `@afriex/balance` | Balance queries and sandbox top-ups |
|
|
173
|
-
| `@afriex/rates` | Exchange rates and conversions |
|
|
174
|
-
| `@afriex/checkout` | Hosted checkout sessions |
|
|
175
|
-
| `@afriex/media` | File uploads |
|
|
176
|
-
| `@afriex/sme-registration` | SME registration for KES virtual accounts |
|
|
177
|
-
| `@afriex/webhooks` | Webhook verification and test triggers |
|
|
179
|
+
Every method returns an `APIPromise`. Call `withResponse()` for the HTTP response and its request id:
|
|
178
180
|
|
|
179
|
-
|
|
181
|
+
```ts
|
|
182
|
+
const {data: customer, response, requestId} = await afriex.customers.get('customer-id').withResponse();
|
|
183
|
+
```
|
|
180
184
|
|
|
181
|
-
##
|
|
185
|
+
## Types
|
|
182
186
|
|
|
183
|
-
Every
|
|
184
|
-
`skills/`, so coding agents get grounded guidance on this SDK instead of guessing at the API.
|
|
185
|
-
If you use an AI agent, run:
|
|
187
|
+
Request and response types are exported by name, such as `Customer`, `Transaction`, `TransactionCreateParams` and `WebhookEvent`. Every type in the spec is also available under the `OpenAPI` namespace:
|
|
186
188
|
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
+
```ts
|
|
190
|
+
import type {OpenAPI} from '@afriex/sdk';
|
|
191
|
+
type Status = OpenAPI.components['schemas']['TransactionStatus'];
|
|
189
192
|
```
|
|
190
193
|
|
|
191
|
-
|
|
194
|
+
An endpoint the SDK doesn't cover yet can be called with `afriex.request('get', '/api/v1/...', {query})`.
|
|
195
|
+
|
|
196
|
+
## Requirements
|
|
197
|
+
|
|
198
|
+
Node 20 or later. The SDK uses `fetch` and `node:crypto` (for webhooks), so it also runs on Bun, Deno, and edge runtimes with Node compatibility.
|
|
192
199
|
|
|
193
|
-
##
|
|
200
|
+
## Versioning
|
|
194
201
|
|
|
195
|
-
|
|
202
|
+
The SDK follows [semantic versioning](https://semver.org). Each release targets the API version in `API_VERSION`. A change to the API that adds to it ships as a minor release; one that would break existing code ships as a major release. Releases are listed in the [changelog](https://docs.afriex.com/changelog), and [Upgrading from version 5](https://docs.afriex.com/sdk/introduction#upgrading-from-version-5) covers the move to 6.0.
|
|
196
203
|
|
|
197
|
-
##
|
|
204
|
+
## Support
|
|
198
205
|
|
|
199
|
-
|
|
206
|
+
Full documentation is at [docs.afriex.com/sdk](https://docs.afriex.com/sdk/introduction). If something doesn't work as documented, email [support@afriex.com](mailto:support@afriex.com) with the `requestId` from the error.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { APIPromise } from './core/api-promise.js';
|
|
2
|
+
import { PagePromise } from './core/pagination.js';
|
|
3
|
+
import type { RequestOptions } from './core/types.js';
|
|
4
|
+
import { Balance } from './resources/balance.js';
|
|
5
|
+
import { Checkout } from './resources/checkout.js';
|
|
6
|
+
import { Customers } from './resources/customers.js';
|
|
7
|
+
import { Media } from './resources/media.js';
|
|
8
|
+
import { PaymentBatches } from './resources/payment-batches.js';
|
|
9
|
+
import { PaymentMethods } from './resources/payment-methods.js';
|
|
10
|
+
import { Rates } from './resources/rates.js';
|
|
11
|
+
import { SmeRegistration } from './resources/sme-registration.js';
|
|
12
|
+
import { Transactions } from './resources/transactions.js';
|
|
13
|
+
import { Webhooks } from './resources/webhooks.js';
|
|
14
|
+
/** The base URL of each environment. `staging` is the sandbox's older name. */
|
|
15
|
+
export declare const ENVIRONMENTS: {
|
|
16
|
+
readonly sandbox: "https://sandbox.api.afriex.com";
|
|
17
|
+
readonly staging: "https://sandbox.api.afriex.com";
|
|
18
|
+
readonly production: "https://api.afriex.com";
|
|
19
|
+
};
|
|
20
|
+
export type Environment = keyof typeof ENVIRONMENTS;
|
|
21
|
+
/**
|
|
22
|
+
* The API version this release of the SDK was built against, sent as
|
|
23
|
+
* `x-api-version`. Each SDK release targets one API version.
|
|
24
|
+
*/
|
|
25
|
+
export declare const API_VERSION = "2026-05-18";
|
|
26
|
+
/** What `signRequest` receives: the request exactly as it will be sent. */
|
|
27
|
+
export interface SignableRequest {
|
|
28
|
+
method: string;
|
|
29
|
+
url: string;
|
|
30
|
+
body: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ClientOptions {
|
|
33
|
+
/** Your Afriex API key. Defaults to the `AFRIEX_API_KEY` environment variable. */
|
|
34
|
+
apiKey?: string;
|
|
35
|
+
/**
|
|
36
|
+
* `'sandbox'` or `'production'`. Defaults to `'production'`, so set it
|
|
37
|
+
* explicitly while you integrate. `'staging'` is accepted as the sandbox.
|
|
38
|
+
*/
|
|
39
|
+
environment?: Environment;
|
|
40
|
+
/** Overrides the base URL that `environment` selects. */
|
|
41
|
+
baseURL?: string;
|
|
42
|
+
/** Sent as `x-api-version`. Defaults to `API_VERSION`. */
|
|
43
|
+
apiVersion?: string;
|
|
44
|
+
/** Milliseconds to wait for each attempt. Defaults to 30 seconds. */
|
|
45
|
+
timeout?: number;
|
|
46
|
+
/**
|
|
47
|
+
* How many times to retry a failed request. Defaults to 2. See the README
|
|
48
|
+
* for which requests are retried.
|
|
49
|
+
*/
|
|
50
|
+
maxRetries?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Returns the `x-api-signature` for a request, if your business has request
|
|
53
|
+
* signing enabled.
|
|
54
|
+
*/
|
|
55
|
+
signRequest?: (request: SignableRequest) => string | undefined | Promise<string | undefined>;
|
|
56
|
+
/** Afriex's public key for webhook signatures, from **Developer → Webhook** in the dashboard. */
|
|
57
|
+
webhookPublicKey?: string;
|
|
58
|
+
/** Headers sent with every request. */
|
|
59
|
+
defaultHeaders?: Record<string, string>;
|
|
60
|
+
/** A `fetch` implementation to use instead of the global one. */
|
|
61
|
+
fetch?: typeof fetch;
|
|
62
|
+
/**
|
|
63
|
+
* The SDK refuses to run in a browser, where your API key would be visible
|
|
64
|
+
* to anyone. Set this only if you understand that.
|
|
65
|
+
*/
|
|
66
|
+
dangerouslyAllowBrowser?: boolean;
|
|
67
|
+
}
|
|
68
|
+
type Method = 'get' | 'post' | 'patch' | 'delete';
|
|
69
|
+
export interface APIRequestInit {
|
|
70
|
+
query?: object;
|
|
71
|
+
body?: unknown;
|
|
72
|
+
/**
|
|
73
|
+
* Safe to send twice: retried on timeouts and server errors as well as on
|
|
74
|
+
* 429. True for every GET; set it for a POST whose body carries an
|
|
75
|
+
* idempotency key.
|
|
76
|
+
*/
|
|
77
|
+
idempotent?: boolean;
|
|
78
|
+
options?: RequestOptions;
|
|
79
|
+
}
|
|
80
|
+
export declare class Afriex {
|
|
81
|
+
#private;
|
|
82
|
+
readonly customers: Customers;
|
|
83
|
+
readonly transactions: Transactions;
|
|
84
|
+
readonly paymentMethods: PaymentMethods;
|
|
85
|
+
readonly paymentBatches: PaymentBatches;
|
|
86
|
+
readonly balance: Balance;
|
|
87
|
+
readonly rates: Rates;
|
|
88
|
+
readonly checkout: Checkout;
|
|
89
|
+
readonly media: Media;
|
|
90
|
+
readonly smeRegistration: SmeRegistration;
|
|
91
|
+
readonly webhooks: Webhooks;
|
|
92
|
+
readonly baseURL: string;
|
|
93
|
+
readonly apiVersion: string;
|
|
94
|
+
readonly timeout: number;
|
|
95
|
+
readonly maxRetries: number;
|
|
96
|
+
constructor(options?: ClientOptions);
|
|
97
|
+
/**
|
|
98
|
+
* Sends a request and returns the parsed JSON body. The resource methods
|
|
99
|
+
* call this; use it yourself only for an endpoint they don't cover yet.
|
|
100
|
+
*/
|
|
101
|
+
request<T>(method: Method, path: string, init?: APIRequestInit): APIPromise<T>;
|
|
102
|
+
/** @internal Fetches one page of a list endpoint. */
|
|
103
|
+
getPage<Item>(path: string, query?: {
|
|
104
|
+
page?: number;
|
|
105
|
+
limit?: number;
|
|
106
|
+
} & object, options?: RequestOptions): PagePromise<Item>;
|
|
107
|
+
/** @internal Sends a request with the configured `fetch`, without the API key. For presigned upload URLs. */
|
|
108
|
+
fetchUnauthenticated(url: string, init: RequestInit): Promise<Response>;
|
|
109
|
+
}
|
|
110
|
+
export {};
|