@durrapay/sdk 0.1.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/README.md +47 -0
- package/index.mjs +101 -0
- package/package.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @durrapay/sdk (Node)
|
|
2
|
+
|
|
3
|
+
Thin, dependency-free client for the [DurraPay Platform API](https://developer.durrapay.com).
|
|
4
|
+
Requires Node 18+.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install @durrapay/sdk
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import { DurraPay } from '@durrapay/sdk'
|
|
12
|
+
|
|
13
|
+
const dp = new DurraPay({
|
|
14
|
+
apiKey: process.env.DURRAPAY_KEY, // dpk_test_... or dpk_live_...
|
|
15
|
+
// baseUrl: 'https://api.durrapay.com/v1', // default
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
// Who am I?
|
|
19
|
+
console.log(await dp.me())
|
|
20
|
+
|
|
21
|
+
// Collect in Kenya (M-Pesa STK)
|
|
22
|
+
const c = await dp.collections.stk({
|
|
23
|
+
phone: '254712345678',
|
|
24
|
+
amount_minor: 150000, // KES 1,500.00 (minor units)
|
|
25
|
+
currency: 'KES',
|
|
26
|
+
reference: 'ORDER-1001',
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// Poll status (or use webhooks)
|
|
30
|
+
await dp.collections.get(c.payment_id)
|
|
31
|
+
|
|
32
|
+
// Send cross-border (FX + payout)
|
|
33
|
+
const quote = await dp.transfers.quote({ from_currency: 'KES', destination_country: 'TZ', from_amount_minor: 1000000 })
|
|
34
|
+
await dp.transfers.create({
|
|
35
|
+
quote_id: quote.quote_id,
|
|
36
|
+
dest_type: 'PHONE',
|
|
37
|
+
dest_phone: '255712345678',
|
|
38
|
+
dest_name: 'Jane Doe',
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Customers, recipients, payment links, balances, usage…
|
|
42
|
+
await dp.customers.create({ name: 'Jane Doe', email: 'jane@example.com' })
|
|
43
|
+
await dp.balances()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Idempotency keys are auto-generated for POSTs (override with `{ idempotencyKey }`).
|
|
47
|
+
Errors throw `DurraPayError` with `.status`, `.code`, and `.body`.
|
package/index.mjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// DurraPay Node SDK — a thin, dependency-free client for the /v1 Platform API.
|
|
2
|
+
// Requires Node 18+ (global fetch).
|
|
3
|
+
//
|
|
4
|
+
// import { DurraPay } from '@durrapay/sdk'
|
|
5
|
+
// const dp = new DurraPay({ apiKey: process.env.DURRAPAY_KEY })
|
|
6
|
+
// const me = await dp.me()
|
|
7
|
+
|
|
8
|
+
import { randomUUID } from 'node:crypto'
|
|
9
|
+
|
|
10
|
+
export class DurraPayError extends Error {
|
|
11
|
+
constructor(message, { status, code, body } = {}) {
|
|
12
|
+
super(message)
|
|
13
|
+
this.name = 'DurraPayError'
|
|
14
|
+
this.status = status
|
|
15
|
+
this.code = code
|
|
16
|
+
this.body = body
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class DurraPay {
|
|
21
|
+
constructor({ apiKey, baseUrl = 'https://api.durrapay.com/v1', fetch: fetchImpl } = {}) {
|
|
22
|
+
if (!apiKey) throw new Error('DurraPay: apiKey is required')
|
|
23
|
+
this._apiKey = apiKey
|
|
24
|
+
this._baseUrl = baseUrl.replace(/\/$/, '')
|
|
25
|
+
this._fetch = fetchImpl || globalThis.fetch
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async _request(method, path, { body, idempotencyKey, query } = {}) {
|
|
29
|
+
let url = this._baseUrl + path
|
|
30
|
+
if (query) {
|
|
31
|
+
const qs = new URLSearchParams(
|
|
32
|
+
Object.entries(query).filter(([, v]) => v !== undefined && v !== null)
|
|
33
|
+
).toString()
|
|
34
|
+
if (qs) url += '?' + qs
|
|
35
|
+
}
|
|
36
|
+
const headers = { 'X-DurraPay-API-Key': this._apiKey }
|
|
37
|
+
if (body) headers['Content-Type'] = 'application/json'
|
|
38
|
+
if (method === 'POST') headers['Idempotency-Key'] = idempotencyKey || randomUUID()
|
|
39
|
+
|
|
40
|
+
const res = await this._fetch(url, {
|
|
41
|
+
method,
|
|
42
|
+
headers,
|
|
43
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
44
|
+
})
|
|
45
|
+
const json = await res.json().catch(() => ({}))
|
|
46
|
+
if (!res.ok || json.success === false) {
|
|
47
|
+
const err = json.error || {}
|
|
48
|
+
throw new DurraPayError(err.message || `HTTP ${res.status}`, {
|
|
49
|
+
status: res.status,
|
|
50
|
+
code: err.code,
|
|
51
|
+
body: json,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
return json.data
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// --- identity / account ---
|
|
58
|
+
me() { return this._request('GET', '/me') }
|
|
59
|
+
balances() { return this._request('GET', '/balances') }
|
|
60
|
+
usage(days = 30) { return this._request('GET', '/usage', { query: { days } }) }
|
|
61
|
+
corridors(from = 'KES') { return this._request('GET', '/corridors', { query: { from } }) }
|
|
62
|
+
|
|
63
|
+
// --- collections ---
|
|
64
|
+
collections = {
|
|
65
|
+
stk: (input, opts = {}) => this._request('POST', '/collections/stk', { body: input, idempotencyKey: opts.idempotencyKey }),
|
|
66
|
+
list: (query = {}) => this._request('GET', '/collections', { query }),
|
|
67
|
+
get: (id) => this._request('GET', `/collections/${id}`),
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// --- payment links ---
|
|
71
|
+
paymentLinks = {
|
|
72
|
+
create: (input, opts = {}) => this._request('POST', '/payment-links', { body: input, idempotencyKey: opts.idempotencyKey }),
|
|
73
|
+
list: (query = {}) => this._request('GET', '/payment-links', { query }),
|
|
74
|
+
delete: (id) => this._request('DELETE', `/payment-links/${id}`),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// --- customers ---
|
|
78
|
+
customers = {
|
|
79
|
+
create: (input) => this._request('POST', '/customers', { body: input }),
|
|
80
|
+
list: (query = {}) => this._request('GET', '/customers', { query }),
|
|
81
|
+
get: (id) => this._request('GET', `/customers/${id}`),
|
|
82
|
+
delete: (id) => this._request('DELETE', `/customers/${id}`),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// --- recipients ---
|
|
86
|
+
recipients = {
|
|
87
|
+
create: (input) => this._request('POST', '/recipients', { body: input }),
|
|
88
|
+
list: () => this._request('GET', '/recipients'),
|
|
89
|
+
delete: (id) => this._request('DELETE', `/recipients/${id}`),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- transfers (cross-border send) ---
|
|
93
|
+
transfers = {
|
|
94
|
+
quote: (input) => this._request('POST', '/transfers/quote', { body: input }),
|
|
95
|
+
create: (input, opts = {}) => this._request('POST', '/transfers', { body: input, idempotencyKey: opts.idempotencyKey }),
|
|
96
|
+
list: (query = {}) => this._request('GET', '/transfers', { query }),
|
|
97
|
+
get: (id) => this._request('GET', `/transfers/${id}`),
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default DurraPay
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@durrapay/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DurraPay Platform API client for Node.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.mjs",
|
|
7
|
+
"exports": { ".": "./index.mjs" },
|
|
8
|
+
"engines": { "node": ">=18" },
|
|
9
|
+
"files": ["index.mjs", "README.md"],
|
|
10
|
+
"keywords": ["durrapay", "payments", "mpesa", "africa", "fintech"],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://developer.durrapay.com",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/Durrafx-repos/durrapy-sdks.git",
|
|
16
|
+
"directory": "node"
|
|
17
|
+
},
|
|
18
|
+
"bugs": { "url": "https://github.com/Durrafx-repos/durrapy-sdks/issues" }
|
|
19
|
+
}
|