@gtech_/nando-sdk 1.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.
Files changed (2) hide show
  1. package/README.md +94 -0
  2. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # @nando/sdk
2
+
3
+ Official Node & Bun SDK for the [Nando](https://nando.ge) SMS public API. Send messages and verify signed delivery webhooks. Zero dependencies — uses the global `fetch` and `node:crypto`.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @nando/sdk
9
+ # or
10
+ bun add @nando/sdk
11
+ ```
12
+
13
+ Requires Node 18+ or Bun.
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { NandoClient } from '@nando/sdk'
19
+
20
+ const nando = new NandoClient({ apiKey: 'sk_nando_live...' }) // or set NANDO_API_KEY
21
+
22
+ const sms = await nando.sendSms({
23
+ body: 'Your verification code is 123456',
24
+ recipients: ['+995555123456'],
25
+ smsSubType: 'transactional', // 'otp' | 'transactional' | 'regular'
26
+ })
27
+
28
+ console.log('queued', sms.id)
29
+ ```
30
+
31
+ `brandNameId` is optional — your default brand name is used when omitted. Schedule for later with `smsType: 'scheduled'` and `scheduledAt: '2026-06-24T12:00:00Z'`.
32
+
33
+ ## Account info
34
+
35
+ ```ts
36
+ const info = await nando.selfInfo()
37
+ info.sms_balance
38
+ info.brand_names
39
+
40
+ await nando.test() // boolean — is the API key valid?
41
+ ```
42
+
43
+ ## Error handling
44
+
45
+ Any non-2xx response rejects with `NandoApiError`:
46
+
47
+ ```ts
48
+ import { NandoApiError } from '@nando/sdk'
49
+
50
+ try {
51
+ await nando.sendSms({ body: '', recipients: [] })
52
+ } catch (e) {
53
+ if (e instanceof NandoApiError) {
54
+ e.status // 400, 401, 403 ...
55
+ e.errors // { body: 'is required' } or { error: '...' }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## Webhooks
61
+
62
+ Nando POSTs a signed JSON event to your webhook URL when an API-originated SMS job changes status. Verify the Ed25519 signature over the **raw** body before parsing — an Express example:
63
+
64
+ ```ts
65
+ import express from 'express'
66
+ import { verifyWebhookSignature } from '@nando/sdk'
67
+
68
+ const app = express()
69
+ const PUBLIC_KEY = process.env.NANDO_WEBHOOK_PUBLIC_KEY!
70
+
71
+ // express.raw keeps req.body a Buffer so the signature stays valid.
72
+ app.post('/webhooks/nando', express.raw({ type: '*/*' }), (req, res) => {
73
+ const ok = verifyWebhookSignature(req.body, req.header('X-Nando-Signature') ?? '', PUBLIC_KEY)
74
+ if (!ok) return res.sendStatus(401)
75
+
76
+ const event = JSON.parse(req.body.toString('utf8'))
77
+ // deduplicate by event.event_id; check event.summary.failed_count
78
+ res.sendStatus(200)
79
+ })
80
+ ```
81
+
82
+ Return `200 OK` to acknowledge. Other statuses, timeouts, or errors trigger up to 5 retries with exponential backoff.
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ bun install
88
+ bun test
89
+ bun run build # emits dist/ via tsc
90
+ ```
91
+
92
+ ## License
93
+
94
+ MIT
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@gtech_/nando-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Official Node & Bun SDK for the Nando SMS public API — send messages and verify signed delivery webhooks.",
5
+ "author": "Gtech",
6
+ "license": "MIT",
7
+ "homepage": "https://nando.ge",
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": ["dist"],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "test": "bun test"
21
+ },
22
+ "keywords": ["nando", "sms", "otp", "webhooks", "ed25519", "bun"],
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "devDependencies": {
27
+ "typescript": "^5.4.0"
28
+ }
29
+ }