> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js and TypeScript SDK for KYC and AML

> Quickstart for the official Didit Node.js and TypeScript SDK: typed calls for the server APIs, webhook verification and Authentication token checks.

The official Didit library for Node.js and TypeScript. It runs on Node.js 18 or later, Bun, Deno and edge runtimes with `fetch`, ships ES module and CommonJS builds, and has no runtime dependencies. See the [server SDKs overview](https://docs.didit.me/integration/server-sdks/overview.md) for what every SDK shares.

## Install

```bash theme={null}
npm install @didit-protocol/sdk-node
```

The package is [`@didit-protocol/sdk-node` on npm](https://www.npmjs.com/package/@didit-protocol/sdk-node). Its source and changelog are in [didit-protocol/sdk-node](https://github.com/didit-protocol/sdk-node) on GitHub.

## Configure the client

`new Didit()` reads `DIDIT_API_KEY` from the environment on Node.js, Bun and Deno (with `--allow-env`). Edge runtimes have no process environment, so pass the key as an option there: `new Didit({ apiKey: env.DIDIT_API_KEY })`. Pass options to override it, or to set the organization and application ids that application-scoped calls (cases, networks, regulatory reports) need. The timeout is in milliseconds.

```typescript theme={null}
import Didit from "@didit-protocol/sdk-node";

const didit = new Didit({
  apiKey: process.env.DIDIT_API_KEY,
  organizationId: process.env.DIDIT_ORGANIZATION_ID,
  applicationId: process.env.DIDIT_APPLICATION_ID,
  timeout: 30_000,
  maxRetries: 2,
});

// Options for a single call.
const fast = didit.withOptions({ timeout: 5_000, maxRetries: 0 });
console.log(await fast.sessions.retrieveDecision("11111111-2222-3333-4444-555555555555"));
```

With CommonJS, use `const { Didit } = require("@didit-protocol/sdk-node");`.

## Create a session

Create a [verification session](https://docs.didit.me/sessions-api/create-session.md) for a workflow and send your user to its URL. Request fields keep the API's own names.

```typescript theme={null}
import Didit from "@didit-protocol/sdk-node";

const didit = new Didit();

const session = await didit.sessions.create({
  workflow_id: "11111111-2222-3333-4444-555555555555",
  vendor_data: "user-123",
  callback: "https://example.com/verification/done",
});
console.log(session.url);
```

## Read the decision

When the user finishes (or when the webhook arrives), [read the decision](https://docs.didit.me/sessions-api/retrieve-session.md). Every feature result is a list with one entry per workflow node, and date-times are `Date` objects.

```typescript theme={null}
import Didit from "@didit-protocol/sdk-node";

const didit = new Didit();

const decision = await didit.sessions.retrieveDecision("11111111-2222-3333-4444-555555555555");
console.log(decision.status);
for (const verification of decision.id_verifications ?? []) {
  console.log(verification.first_name, verification.last_name);
}
```

## Verify a webhook

Pass the raw body (not parsed JSON) and the request headers: a Node.js or Express `req.headers` object, a Fetch `Headers` object or `[name, value]` pairs (the `WebhookHeaders` type). `verify` returns a promise and rejects with `WebhookVerificationError` for anything that is not a valid, fresh delivery.

```typescript theme={null}
import { webhooks, WebhookVerificationError, type WebhookHeaders } from "@didit-protocol/sdk-node";

const secret = process.env.DIDIT_WEBHOOK_SECRET ?? "";

export async function handleWebhook(rawBody: Buffer, headers: WebhookHeaders): Promise<number> {
  try {
    const event = await webhooks.verify(rawBody, headers, secret);
    if (event.webhook_type === "status.updated") {
      console.log(event.session_id, event.status);
    }
    return 200;
  } catch (error) {
    if (error instanceof WebhookVerificationError) return 400;
    throw error;
  }
}
```

With Express, read the body with `express.raw({ type: "application/json" })` and call `handleWebhook(req.body, req.headers)`. While you rotate the secret, pass both: `[newSecret, oldSecret]`. See [Webhooks](https://docs.didit.me/integration/webhooks.md) for the events and the signature scheme.

## Screen a transaction

Submit a payment, withdrawal or crypto transfer to [transaction monitoring](https://docs.didit.me/transaction-monitoring/overview.md); the response carries its status and risk score.

```typescript theme={null}
import Didit from "@didit-protocol/sdk-node";

const didit = new Didit();

const transaction = await didit.transactions.create({
  transaction_id: "txn-1001",
  transaction_category: "finance",
  transaction_details: { direction: "outbound", amount: 1500, currency: "EUR" },
  subject: { entity_type: "individual", vendor_data: "user-123", full_name: "Maria Garcia" },
});
console.log(transaction.status, transaction.score);
```

## Verify Authentication tokens

`Authentication` checks the access tokens your [Authentication](https://docs.didit.me/authentication/overview.md) issuer signs, in your backend, without calling Didit for each request. It also exchanges codes, refreshes tokens, checks and revokes sessions, and runs step-ups.

> [!NOTE]
>
> Token verification makes the checks in [Verify a token on your server](https://docs.didit.me/authentication/tokens-and-jwks.md#verify-a-token-on-your-server), against your application's issuer and signing keys.

```typescript theme={null}
import { Authentication, TokenVerificationError } from "@didit-protocol/sdk-node";

// The publishable key (pk_live_... or pk_test_...) carries your issuer URL.
const auth = Authentication.fromPublishableKey("pk_live_...", { clientId: "your-application-id" });

export async function currentUser(accessToken: string): Promise<string | null> {
  try {
    const claims = await auth.verifyAccessToken(accessToken);
    return claims.sub;
  } catch (error) {
    if (error instanceof TokenVerificationError) return null;
    throw error;
  }
}
```

## Errors

```typescript theme={null}
import Didit, { APIStatusError, NotFoundError, RateLimitError } from "@didit-protocol/sdk-node";

const didit = new Didit();

try {
  await didit.sessions.retrieveDecision("11111111-2222-3333-4444-555555555555");
} catch (error) {
  if (error instanceof NotFoundError) console.log("no such session");
  else if (error instanceof RateLimitError) console.log("slow down, request", error.requestId);
  else if (error instanceof APIStatusError) console.log(error.status, error.body);
  else throw error;
}
```

## Lists and files

```typescript theme={null}
import Didit, { fileFromPath } from "@didit-protocol/sdk-node";

const didit = new Didit();

// Lists page through every result.
for await (const session of didit.sessions.list({ status: "Approved" })) {
  console.log(session.session_id);
}

// Uploads take a Blob, a Buffer, a stream or fileFromPath.
const result = await didit.idVerification.verify({
  front_image: await fileFromPath("id-front.jpg"),
  back_image: await fileFromPath("id-back.jpg"),
});
console.log(result.id_verification);
```

Server endpoint pages of the [API reference](https://docs.didit.me/api-reference/overview.md) have a Node.js sample for their operation, except for the endpoints and fields that no 1.0.1 release has yet, named in the [overview](https://docs.didit.me/integration/server-sdks/overview.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.