Ledger Gate

SDK Reference

Complete TypeScript API reference for @ledgergate/ledgergate-sdk — every exported function, class, type, and constant.

Installation

npm install @ledgergate/ledgergate-sdk
# pnpm add @ledgergate/ledgergate-sdk
# yarn add @ledgergate/ledgergate-sdk

Requires Node.js 18+. Framework packages (express, fastify) are optional peer dependencies — install only what you use.


createLedgergateSdk(config)

The main entry point. Validates config, applies defaults, and initialises the event queue.

import { createLedgergateSdk } from "@ledgergate/ledgergate-sdk";

const sdk = createLedgergateSdk({
  apiKey: process.env.LEDGERGATE_API_KEY!,
});

Parameters

ParamTypeDescription
configSdkConfigInputSDK configuration — only apiKey is required

Returns SdkInstance

Throws ZodError if the supplied configuration is invalid.

See Configuration for the full options reference.


SdkInstance

The object returned by createLedgergateSdk().

interface SdkInstance {
  readonly config: SdkConfig;
  readonly queue: EventQueue;
  shutdown(): Promise<void>;
}
MemberDescription
configFully resolved configuration with all defaults applied
queueThe in-memory event queue
shutdown()Flushes remaining events and tears down the queue. Idempotent.

Adapters

createExpressMiddleware(sdk)

Returns an Express RequestHandler that wires the SDK into the request/response lifecycle.

import { createExpressMiddleware } from "@ledgergate/ledgergate-sdk";

app.use(createExpressMiddleware(sdk));

After mounting, every request has an x402Context attached to res.locals.


fastifyLedgergate

Fastify plugin (Fastify 5, wrapped with fastify-plugin for global hook scope).

import { fastifyLedgergate } from "@ledgergate/ledgergate-sdk";

await app.register(fastifyLedgergate, { sdk });

After registration, every request has an x402Context property on FastifyRequest.

Options: FastifyLedgergateOptions

interface FastifyLedgergateOptions {
  sdk: SdkInstance;
}

Event Queue

EventQueue

interface EventQueue {
  enqueue(event: AnalyticsEvent): void;
  flush(): Promise<void>;
  shutdown(): Promise<void>;
  size(): number;
}
MethodDescription
enqueue(event)Adds an event to the buffer. Triggers an immediate send if batchSize is reached; otherwise schedules a timed flush. No-ops silently after shutdown().
flush()Forces an immediate send of all buffered events. Awaitable.
shutdown()Cancels the flush timer, waits for any in-flight send, then flushes remaining events. Idempotent.
size()Returns the current number of events waiting in the buffer.

Event Builders

Higher-level helpers that construct validated AnalyticsEvent objects from SDK context.

buildRequestReceivedEvent(context)

function buildRequestReceivedEvent(context: RequestContext): AnalyticsEvent

buildPaymentRequiredEvent(context, payment, response)

function buildPaymentRequiredEvent(
  context: RequestContext,
  payment: X402Metadata,
  response: ResponseData
): AnalyticsEvent

buildPaymentVerifiedEvent(context, payment, response)

function buildPaymentVerifiedEvent(
  context: RequestContext,
  payment: X402Metadata,
  response: ResponseData
): AnalyticsEvent

buildPaymentFailedEvent(context, payment, response)

function buildPaymentFailedEvent(
  context: RequestContext,
  payment: X402Metadata,
  response: ResponseData
): AnalyticsEvent

buildRequestCompletedEvent(context, response, payment?)

function buildRequestCompletedEvent(
  context: RequestContext,
  response: ResponseData,
  payment?: X402Metadata
): AnalyticsEvent

Core Utilities

createRequestContext(options)

function createRequestContext(options: CreateContextOptions): RequestContext

Builds an immutable per-request context: generates a UUID, starts the high-resolution timer, extracts and hashes the client IP, and redacts headers.

interface CreateContextOptions {
  method: string;
  path: string;
  headers: Record<string, string | string[] | undefined>;
  remoteAddress?: string;
  redaction: RedactionConfig;
  sampled: boolean;
}

captureResponseData(context, statusCode)

function captureResponseData(
  context: RequestContext,
  statusCode: number
): ResponseData

Calculates latency from the context timer and returns a ResponseData object.


shouldSample(rate)

function shouldSample(rate: number): boolean

Returns true with the given probability (01). Called once per request at middleware entry.


createTimer()

function createTimer(): Timer

interface Timer {
  elapsed(): number; // milliseconds since timer creation
}

getTimestamp()

function getTimestamp(): string // ISO 8601

Privacy Utilities

extractClientIp(headers, directIp?)

function extractClientIp(
  headers: Record<string, string | string[] | undefined>,
  directIp?: string
): string | undefined

Checks X-Forwarded-ForX-Real-IPdirectIp in order and returns the first non-empty value.


hashIp(ip, salt?)

function hashIp(ip: string, salt?: string): string

SHA-256 hashes salt + ip and returns the first 16 hex characters.


isSensitiveHeader(name)

function isSensitiveHeader(headerName: string): boolean

Case-insensitive check against the built-in sensitive header list.


redactHeaders(headers, allowlist?)

