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

@selfxyz/enterprise-sdk

v0.2.0

Published

Node/TS SDK for Self.xyz enterprise verification: session creation, webhook signature verification, typed payloads.

Readme

@selfxyz/enterprise-sdk

Official Node/TypeScript SDK for the Self.xyz Enterprise API. Create verification sessions and verify webhooks with typed payloads.

Pre-1.0 stability: this SDK is under active development. Minor versions may include breaking changes until 1.0.0. Pin to an exact version in production.

Requirements

  • Node.js ≥ 20
  • ESM-only (the package is "type": "module"; use it from ESM consumers, or via dynamic import() from CommonJS)

Install

pnpm add @selfxyz/enterprise-sdk
# or
npm install @selfxyz/enterprise-sdk
# or
yarn add @selfxyz/enterprise-sdk

Quickstart

Create a verification session and hand the returned URL to your end user:

import { SelfClient } from '@selfxyz/enterprise-sdk';

const self = new SelfClient({ apiKey: process.env.SELF_API_KEY! });

const session = await self.sessions.create({
  flowId: '<your-flow-uuid>',
  externalUuid: '<user-uuid>',
});

// Redirect the end user here:
console.log(session.verificationUrl);

To look up a session later:

const detail = await self.sessions.get(session.id);
console.log(detail.status); // 'pending' | 'valid' | 'invalid' | 'error' | 'expired'

Webhook verification

Use SelfWebhooks.verify to validate an inbound webhook signature and return a typed event:

import { SelfWebhooks } from '@selfxyz/enterprise-sdk';

app.post('/webhooks/self', (req, res) => {
  try {
    const event = SelfWebhooks.verify(
      req.body, // raw string or Buffer (do NOT pre-parse)
      req.headers, // must include the signature headers as received
      process.env.SELF_WEBHOOK_SECRET!, // whsec_... from the Self dashboard
    );

    console.log(event.type, event.verification_id);
    res.status(200).end();
  } catch (err) {
    res.status(400).end();
  }
});

The raw request body must be passed exactly as received. Middleware that JSON-parses the body before signature verification will cause it to fail.

Proof re-verification

verifyProof lets you independently re-verify a proof you received from Self.

Persist event.proof, event.proof_attributes, and event.environment from the verification.completed payload — those three fields are everything verifyProof needs to re-run offline whenever you want.

import { verifyProof } from '@selfxyz/enterprise-sdk';

// `verificationData` is whatever you stored when the
// `verification.completed` webhook arrived — keep `event.proof`,
// `event.proof_attributes`, and `event.environment` so this call
// can run offline at any time.
const { isValid } = await verifyProof({
  orgId: process.env.SELF_ORG_ID!,
  proof: verificationData.proof,
  proofAttributes: verificationData.proof_attributes,
  environment: verificationData.environment,
});

isValid is true only when the Groth16 proof verifies, the minimum-age predicate is satisfied (if configured), and the user is not on an OFAC list (if OFAC checking is configured).

orgId

verifyProof requires your organization UUID — it's needed to verify the proof. You can find it on the dashboard under any product's Deploy tab → Re-verify proofs step.

Error handling

The SDK throws three distinct error types:

  • SelfValidationError: bad arguments. Raised before any network call when an SDK input (e.g. flowId) fails the schema check, or by SelfWebhooks.verify when a webhook payload doesn't match a known event shape.
  • SelfApiError: non-2xx response from the API.
  • WebhookVerificationError: invalid or missing webhook signature (re-exported from svix).

Network-level failures (DNS errors, connection refused, request aborts) propagate as the underlying TypeError/AbortError from fetch. They are not wrapped in SelfApiError. Handle them separately if you need to distinguish network problems from API responses.

import {
  SelfApiError,
  SelfValidationError,
  WebhookVerificationError,
} from '@selfxyz/enterprise-sdk';

try {
  await self.sessions.create({ flowId, externalUuid });
} catch (err) {
  if (err instanceof SelfValidationError) {
    err.message; // 'Invalid sessions.create input: flowId (Invalid uuid)'
    err.issues; // ZodIssue[] (raw issues for programmatic handling)
  } else if (err instanceof SelfApiError) {
    err.statusCode; // number (HTTP status)
    err.code; // string (machine-readable error code; see table below)
    err.message; // string (human-readable)
    err.details; // Record<string, unknown> | undefined (see "When details is populated")
    err.requestId; // string | undefined (X-Request-Id from the response)
  }
  throw err;
}

Error codes

SelfApiError.code carries a machine-readable error code so consumers can branch on the failure mode:

| Code | HTTP status | Meaning | | -------------------- | ----------- | ---------------------------------------------------------------------------------------------------------- | | validation_failed | 400 | Request body failed server-side validation. | | unauthenticated | 401 | Missing, invalid, or revoked API key. | | unauthenticated | 402 | Insufficient credits / billing gate triggered. Disambiguate from 401 via statusCode and check details. | | forbidden | 403 | API key lacks permission for the resource. | | not_found | 404 | Flow or session not found. | | conflict | 409 | Flow has no published version, or other state conflict. | | rate_limited | 429 | Rate limit exceeded. Back off and retry. | | internal_error | 500 | Unhandled server error. | | vendor_unavailable | 503 | Upstream dependency is degraded (e.g. circuit breaker open). | | unknown_error | any | API response didn't match the expected envelope. The message field includes a body preview. |

The set of codes may grow over time. Always include a default branch in any switch (err.code) so future codes don't fall through silently.

try {
  await self.sessions.create({ flowId, externalUuid });
} catch (err) {
  if (!(err instanceof SelfApiError)) throw err;
  switch (err.code) {
    case 'rate_limited':
      // back off and retry
      break;
    case 'unauthenticated':
      if (err.statusCode === 402) {
        // billing gate. err.details is { balance, required, planTier, creditGateMode }
      } else {
        // bad API key (401)
      }
      break;
    case 'not_found':
      // flow or session doesn't exist
      break;
    default:
      // unknown_error or any future code. Log err.requestId and err.message
      console.error('Self API error', { code: err.code, requestId: err.requestId });
  }
}

When details is populated

SelfApiError.details is the server's optional context object. It's set on the following errors:

unauthenticated + statusCode: 402 (billing gate): emitted when your organization's credit balance is below what the requested verification costs:

{
  balance: number; // spendable credits at request time
  required: number; // credits needed for this request
  planTier: 'free' | 'starter' | 'enterprise';
  creditGateMode: 'hard'; // always 'hard' (soft-gate orgs do not see this error)
}

validation_failed + statusCode: 400: { issues: ZodIssue[] }. The SDK pre-validates request bodies and throws SelfValidationError before sending, so this server-side variant is normally caught client-side. It can surface if the SDK and server schemas fall out of sync; pin an exact SDK version in production to avoid this.

For every other code, details is undefined.

License

Licensed under the Business Source License 1.1. © 2025 Socialconnect Labs, Inc.

On 2029-06-11 the license converts automatically to the Apache License, Version 2.0.