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

@cdx-forge/di-typescript-sdk

v0.1.0-beta.1

Published

TypeScript server SDK for the Candescent Digital Insight API

Readme

@candescent/di-typescript-sdk

npm version Node.js 20+

Server-side TypeScript/Node.js SDK for the Candescent Digital Insight API. Covers all 99 API operations across 12 service areas with full type safety, automatic OAuth token management, and built-in retry logic.


Requirements

  • Node.js 20+
  • ESM only — use import syntax. require() is not supported (see Troubleshooting).

Installation

npm install @candescent/di-typescript-sdk
yarn add @candescent/di-typescript-sdk
pnpm add @candescent/di-typescript-sdk

Quick Start

import { CandescentClient, Environment } from "@candescent/di-typescript-sdk";

const client = new CandescentClient({
  clientId: process.env.CANDESCENT_CLIENT_ID!,
  clientSecret: process.env.CANDESCENT_CLIENT_SECRET!,
  institutionId: process.env.CANDESCENT_INSTITUTION_ID!,
  environment: Environment.Stage, // or Environment.Production
});

const accounts = await client.accounts.list({ hostUserId: "user-12345" });
console.log(`Found ${accounts.accounts?.length ?? 0} accounts`);

await client.close();

Authentication

Obtain your Client ID, Client Secret, and Institution ID from the Candescent Developer Console. For detailed steps, see the Quick Start guide.

Option 1 — OAuth 2.0 Client Credentials (recommended)

import { CandescentClient, Environment } from "@candescent/di-typescript-sdk";

const client = new CandescentClient({
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  institutionId: "your-institution-id",
  environment: Environment.Production,
});

The SDK obtains and caches OAuth tokens automatically, refreshes them before expiry, and injects the correct Authorization header on every request. You never handle tokens directly.

Option 2 — Environment Variables

export CANDESCENT_CLIENT_ID=your-client-id
export CANDESCENT_CLIENT_SECRET=your-client-secret
export CANDESCENT_INSTITUTION_ID=your-institution-id
export CANDESCENT_ENVIRONMENT=production  # or stage (default)
import { CandescentClient } from "@candescent/di-typescript-sdk";

const client = CandescentClient.fromEnv();

Option 3 — Static Bearer Token

import { CandescentClient } from "@candescent/di-typescript-sdk";

const client = new CandescentClient({
  bearerToken: "your-pre-obtained-jwt",
  institutionId: "your-institution-id",
});

Environment Variables Reference

| Variable | Required | Description | |----------|----------|-------------| | CANDESCENT_INSTITUTION_ID | ✅ Always | Your institution identifier | | CANDESCENT_CLIENT_ID | Yes* | OAuth 2.0 client ID | | CANDESCENT_CLIENT_SECRET | Yes* | OAuth 2.0 client secret | | CANDESCENT_BEARER_TOKEN | Yes* | Pre-obtained JWT (skips OAuth flow) | | CANDESCENT_ENVIRONMENT | No | stage (default) or production | | CANDESCENT_USERNAME | No | Password grant — user username | | CANDESCENT_PASSWORD | No | Password grant — user password |

*Provide either CANDESCENT_BEARER_TOKEN or CANDESCENT_CLIENT_ID + CANDESCENT_CLIENT_SECRET.

Note: Node.js does not automatically load .env files. Either run source .env before your script, or use a library like dotenv to load them at runtime.


Usage

The client is organized by API service area. Each property on client maps to one group of operations.

Accounts

// List accounts for a user
const accounts = await client.accounts.list({ hostUserId: "user-12345" });

// Get a specific account
const account = await client.accounts.get({ accountId: "acc-abc123" });

// List transactions for an account
const txns = await client.accounts.listTransactions({
  accountId: "acc-abc123",
  hostUserId: "user-12345",
});

Customer Management

import type { RegisterCustomerRequest } from "@candescent/di-typescript-sdk";

// Register a new customer
const response = await client.customerManagement.register({
  diFiid: "05523",
  body: {
    fICustomer: {
      id: { value: "0", type: "GUID" },
      fiId: { value: "05523" },
      memberNumber: "123456789",
      person: {
        personName: { firstName: "Jane", lastName: "Smith" },
        contactInfo: { emailAddress: "[email protected]" },
      },
      userType: "PRIMARY",
    },
  },
});
const customerId = response.fICustomer?.id?.value;

// Look up customer information
const info = await client.customerManagement.getInformation({
  customerId,
});

Authentication

// Create an OAuth token
const token = await client.authentication.createToken({
  grantType: "client_credentials",
});

// Revoke a token on logout
await client.authentication.revokeToken({
  token: token.accessToken,
});

Business Banking

// Get business entitlements
const entitlements = await client.businessBanking.getBusinessEntitlements({
  businessId: "biz-456",
});

// Look up business details by ID
const details = await client.businessBanking.getBusinessDetails({
  searchType: "BUSINESS_ID",
  searchValue: "biz-456",
  includeTins: true,
  includeUsers: true,
});

Standalone Functions (Serverless / Lambda)

For environments where managing a client lifecycle is inconvenient:

import { listAccounts, getAccount, listTransactions } from "@candescent/di-typescript-sdk/operations";

// Reads credentials from process.env.CANDESCENT_*
const accounts = await listAccounts({ hostUserId: "user-12345" });
const account = await getAccount({ accountId: "acc-abc123" });

Error Handling

All API errors are thrown as typed exceptions. Catch the base ApiError or any specific subclass:

import {
  ApiError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  BadRequestError,
} from "@candescent/di-typescript-sdk";

