npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@iips/quasar-sdk

v1.1.1

Published

Official iiips Quasar Node.js SDK

Downloads

63

Readme

IIPS Quasar SDK

Official Node.js SDK for Quasar APIs.

Install

npm install @iips/quasar-sdk

Quick Start

import { QuasarClient } from "@iips/quasar-sdk";

const client = new QuasarClient({
  apiKey: process.env.QUASAR_API_KEY!,
  baseUrl: process.env.QUASAR_BASE_URL // optional
});
  • Default baseUrl: https://api-quasar.iips.app/api/v1
  • Auth header used by SDK: Authorization: Bearer <apiKey>

Core Modules

  • client.payments - payment intents and Paystack card / hosted checkout flows
  • client.endUsers - dedicated virtual accounts (bank transfer) for any tenant using parent/child wallet owners (school, retail, service, etc.)
  • client.school - deprecated alias of endUsers (studentId / schoolId naming)
  • client.transfers - payout / sweep transfers to external bank accounts
  • client.wallets - wallet balances and transactions
  • client.webhooks - webhook endpoint registration and signature verification

Choosing a flow: use client.payments when the payer pays by card / Paystack redirect. Use client.endUsers.createVirtualAccount when you issue a static account number for bank transfers (NUBAN-style) and track inflows against a child wallet owner.

Admin API — Invify device fleet (v1.1.0+)

Use QuasarAdminClient with an admin JWT (from Quasar admin login), not sk_* API keys.

import { QuasarAdminClient } from "@iips/quasar-sdk";

const admin = new QuasarAdminClient({
  adminAccessToken: process.env.QUASAR_ADMIN_JWT!,
  baseUrl: process.env.QUASAR_BASE_URL, // optional; same default as QuasarClient
  vertical: "invify_retail" // optional; sets X-IIPS-Vertical on every request
});

const { data, meta } = await admin.invify.listDevices({
  page: 1,
  pageSize: 100,
  vertical: "invify_retail",
  tenantId: undefined
});

for (const row of data) {
  console.log(row.id, row.agent?.business_name, row.tenant?.slug, row.status);
}

See also: iips-pay/docs/INVIFY_DEVICE_FLEET_API.md in this monorepo for full field reference.

Payments Example

const intent = await client.payments.createIntent({
  amount: "50000.00",
  currency: "NGN",
  customerId: "cust_123",
  metadata: { orderId: "INV-1001" }
});

Virtual accounts (dedicated bank transfer) — integration

Use this when end users pay by bank transfer into a dedicated virtual account tied to a child wallet owner (student, customer, member). Use client.endUsers with generic childId / parentId — the HTTP route is unchanged (/school/students/{id}/...) for backward compatibility.

API key scopes

  • Create / provision: virtual_accounts:write
  • Read VA, wallet, inflow list: virtual_accounts:read

Tenant is determined by the API key. Do not send a separate tenant id in the body for this route.

Identity fields (required on every create)

Quasar forwards email, firstName, and lastName to the PSP when creating the customer behind the dedicated account. Send the real account-holder identity for all modes (school, retail, service); omitting or placeholder values can break name validation and reconciliation.

| Field | Required | Notes | |--------|----------|--------| | currency | Yes | ISO 4217, three letters (e.g. NGN). | | email | Yes | Account-holder email. | | firstName | Yes | Given name, 1–64 characters. | | lastName | Yes | Family name, 1–64 characters. | | parentId (SDK) | Yes | Parent wallet-owner UUID — school, merchant, or platform that may receive the optional split share. Sent as merchantWalletOwnerId on the wire. | | parentShareBps (SDK) | No | Basis points 0–10000 on the parent share. Default 0 (100% to the child). Maps to counterpartyShareBps. | | preferredBankCode / paystackPreferredBank | No | Preferred issuing bank code for the active VA provider. When the provider is Paystack, this is a Paystack bank slug (e.g. wema-bank). Ignored for mock or other providers until wired. Prefer preferredBankCode; paystackPreferredBank is a deprecated alias. | | metadata | No | Strongly recommended: your own ids (customerId, schoolId, orderId, etc.) for support and tracing. |

Parent / child (SDK)

| SDK field | Meaning | |-----------|---------| | childId | Child wallet-owner UUID — end-user who owns the VA (student, customer, member). Same as {id} in POST /api/v1/school/students/{id}/virtual-account. | | parentId | Parent wallet-owner UUID — counterparty that may receive a split (school, merchant, platform). |