function redactHeaders(
  headers: Record<string, string | string[] | undefined>,
  allowlist?: readonly string[]
): Record<string, string>

Returns a new headers object with sensitive header values replaced by "[REDACTED]". Keys not in allowlist and matching the sensitive header list are redacted. Array values are joined with ", ".


x402 Detection

detectX402(statusCode, headers, config?, body?)

function detectX402(
  statusCode: number,
  headers: Record<string, string | string[] | undefined>,
  config?: X402DetectionConfig,
  body?: Record<string, unknown>
): X402Metadata | undefined

Inspects a response for x402 payment signals. Returns X402Metadata if a 402 status code is present or any configured payment field is found; otherwise returns undefined.


isPaymentRequired(statusCode)

function isPaymentRequired(statusCode: number): boolean

Returns true if statusCode === 402.


parsePaymentHeaders(headers, fieldMapping?)

function parsePaymentHeaders(
  headers: Record<string, string | string[] | undefined>,
  fieldMapping?: PaymentFieldMapping
): Partial<X402Metadata>

parsePaymentBody(body, fieldMapping?)

function parsePaymentBody(
  body: Record<string, unknown>,
  fieldMapping?: PaymentFieldMapping
): Partial<X402Metadata>

applyX402DetectionDefaults(input?)

function applyX402DetectionDefaults(
  input?: Partial<X402DetectionConfig>
): X402DetectionConfig

Config Utilities

parseConfig(input)

function parseConfig(input: SdkConfigInput): SdkConfig

Validates with Zod and applies all defaults. Throws ZodError on invalid input.


safeParseConfig(input)

function safeParseConfig(input: unknown): z.SafeParseReturnType<SdkConfigInput, SdkConfig>

Non-throwing variant — returns a Zod safe-parse result.


Types

SdkConfig

interface SdkConfig {
  readonly apiKey: string;
  readonly endpoint: string;
  readonly redaction: RedactionConfig;
  readonly transport: TransportConfig;
  readonly sampleRate: number;
  readonly debug: boolean;
  readonly x402: X402DetectionConfig;
}

RedactionConfig

interface RedactionConfig {
  readonly hashIp: boolean;
  readonly allowedHeaders: readonly string[];
  readonly ipHashSalt?: string;
}

TransportConfig

interface TransportConfig {
  readonly batchSize: number;
  readonly flushIntervalMs: number;
  readonly maxRetries: number;
  readonly timeoutMs: number;
}

RequestContext

interface RequestContext {
  readonly id: string;           // UUID v4 — shared by all events for this request
  readonly timer: Timer;
  readonly method: string;       // uppercase HTTP method
  readonly path: string;         // normalised path, no query string
  readonly headers: Readonly<Record<string, string>>;
  readonly clientIpHash?: string;
  readonly sampled: boolean;
}

ResponseData

interface ResponseData {
  statusCode: number;
  latencyMs: number;
}

AnalyticsEvent

interface AnalyticsEvent {
  schemaVersion: "1.0";
  eventId: string;
  eventType: string;
  timestamp: string;
  request: {
    id: string;
    method: string;
    path: string;
    statusCode?: number;
    latencyMs?: number;
    clientIpHash?: string;
    headers?: Record<string, string>;
  };
  payment?: {
    isRequired: boolean;
    address?: string;
    amount?: string;
    network?: string;
    token?: string;
    status?: "required" | "verified" | "failed";
  };
  sdk: { name: string; version: string };
}

X402Metadata

interface X402Metadata {
  readonly isPaymentRequired: boolean;
  readonly paymentAddress?: string;
  readonly paymentAmount?: string;
  readonly paymentNetwork?: string;
  readonly paymentToken?: string;
  readonly paymentStatus?: "required" | "verified" | "failed";
}

X402DetectionConfig

interface X402DetectionConfig {
  readonly source: "header" | "body" | "both";
  readonly fieldMapping: Required<PaymentFieldMapping>;
}

PaymentFieldMapping

interface PaymentFieldMapping {
  readonly address?: string;  // default: "x-payment-address"
  readonly amount?: string;   // default: "x-payment-amount"
  readonly network?: string;  // default: "x-payment-network"
  readonly token?: string;    // default: "x-payment-token"
  readonly status?: string;   // default: "x-payment-status"
}

EventType

const EventType = {
  REQUEST_RECEIVED: "request.received",
  PAYMENT_REQUIRED: "payment.required",
  PAYMENT_VERIFIED: "payment.verified",
  PAYMENT_FAILED:   "payment.failed",
  REQUEST_COMPLETED:"request.completed",
} as const;

PaymentStatus

const PaymentStatus = {
  REQUIRED: "required",
  VERIFIED: "verified",
  FAILED:   "failed",
} as const;

Zod Schemas

Use these to validate event data in your own tooling or tests:

ExportValidates
SdkConfigSchemaFull SDK config input
RedactionConfigSchemaredaction sub-object
TransportConfigSchematransport sub-object
X402DetectionConfigSchemax402 sub-object
AnalyticsEventSchemaA single analytics event

Constants

ExportValueDescription
SDK_VERSION"1.0.0"Current SDK version
SDK_NAME"ledgergate-sdk"SDK name included in every event

On this page