stile
SDKs

Node.js SDK

The official stile Node.js library. Works with any Node.js backend framework.

Installation

npm install @stile/node

Initialization

Create a single client instance and reuse it throughout your application. Pass your API key as the first argument.

import Stile from "@stile/node";

const stile = new Stile(process.env.STILE_API_KEY!);

The SDK automatically retries failed requests and handles timeouts. Use vk_test_ keys in development and vk_live_ in production.

Verification Sessions

Create a session

const session = await stile.verificationSessions.create({
  type: "identity",
  return_url: "https://yourapp.com/verify/done",
  cancel_url: "https://yourapp.com/verify/cancel",
  client_reference_id: "user_123",
});

// session.id           — e.g. "vks_abc123"
// session.client_secret — pass to the frontend widget
// session.expires_at   — Unix timestamp (24h from now)
// session.status       — "created"

Retrieve a session

const session = await stile.verificationSessions.retrieve("vks_abc123");

Cancel a session

const session = await stile.verificationSessions.cancel("vks_abc123");
// session.status === "cancelled"

List sessions

const { data, has_more } = await stile.verificationSessions.list({
  limit: 20,
  starting_after: "vks_xyz",
});

Webhook Endpoints

// Create
const endpoint = await stile.webhookEndpoints.create({
  url: "https://yourapp.com/api/webhooks",
  enabled_events: ["verification_session.verified", "verification_session.failed"],
  description: "Production webhook",
});
// endpoint.secret — save this to verify signatures

// Retrieve
const ep = await stile.webhookEndpoints.retrieve("we_abc123");

// Update
await stile.webhookEndpoints.update("we_abc123", {
  enabled_events: ["*"],
  status: "enabled",
});

// Delete
await stile.webhookEndpoints.del("we_abc123");

// List
const { data } = await stile.webhookEndpoints.list();

// List delivery attempts
const { data: deliveries } = await stile.webhookEndpoints.listDeliveries("we_abc123");

Events

// Retrieve a single event
const event = await stile.events.retrieve("evt_abc123");

// List events
const { data } = await stile.events.list({ limit: 20 });

Verified Persons

Check if a user has been previously verified across any site in the stile network. Call this from your backend before loading the SDK to skip verification for returning users.

const result = await stile.verifiedPersons.lookup({
  email: "user@example.com",
  methods: ["document_capture"],
  min_strength: "document_capture",
  max_age: "30",
});

if (result.verified) {
  // User already verified — grant access, skip SDK
  console.log(result.verified_person_id, result.credentials);
} else {
  // Create a session and load the SDK
}

Webhook Signature Verification

Verify incoming webhook signatures to prevent processing spoofed events. The SDK provides two methods:

fromRequest() — for any Web API framework

Works with Next.js, Hono, Cloudflare Workers, Bun, Deno, and any framework using the standard Request object:

export async function POST(req: Request) {
  const event = await stile.webhooks.fromRequest(
    req,
    process.env.WEBHOOK_SECRET!,
  );

  if (event.type === "verification_session.verified") {
    console.log("Session verified:", event.data.id);
  }

  return Response.json({ received: true });
}

constructEvent() — low-level

For frameworks that don't use the standard Request object, pass the raw body and header directly:

const event = stile.webhooks.constructEvent(
  rawBody,                         // string or Buffer
  signatureHeader,                 // stile-signature header value
  process.env.WEBHOOK_SECRET!,
);

Always use raw body

JSON body parsers modify the request body before it reaches your handler, which invalidates the signature. Always pass the raw, unmodified request body.

Error handling

import {
  StileError,
  StileAuthenticationError,
  StileRateLimitError,
} from "@stile/node";

try {
  await stile.verificationSessions.create({ type: "identity" });
} catch (err) {
  if (err instanceof StileAuthenticationError) {
    // 401 — invalid or expired API key
  } else if (err instanceof StileRateLimitError) {
    // 429 — slow down, retry after err.retryAfter seconds
  } else if (err instanceof StileError) {
    console.error(err.type, err.code, err.message);
  }
}

For a complete guide to error types, retry strategies, and idempotency, see Error Handling.

On this page