try {
  const account = await client.accounts.get({ accountId: "acc-not-found" });
} catch (error) {
  if (error instanceof NotFoundError) {
    console.error("Account not found:", error.message);
  } else if (error instanceof RateLimitError) {
    console.warn(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof AuthenticationError) {
    console.error("Check your credentials");
  } else if (error instanceof ApiError) {
    console.error(`API error ${error.statusCode}:`, error.message);
  } else {
    throw error; // re-throw unexpected errors
  }
}

Error Hierarchy

| HTTP Status | Exception Class | |-------------|----------------| | Any non-2xx | ApiError (base) | | 400 | BadRequestError | | 401 | AuthenticationError | | 403 | PermissionDeniedError | | 404 | NotFoundError | | 409 | ConflictError | | 422 | UnprocessableEntityError | | 429 | RateLimitError | | 5xx | InternalServerError |


Pagination

Endpoints that return lists support PageIterator — an async iterable that handles fetching subsequent pages automatically:

import { PageIterator } from "@candescent/di-typescript-sdk";

// Iterate all accounts across all pages (25 per page by default)
for await (const account of new PageIterator(
  (req) => client.accounts.list({ hostUserId: "user-12345", ...req }),
  { page: 0, size: 50 },
)) {
  console.log(account.accountId);
}

Or collect all results into an array:

import { PageIterator } from "@candescent/di-typescript-sdk";

const allAccounts = [];
for await (const account of new PageIterator(
  (req) => client.accounts.list({ hostUserId: "user-12345", ...req }),
)) {
  allAccounts.push(account);
}

Retry Behavior

The SDK automatically retries on transient failures with exponential backoff:

| Retried Status Codes | Max Retries | Initial Delay | Max Delay | |----------------------|-------------|---------------|-----------| | 408, 429, 500, 502, 503, 504 | 2 (3 total attempts) | 500ms | 30s |

RateLimitError is thrown only after all retries are exhausted. The retryAfter property contains the value from the Retry-After response header.


Framework Integration

Express / Fastify

import express from "express";
import { CandescentClient } from "@candescent/di-typescript-sdk";

const app = express();
const client = CandescentClient.fromEnv();

app.get("/accounts/:userId", async (req, res) => {
  const accounts = await client.accounts.list({ hostUserId: req.params.userId });
  res.json(accounts);
});

AWS Lambda

import { listAccounts } from "@candescent/di-typescript-sdk/operations";

export const handler = async (event: { userId: string }) => {
  const accounts = await listAccounts({ hostUserId: event.userId });
  return { statusCode: 200, body: JSON.stringify(accounts) };
};

Lifecycle Management

const client = CandescentClient.fromEnv();

// On shutdown — revokes cached tokens
await client.close();

Configuration Reference

import { CandescentClient, Environment } from "@candescent/di-typescript-sdk";

const client = new CandescentClient({
  // --- Required (one of the two auth methods) ---
  clientId: "...",            // OAuth client ID
  clientSecret: "...",        // OAuth client secret
  institutionId: "...",       // Your institution identifier

  // --- OR use a static token ---
  bearerToken: "...",         // Pre-obtained JWT

  // --- Optional ---
  environment: Environment.Production,  // Environment.Stage (default) | Environment.Production
  baseUrl: "https://custom.api.host",   // Override base URL (advanced)
});

Examples

The examples/ directory contains 21 runnable scripts covering all API operations:

| Example File | What It Covers | |---|---| | accounts.ts | List accounts, retrieve account details, banking images | | transactions.ts | Transaction history, filtering | | authentication.ts | OAuth token lifecycle | | authentication-lifecycle.ts | Full token create / revoke flow | | customer-management.ts | Contact methods, password reset, unlock | | register-and-lookup.ts | Customer registration + 3-way lookup | | disclosures.ts | Institution and user disclosures | | estatements.ts | E-statement delivery preferences | | alert-configuration.ts | Alert templates and types | | alert-preferences.ts | User and institution alert preferences | | alert-delivery.ts | Alert history and content | | notification-channels.ts | Subscription management | | business-registration.ts | Business banking registration | | business-entitlements.ts | Business and user entitlements | | business-payments.ts | ACH and wire payments | | customer-campaigns.ts | Experience groups and campaigns | | money-movement.ts | Recipients and transfers | | mx-service.ts | MX integration — widget, users, logs | | pagination.ts | PageIterator across all pagination patterns | | error-handling.ts | Full error hierarchy showcase | | user-status.ts | User authentication status |

To run an example:

# 1. Copy and fill in your credentials
cp .env.example .env

# 2. Install dependencies
npm install

# 3. Run any example
node --experimental-strip-types examples/typescript/accounts.ts

Troubleshooting

CommonJS require() not working

This package is ESM-only. Your project must use "type": "module" in package.json or use .mjs file extensions. require('@candescent/di-typescript-sdk') will throw ERR_REQUIRE_ESM.

Cannot find module '@candescent/di-typescript-sdk'

Run npm install @candescent/di-typescript-sdk and confirm the package is listed in your package.json dependencies.

Authentication errors (401)

  • Verify CANDESCENT_CLIENT_ID and CANDESCENT_CLIENT_SECRET are correct
  • Confirm CANDESCENT_INSTITUTION_ID matches the credentials issued to you
  • For staging environments, set CANDESCENT_ENVIRONMENT=stage

"Parameters hostUserId and loginId are mutually exclusive"

Pass only one user identifier per request — either hostUserId or loginId, not both.

"Module not found" when running examples

Run npm install in the repo root or examples/ directory to install dependencies.


Versioning

This SDK follows semantic versioning independently from the Candescent API spec version. The API specification version (currently 1.4.0) and the SDK package version (starting at 1.0.0) are tracked separately. The release notes document which API spec version each SDK release was generated from.


Support