TypeScript / Node.js SDK
@finsel-dgi/pasby — v2 REST client for identification, signing, flows, and documents.
The official Node.js library is @finsel-dgi/pasby. It targets API v2 on the public gateway (l.pasby.africa / s.pasby.africa) and maps one-to-one to the routes in Endpoint index.
Repository: github.com/Finsel-DGI/pasby-typescript-sdk
This package does not include OIDC (kipindi / shake / resource). For hosted login use @finsel-dgi/pasby-next or @finsel-dgi/pasby-react.
Requirements
- Node.js 10 or higher
- Dependency:
axios(bundled with the package)
npm install @finsel-dgi/pasbyConfigure the client
Use a named import (there is no default export):
import { Pasby } from "@finsel-dgi/pasby";
const pasby = new Pasby({
apikeyAuth: "bk-test_YOUR_KEY",
appSecretKey: "YOUR_APP_SECRET",
basePath: "https://s.pasby.africa", // sandbox
version: "v2", // default; only v2 is typed
});| Option | Required | Default | Maps to |
|---|---|---|---|
apikeyAuth | Yes | — | Header x-api-key |
appSecretKey | Yes | — | Header x-access-secret |
basePath | No | https://l.pasby.africa | Request host |
version | No | "v2" | Path segment /api/v2/... |
baseOptions | No | {} | Merged into every Axios call |
| Environment | basePath | Key prefix |
|---|---|---|
| Sandbox | https://s.pasby.africa | bk-test_ |
| Production | https://l.pasby.africa | bk-live_ |
See Credentials.
Client layout
The Pasby class exposes five namespaces:
| Namespace | Class | REST domain |
|---|---|---|
pasby.health | HealthApi | GET /api/health/check |
pasby.identification | IdentificationApi | /api/v2/identification/* |
pasby.signing | SigningApi | /api/v2/signing/* |
pasby.flows | FlowsApi | /api/v2/flow/* (partial) |
pasby.docs | DocsApi | /api/v2/document/* |
Method → endpoint map
pasby.health
| SDK method | HTTP | Path | Headers |
|---|---|---|---|
healthCheck() | GET | /api/health/check | x-api-key only |
pasby.identification
| SDK method | HTTP | Path |
|---|---|---|
sameDevice({ action, claims, payload }) | POST | /api/v2/identification/same-device |
differentDevice({ action, claims, payload, user }) | POST | /api/v2/identification/different-device |
wildcard({ action, claims, payload, seeds }) | POST | /api/v2/identification/wildcard |
action: "login" | "signup" | "link".
claims: typed claim keys from the SDK (e.g. "naming.given", "contact.email").
pasby.signing
| SDK method | HTTP | Path |
|---|---|---|
sameDevice({ nin, action, payload, webhook? }) | POST | /api/v2/signing/same-device |
differentDevice({ nin, action, payload, webhook? }) | POST | /api/v2/signing/different-device |
wildcard({ action, payload, seeds, webhook? }) | POST | /api/v2/signing/wildcard |
action: "sign" (requires webhook) or "confirm" (no webhook).
pasby.flows
| SDK method | HTTP | Path | In SDK? |
|---|---|---|---|
ping({ request }) | POST | /api/v2/flow/ping | Yes |
cancel({ request }) | POST | /api/v2/flow/cancel | Yes |
authorize({ sub, app }) | GET | /api/v2/flow/authorize | Generated but not public on FlowsApi |
longPolling({ request }) | POST | /api/v2/flow/polling | Generated but not public on FlowsApi |
Use pasby.flows (plural), not pasby.flow. For SSE (GET /api/v2/flow/sse) and v1 authorize, call the REST API directly or use Axios — the SDK does not expose those methods on the public class.
pasby.docs
| SDK method | HTTP | Path |
|---|---|---|
docSign({ to, file, webhook }) | POST | /api/v2/document/signing |
docReview({ signee, file, webhook }) | POST | /api/v2/document/review |
docSignatureRefresh({ flow }) | POST | /api/v2/document/refresh |
flow on refresh must be at least 40 characters.
Reading responses
All methods return an Axios response. The pasby JSON envelope is on response.data:
const { data } = await pasby.identification.wildcard({
action: "signup",
claims: ["naming.given", "contact.email"],
seeds: 4,
payload: "Create your account",
});
console.log(data.status); // e.g. "successful"
console.log(data.data.request.id); // flow id for ping
console.log(data.data.seeds); // QR seeds (wildcard)Poll with:
const { data: ping } = await pasby.flows.ping({
request: data.data.request.id,
});Errors
Failed HTTP calls throw PasbyError (exported from the package) with status, reason, responseBody, and validation details when the API returns Zod-style arrays.
import { Pasby, PasbyError } from "@finsel-dgi/pasby";
try {
await pasby.identification.differentDevice({ /* ... */ });
} catch (err) {
if (err instanceof PasbyError) {
console.error(err.status, err.message);
}
}See Errors reference.
End-to-end example (sandbox)
import { Pasby } from "@finsel-dgi/pasby";
const pasby = new Pasby({
apikeyAuth: process.env.PASBY_API_KEY!,
appSecretKey: process.env.PASBY_APP_SECRET!,
basePath: "https://s.pasby.africa",
});
// 1. Start identification
const { data: start } = await pasby.identification.wildcard({
action: "signup",
claims: ["naming.given", "contact.email"],
seeds: 4,
payload: "Create your account",
});
const flowId = start.data.request.id;
// 2. Poll until complete (simplified)
let done = false;
while (!done) {
const { data: ping } = await pasby.flows.ping({ request: flowId });
const req = ping.data.request;
if (req.cancelled || req.signature) done = true;
else await new Promise((r) => setTimeout(r, 2000));
}
// 3. Decrypt claims on your server — see Handling encrypted claims guideMore examples: Quickstart, SampleCode, SDK repo examples/document-signature-refresh.ts.
v1 and OIDC
| Feature | This SDK |
|---|---|
| API v2 REST | Supported (default) |
API v1 / x-access-token | Not typed; use REST or migrate to v2 |
| OIDC | Use @finsel-dgi/pasby-next / @finsel-dgi/pasby-react |
Exported types
The package re-exports request/response interfaces (e.g. FlowsPingResponse, IdentificationSameDeviceResponse, PasbyDocSignRequest) for TypeScript consumers. Import from @finsel-dgi/pasby when you need strict typing.