Legacy client.school still accepts studentId + schoolId / merchantWalletOwnerId and delegates to endUsers.

Idempotency

Provisioning is idempotent per (tenant, end-user wallet owner, currency): a second call returns the same VA. For network retries, pass an Idempotency-Key:

await client.endUsers.createVirtualAccount(
  { childId, parentId, currency, email, firstName, lastName },
  { idempotencyKey: `va:${childId}:${currency}` }
);

Raw HTTP (reference)

POST {baseUrl}/school/students/{endUserWalletOwnerId}/virtual-account with Authorization: Bearer <sk_*> and a JSON body matching the table above. Default baseUrl includes /api/v1.

Response shape

createVirtualAccount returns both accountNumber (camelCase) and account_number (snake_case) for compatibility, plus bankName, provider, reference, currency. Persist at least reference, account_number, bankName, and currency in your database.

Retail / service example

const va = await client.endUsers.createVirtualAccount({
  childId: "660e8400-e29b-41d4-a716-446655440001",
  parentId: "6ba7b813-9dad-11d1-80b4-00c04fd430c8",
  currency: "NGN",
  email: "[email protected]",
  firstName: "Ada",
  lastName: "Buyer",
  parentShareBps: 0,
  preferredBankCode: "wema-bank",
  metadata: {
    customerId: "660e8400-e29b-41d4-a716-446655440001",
    merchantId: "6ba7b813-9dad-11d1-80b4-00c04fd430c8"
  }
});

console.log(va.accountNumber, va.bankName, va.reference);

School onboarding example (same contract)

When a student record exists in your system, provision the VA with the same required identity fields:

const va = await client.endUsers.createVirtualAccount({
  childId: student.id,
  parentId: student.schoolId,
  currency: "NGN",
  email: student.email,
  firstName: student.firstName,
  lastName: student.lastName,
  metadata: {
    studentId: student.id,
    schoolId: student.schoolId
  }
});

await db.studentVirtualAccounts.upsert({
  studentId: student.id,
  schoolId: student.schoolId,
  quasarAccountId: va.reference,
  accountNumber: va.account_number,
  bankName: va.bankName
});

Related client.endUsers calls

  • getVirtualAccount(childId, { currency }) — fetch existing VA
  • listPayments(childId, { page, pageSize }) — VA inflow rows (data + meta)
  • getWallet / getBalance — wallet snapshot for that child wallet owner

More context for operators: sdk/CLIENT_INTEGRATION_GUIDE.md (checklist, errors, webhooks).

Webhook Signature Verification

const ok = client.webhooks.verifySignature(
  rawPayload,
  headers["x-quasar-signature"] as string,
  process.env.QUASAR_WEBHOOK_SECRET!
);

Transfers (Payout / Sweep)

const transfer = await client.transfers.create({
  amount: "50000.0000",
  currency: "NGN",
  reference: "trf_ref_20260428_001",
  destination: {
    account_number: "0123456789",
    bank_code: "058",
    account_name: "IIPS SCHOOL ACCOUNT"
  },
  metadata: {
    tenantId: process.env.QUASAR_TENANT_ID!,
    schoolId: "550e8400-e29b-41d4-a716-446655440000"
  }
});

const latest = await client.transfers.get(transfer.reference);
console.log(latest.status); // PENDING | PROCESSING | SUCCESS | FAILED

Errors and Retries

  • SDK retries transient failures internally (network errors and 408/429/5xx).
  • Write operations should include an idempotency key when possible.
await client.payments.createIntent(
  { amount: "50000.00", currency: "NGN" },
  { idempotencyKey: "intent:order:INV-1001" }
);

Scripts (SDK Workspace)

  • npm run generate:sdk - regenerate OpenAPI-generated client from ../swagger.public.json
  • npm run build - build ESM + CJS bundles with type declarations
  • npm run test - run SDK tests

Additional Docs

  • Integration guide: sdk/CLIENT_INTEGRATION_GUIDE.md

Publishing Notes

For GitHub Actions publishing:

  1. Create npm automation token.
  2. Add repo secret NPM_TOKEN.
  3. Ensure npm access for package @iips/quasar-sdk.

Manual publish from the sdk/ directory (runs codegen, build, and tests via prepublishOnly):

cd sdk
npm ci
npm publish --access public

Requires npm login (or NPM_TOKEN in ~/.npmrc) for the @iips scope.