@pulsebyshiga/node 0.2.0 → 0.2.1
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/README.md +54 -49
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
# @pulsebyshiga/node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
name-enquiry, collection sessions, and webhook verification. Idempotent requests,
|
|
5
|
-
|
|
3
|
+
The official Node.js SDK for the Pulse API — quotes, offramp and onramp orders, bank
|
|
4
|
+
name-enquiry, collection sessions, and webhook verification. Idempotent requests, automatic
|
|
5
|
+
retries, and fully-typed responses and errors are built in.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
> ([Swagger](https://engine-api.shiga.io/swagger/public/index.html)). The collection-session
|
|
10
|
-
> and webhook surface is the product extension landing in the engine — see
|
|
11
|
-
> [docs/engine-gap.md](../../docs/engine-gap.md).
|
|
7
|
+
Server-side only: your `sk_*` key and user identity (BVN/NIN) never leave your backend. The
|
|
8
|
+
browser and mobile SDKs receive only a short-lived, single-order session token (`cs_*`).
|
|
12
9
|
|
|
13
|
-
**
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
> **Pre-release (0.2.0).** The public API may still change. Quotes, offramp/onramp orders, and
|
|
11
|
+
> bank name-enquiry map 1:1 to the live engine contract
|
|
12
|
+
> ([Swagger](https://engine-api.shiga.io/swagger/public/index.html)).
|
|
16
13
|
|
|
17
14
|
## Requirements
|
|
18
15
|
|
|
@@ -26,7 +23,7 @@ npm install @pulsebyshiga/node
|
|
|
26
23
|
# pnpm add @pulsebyshiga/node · yarn add @pulsebyshiga/node
|
|
27
24
|
```
|
|
28
25
|
|
|
29
|
-
##
|
|
26
|
+
## Quickstart
|
|
30
27
|
|
|
31
28
|
```ts
|
|
32
29
|
import Pulse, { useApiKey } from '@pulsebyshiga/node';
|
|
@@ -34,21 +31,28 @@ import Pulse, { useApiKey } from '@pulsebyshiga/node';
|
|
|
34
31
|
const pulse = new Pulse(useApiKey(process.env.PULSE_API_KEY), {
|
|
35
32
|
webhookSecret: process.env.PULSE_WEBHOOK_SECRET,
|
|
36
33
|
});
|
|
34
|
+
|
|
35
|
+
// Lock a price, then create an order against it.
|
|
36
|
+
const quote = await pulse.quotes.create({
|
|
37
|
+
amount: '100.50',
|
|
38
|
+
source_currency: 'USDC',
|
|
39
|
+
destination_currency: 'NGN',
|
|
40
|
+
network: 'BASE',
|
|
41
|
+
});
|
|
37
42
|
```
|
|
38
43
|
|
|
39
44
|
`useApiKey(...)` declares the server credential (a bare string still works for back-compat).
|
|
40
|
-
The key is sent as `X-API-Key` (the engine's
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
sandbox.
|
|
45
|
+
The key is sent as `X-API-Key` (the engine's scheme) and as a `Bearer` token (the session
|
|
46
|
+
surface's scheme) — one key, both means. The default host is `https://engine-api.shiga.io`;
|
|
47
|
+
override it with `baseUrl` for local development or a future sandbox.
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
## Core concept — quote first
|
|
46
50
|
|
|
47
|
-
Everything starts with a locked price
|
|
48
|
-
`expires_at` passes.
|
|
51
|
+
Everything starts with a locked price. Create a quote, then create an order from `quote.id`
|
|
52
|
+
before `expires_at` passes. Amounts are decimal strings; networks are UPPERCASE.
|
|
49
53
|
|
|
50
|
-
**Just the rate
|
|
51
|
-
|
|
54
|
+
**Just the rate, no order** — `rates.preview` wraps a quote for display; nothing settles and no
|
|
55
|
+
order is created:
|
|
52
56
|
|
|
53
57
|
```ts
|
|
54
58
|
const rate = await pulse.rates.preview({
|
|
@@ -61,7 +65,9 @@ const rate = await pulse.rates.preview({
|
|
|
61
65
|
// Proceed to an order with quoteId to transact at exactly this locked rate.
|
|
62
66
|
```
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
## Offramp — crypto in, fiat out
|
|
69
|
+
|
|
70
|
+
The collection direction. Verify the payout account (name enquiry), then create the order:
|
|
65
71
|
|
|
66
72
|
```ts
|
|
67
73
|
const quote = await pulse.quotes.create({
|
|
@@ -71,7 +77,6 @@ const quote = await pulse.quotes.create({
|
|
|
71
77
|
network: 'BASE', // BASE | POLYGON | ARBITRUM | OPTIMISM | ETHEREUM | BSC
|
|
72
78
|
});
|
|
73
79
|
|
|
74
|
-
// Verify the payout account first (name enquiry).
|
|
75
80
|
const account = await pulse.banks.resolve({ account_number: '0123456789', bank_code: '000013' });
|
|
76
81
|
|
|
77
82
|
const order = await pulse.offramp.create({
|
|
@@ -88,7 +93,7 @@ const order = await pulse.offramp.create({
|
|
|
88
93
|
// Poll pulse.offramp.retrieve(order.id) until a terminal status.
|
|
89
94
|
```
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
## Onramp — fiat in, crypto out
|
|
92
97
|
|
|
93
98
|
```ts
|
|
94
99
|
const quote = await pulse.quotes.create({
|
|
@@ -108,14 +113,15 @@ const order = await pulse.onramp.create({
|
|
|
108
113
|
// Poll pulse.onramp.retrieve(order.id) until a terminal status.
|
|
109
114
|
```
|
|
110
115
|
|
|
111
|
-
|
|
116
|
+
## Banks
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
- `pulse.banks.list()` — supported banks (name + NIP code).
|
|
119
|
+
- `pulse.banks.resolve({ account_number, bank_code })` — name enquiry; run it before creating an offramp order.
|
|
114
120
|
|
|
115
|
-
|
|
116
|
-
[docs/engine-gap.md](../../docs/engine-gap.md) tracks its adoption into the engine.
|
|
121
|
+
## Collection sessions
|
|
117
122
|
|
|
118
|
-
|
|
123
|
+
The surface the embedded components run on. Create a session server-side and hand the `cs_*`
|
|
124
|
+
token to your frontend — nothing else.
|
|
119
125
|
|
|
120
126
|
```ts
|
|
121
127
|
// Naira gate — funds settle to the user's named virtual account.
|
|
@@ -143,11 +149,10 @@ const usdSession = await pulse.collectionSessions.create({
|
|
|
143
149
|
// Hand session.session_token (cs_*) to your frontend. Nothing else.
|
|
144
150
|
```
|
|
145
151
|
|
|
146
|
-
**Direction.** Sessions default to `offramp` (crypto in → fiat out). Pass
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
instructions instead of a deposit address/QR).
|
|
152
|
+
**Direction.** Sessions default to `offramp` (crypto in → fiat out). Pass `direction: 'onramp'`
|
|
153
|
+
for the reverse — the user pays a virtual bank account (carried on the order as `pay_account`)
|
|
154
|
+
and receives crypto at a wallet. The embedded component renders the matching UI automatically
|
|
155
|
+
(bank-transfer instructions instead of a deposit address/QR).
|
|
151
156
|
|
|
152
157
|
```ts
|
|
153
158
|
const onrampSession = await pulse.collectionSessions.create({
|
|
@@ -161,7 +166,7 @@ const onrampSession = await pulse.collectionSessions.create({
|
|
|
161
166
|
});
|
|
162
167
|
```
|
|
163
168
|
|
|
164
|
-
|
|
169
|
+
**Query orders.**
|
|
165
170
|
|
|
166
171
|
```ts
|
|
167
172
|
const order = await pulse.collectionOrders.retrieve(orderId); // ground truth for one order
|
|
@@ -235,14 +240,9 @@ embed's `onSuccess` are UX signals and can be spoofed; the signed webhook cannot
|
|
|
235
240
|
|
|
236
241
|
## Reliability
|
|
237
242
|
|
|
238
|
-
- **Idempotency** — every POST carries an `Idempotency-Key` (yours via `idempotencyKey`,
|
|
239
|
-
|
|
240
|
-
- **
|
|
241
|
-
(2 retries, 250 ms base delay by default). Other 4xx responses throw immediately.
|
|
242
|
-
- **Identification, not telemetry** — every request carries a static
|
|
243
|
-
`X-Pulse-SDK: pulse-node/<version> node/<version> (<platform>)` header so the API can
|
|
244
|
-
measure adoption and error rates per SDK version server-side. The SDK never emits
|
|
245
|
-
telemetry from your infrastructure.
|
|
243
|
+
- **Idempotency** — every POST carries an `Idempotency-Key` (yours via `idempotencyKey`, otherwise a generated UUID), so retries can never double-create an order.
|
|
244
|
+
- **Retries** — network errors, HTTP 429, and 5xx are retried with exponential backoff (2 retries, 250 ms base delay by default). Other 4xx responses throw immediately.
|
|
245
|
+
- **Identification, not telemetry** — every request carries a static `X-Pulse-SDK: pulse-node/<version> node/<version> (<platform>)` header so the API can measure adoption and error rates per SDK version. The SDK never emits telemetry from your infrastructure.
|
|
246
246
|
|
|
247
247
|
## Configuration
|
|
248
248
|
|
|
@@ -252,7 +252,7 @@ new Pulse(apiKey, options?)
|
|
|
252
252
|
|
|
253
253
|
| Option | Type | Default | Description |
|
|
254
254
|
| ------------------- | --------------------- | ----------------------- | ------------------------------------------------------------------- |
|
|
255
|
-
| `baseUrl` | `string` | derived from key prefix | API host override (local
|
|
255
|
+
| `baseUrl` | `string` | derived from key prefix | API host override (local development, staging). |
|
|
256
256
|
| `maxRetries` | `number` | `2` | Retry count for network errors / 429 / 5xx. |
|
|
257
257
|
| `retryDelayMs` | `number` | `250` | Base backoff delay, doubled per attempt. |
|
|
258
258
|
| `fetchImpl` | `FetchLike` | global `fetch` | Injectable transport for tests/instrumentation. |
|
|
@@ -286,16 +286,21 @@ try {
|
|
|
286
286
|
## TypeScript
|
|
287
287
|
|
|
288
288
|
Written in TypeScript; every request, response, webhook event, and error is fully typed and
|
|
289
|
-
exported (`CollectionOrder`, `WebhookEvent`, `PartnerConfig`, `Network`, …). The webhook
|
|
290
|
-
|
|
289
|
+
exported (`CollectionOrder`, `WebhookEvent`, `PartnerConfig`, `Network`, …). The webhook event
|
|
290
|
+
union discriminates on `type`, so a `switch` narrows `event.data` automatically.
|
|
291
291
|
|
|
292
292
|
## Security model
|
|
293
293
|
|
|
294
|
-
- `sk_*` keys and BVN/NIN are **server-to-server only** — never ship them to a browser or
|
|
295
|
-
mobile app. Clients receive only the short-lived, single-order `session_token` (`cs_*`).
|
|
294
|
+
- `sk_*` keys and BVN/NIN are **server-to-server only** — never ship them to a browser or mobile app. Clients receive only the short-lived, single-order `session_token` (`cs_*`).
|
|
296
295
|
- Verify every webhook before acting on it; verification is constant-time and replay-bounded.
|
|
297
296
|
- Credit users exclusively from the signed `disbursement.completed` event.
|
|
298
297
|
|
|
298
|
+
## Related packages
|
|
299
|
+
|
|
300
|
+
- [`@pulsebyshiga/collect-js`](https://www.npmjs.com/package/@pulsebyshiga/collect-js) — framework-agnostic web loader for the payment embed.
|
|
301
|
+
- [`@pulsebyshiga/collect-react`](https://www.npmjs.com/package/@pulsebyshiga/collect-react) — React bindings.
|
|
302
|
+
- [`@pulsebyshiga/collect-react-native`](https://www.npmjs.com/package/@pulsebyshiga/collect-react-native) — React Native bindings.
|
|
303
|
+
|
|
299
304
|
## License
|
|
300
305
|
|
|
301
|
-
|
|
306
|
+
MIT © Shiga Digital
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED