Official Node.js SDK for the First Iraqi Bank (FIB) Subscription Service
- Features
- Installation
- Quick Start
- Configuration
- API Reference
- Subscription Statuses
- ISO-8601 Period Cheatsheet
- Error Handling
- Webhook Integration
- Examples
- Publishing
- β Full coverage of the FIB Subscription API (create, get, cancel)
- π Automatic OAuth2 token management with expiry refresh
- β³ Built-in polling helper (
waitForActivation) - π Stage & Production environment support
- π¦ Zero runtime dependencies
- π· ESM-native (
"type": "module") - π Full JSDoc type annotations
npm install fibsubscribeRequires Node.js v14 or higher. This package is ESM-only β use
import, notrequire().
import { FibSubscribe } from 'fibsubscribe';
const fib = new FibSubscribe({
clientId: process.env.FIB_CLIENT_ID,
clientSecret: process.env.FIB_CLIENT_SECRET,
environment: 'stage', // or 'production'
});
// 1. Create a monthly subscription with a 7-day trial
const sub = await fib.createSubscription({
title: 'Premium Membership',
description: 'Full access to all premium features.',
amount: 5000,
currency: 'IQD',
interval: 'P1M', // every 1 month
trialPeriod: 'P7D', // 7-day free trial
expiresIn: 'P1DT12H', // QR valid for 1 day 12 hours
statusCallbackUrl: 'https://yoursite.com/fib/subscription/webhook',
});
// 2. Show QR code or app link to the subscriber
console.log('App Link:', sub.appLink);
// Render: <img src={sub.qrCode} />
// 3. Wait until subscriber confirms (or rejects)
const result = await fib.waitForActivation(sub.subscriptionId);
console.log('Status:', result.status); // 'ACTIVE' | 'TRIAL' | 'REJECTED' | 'CANCELLED'const fib = new FibSubscribe({
clientId: 'YOUR_CLIENT_ID', // required
clientSecret: 'YOUR_CLIENT_SECRET', // required
environment: 'stage', // 'stage' (default) | 'production'
});| Option | Type | Required | Default | Description |
|---|---|---|---|---|
clientId |
string |
β | β | FIB-issued client ID |
clientSecret |
string |
β | β | FIB-issued client secret |
environment |
string |
β | 'stage' |
'stage' for testing, 'production' for live |
| Environment | Base URL |
|---|---|
| Stage (Test Mode) | https://fib-stage.fib.iq |
| Production (Live) | https://fib.prod.fib.iq |
const sub = await fib.createSubscription(options);| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
title |
string |
β | β | Display name (e.g. "Premium Streaming") |
description |
string |
β | β | What the subscriber gets |
amount |
number |
β | β | Charge per interval (positive number) |
currency |
string |
β | 'IQD' |
ISO 4217 code |
interval |
string |
β | β | ISO-8601 billing period (e.g. "P1M", "P7D") |
trialPeriod |
string |
β | β | ISO-8601 free trial (e.g. "P7D"). Omit = no trial |
expiresIn |
string |
β | β | QR code validity (e.g. "P1DT12H") |
statusCallbackUrl |
string |
β | β | Webhook URL for status-change events |
Response
{
"subscriptionId": "1d1b9133-6932-45b6-94bc-c40882da1bf9",
"readableCode": "DMRJ-JAMJ-RN36",
"qrCode": "data:image/png;base64,...",
"validUntil": "2025-08-19T19:40:35.087Z",
"appLink": "https://p-stage.fib.iq/0fc8/subscription?identifier=DDRKDIOZJEUW"
}const details = await fib.getSubscription(subscriptionId);Response
{
"id": "8d77b6b2-3eb3-4c74-9a95-9779ddfbbe94",
"readableCode": "DAID-9CTX-5YBU",
"title": "Premium Membership",
"description": "Full access to all premium features.",
"monetaryValue": { "amount": 5000, "currency": "IQD" },
"interval": "P1M",
"trialPeriod": "P7D",
"status": "TRIAL",
"activeUntil": 1755588900190,
"lastPaymentAt": null
}Cancels an active or trial subscription. Returns null on success (HTTP 202).
await fib.cancelSubscription(subscriptionId);Polls getSubscription() until the subscription leaves DRAFT status or the timeout is exceeded.
const result = await fib.waitForActivation(subscriptionId, options);| Parameter | Type | Default | Description |
|---|---|---|---|
intervalMs |
number |
4000 |
Polling interval in milliseconds |
timeoutMs |
number |
300000 |
Max wait time in ms (default: 5 min) |
| Status | Description |
|---|---|
DRAFT |
Created, awaiting subscriber confirmation via QR/app |
TRIAL |
Subscriber confirmed, currently in free trial |
ACTIVE |
Trial ended or no trial β subscriber is actively charged |
REJECTED |
Subscriber declined the subscription |
CANCELLED |
Cancelled by merchant or subscriber |
| Value | Meaning |
|---|---|
P1D |
Every day |
P7D |
Every 7 days |
P1M |
Every month |
P3M |
Every 3 months |
P1Y |
Every year |
P1DT12H |
1 day 12 hours |
import { FibSubscribe, FibSubscribeError } from 'fibsubscribe';
try {
await fib.createSubscription({ title: 'Plan', amount: 1000, interval: 'P1M' });
} catch (err) {
if (err instanceof FibSubscribeError) {
console.error('API Error:', err.message);
console.error('Status Code:', err.statusCode);
console.error('Body:', err.body);
} else {
throw err;
}
}Pass a statusCallbackUrl when creating a subscription. FIB will POST to this URL on every status change.
app.post('/fib/subscription/webhook', (req, res) => {
const { subscriptionId, status } = req.body;
res.sendStatus(200); // acknowledge immediately
switch (status) {
case 'ACTIVE': /* enable full access */ break;
case 'TRIAL': /* enable trial access */ break;
case 'CANCELLED': /* revoke access */ break;
case 'REJECTED': /* notify the user */ break;
}
});| File | Description |
|---|---|
examples/basic.js |
Create β wait β cancel flow |
examples/express-webhook.js |
Express server with full webhook handling |
FIB_CLIENT_ID=xxx FIB_CLIENT_SECRET=yyy node examples/basic.jsThis package is ESM-only. For CommonJS projects use a dynamic import:
const { FibSubscribe } = await import('fibsubscribe');MIT Β© Rageofkurd