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

@pacspace-io/sdk

v0.7.0

Published

Official PacSpace Balance API SDK — zero-dependency TypeScript client for neutral usage-based billing verification

Readme

@pacspace-io/sdk

Official TypeScript SDK for the PacSpace Balance API. Zero dependencies, fully typed, built for Node.js 18+.

Install

npm install @pacspace-io/sdk

Quick Start

import { PacSpace } from '@pacspace-io/sdk';

const pac = new PacSpace({ apiKey: process.env.PACSPACE_API_KEY! });

// Record a delta
const delta = await pac.balance.emit('cust_123', -42.50, 'usage_charge');
console.log(delta.receiptId); // Store for later verification

// Derive balance
const { computedBalance } = await pac.balance.derive('cust_123');

// Compare against counterparty
const report = await pac.balance.compare('cust_123', {
  yours: 95000,
  theirs: 98000,
});

// Period-end checkpoint
const checkpoint = await pac.balance.checkpoint('cust_123', {
  period: '2026-02',
});

API Reference

new PacSpace(config)

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | required | Your Balance API key (pk_live_* or pk_test_*) | | baseUrl | string | auto-routed | API base URL (overrides auto-routing if provided) | | sandboxUrl | string | Sandbox URL from your PacSpace dashboard | Custom sandbox URL (used for pk_test_* keys) | | productionUrl | string | https://app.pacspace.io | Custom production URL (used for pk_live_* keys) | | chainId | number | auto-detected | Default chain ID (296 for sandbox, 295 for production) | | maxRetries | number | 2 | Max retries on transient errors | | timeout | number | 30000 | Request timeout in ms | | webhookSecret | string | — | Webhook signing secret (enables pac.webhooks) |

Balance API

pac.balance.emit(customerId, delta, reason, options?)

Record a credit or debit delta. Returns immediately with QUEUED status.

const delta = await pac.balance.emit('cust_123', -42.50, 'usage_charge', {
  referenceId: 'inv_001',
  metadata: { plan: 'growth' },
});

pac.balance.emitAndWait(customerId, delta, reason, options?)

Record a delta and poll until it reaches a terminal status (VERIFIED or FAILED).

const verified = await pac.balance.emitAndWait('cust_123', -42.50, 'usage', {
  timeout: 30_000,
  pollInterval: 1000,
});

pac.balance.derive(customerId, options?)

Derive a customer's balance from all verified deltas.

const result = await pac.balance.derive('cust_123');
console.log(result.computedBalance);

// With checkpointing for efficiency:
const next = await pac.balance.derive('cust_123', {
  startingBalance: result.computedBalance,
  startingCheckpoint: result.latestReceiptId!,
});

pac.balance.compare(customerId, balances, options?)

Compare balances against neutral truth for dispute resolution.

const report = await pac.balance.compare('cust_123', {
  yours: 95000,
  theirs: 98000,
});

if (report.matchesYours) {
  console.log('Your balance is correct');
}

pac.balance.receipt(customerId, options?)

Generate a verifiable receipt. With options.period (YYYY-MM), returns a period-specific receipt with proofRoot, verifyUrl, and verificationReference. Treat verifyUrl as an opaque invoice link; when Shared Record is enabled it may point at a persistent /c/{handle} customer record instead of a proof-root URL.

// Period receipt (shareable proof for invoices)
const receipt = await pac.balance.receipt('cust_123', { period: '2026-02' });
console.log(receipt.proofRoot);   // Proof root for verification
console.log(receipt.verifyUrl);   // Share this opaque URL on invoices
console.log(receipt.verificationApiUrl); // Machine endpoint for tools and auditors
console.log(receipt.finalBalance);

// Full record receipt (all verified deltas)
const full = await pac.balance.receipt('cust_123');
console.log(full.finalBalance);
console.log(full.verification.itemHashes);

pac.verify(proofRoot, options?)

Verify a proof root via the public verification endpoint. No API key required — the proof root is the access key.

const result = await pac.verify(receipt.proofRoot);
if (result.verified) {
  console.log(result.verification?.verificationExplorerUrl);
  console.log(result.summary?.recordCount);
}

Use options.source to select the verification source:

await pac.verify(receipt.proofRoot, { source: 'both' }); // 'db' (default), 'chain', or 'both'

Use receipt.verifyUrl for human invoice links. Use receipt.verificationApiUrl when a tool, agent, or auditor needs to call the machine verification endpoint. receipt.verificationExplorerUrl is a deprecated legacy compatibility field and will be retained until a future major version.

pac.balance.checkpoint(customerId?, options?)

Commit a period-end checkpoint. The proof root is recorded on the public verification layer for independent verification.

const checkpoint = await pac.balance.checkpoint('cust_123', {
  period: '2026-02',
});
console.log(checkpoint.proofRoot); // Include in your invoice

Webhooks

Verify webhook signatures and process events with type safety.

const pac = new PacSpace({
  apiKey: process.env.PACSPACE_API_KEY!,
  webhookSecret: process.env.PACSPACE_WEBHOOK_SECRET!,
});

// Express middleware
app.use('/webhooks', express.json({
  verify: (req, _res, buf) => { (req as any).rawBody = buf.toString(); }
}));

app.post('/webhooks/pacspace', pac.webhooks!.middleware(), (req, res) => {
  const event = (req as any).pacspaceEvent;

  if (event.event === 'delta.verified') {
    console.log('Delta verified:', event.data.receiptId);
  }

  res.status(200).json({ received: true });
});

// Manual verification
const event = pac.webhooks!.verify(signature, timestamp, rawBody);

Error Handling

All errors extend PacSpaceError with structured data:

import { PacSpace, InsufficientCreditsError, RateLimitError } from '@pacspace-io/sdk';

try {
  await pac.balance.emit('cust_123', -1000, 'charge');
} catch (err) {
  if (err instanceof InsufficientCreditsError) {
    console.log('Buy more credits');
  } else if (err instanceof RateLimitError) {
    console.log(`Retry after ${err.retryAfter}s`);
  }
}

| Error Class | Status | When | |-------------|--------|------| | ValidationError | 400 | Invalid request data | | InvalidApiKeyError | 401 | Bad or missing API key | | InsufficientCreditsError | 402 | Not enough credits | | NotFoundError | 404 | Resource not found | | ContractNotDeployedError | 412 | No contract provisioned | | RateLimitError | 429 | Rate limit exceeded | | TimeoutError | — | Polling timeout exceeded |

Environment Detection & Auto-Routing

The SDK automatically routes requests to the correct API endpoint based on your API key prefix:

  • pk_test_* → Sandbox API (the Sandbox URL shown in your PacSpace dashboard, or sandboxUrl when configured)
  • pk_live_* → Production API (https://app.pacspace.io)

Examples

Sandbox (automatic):

const pac = new PacSpace({ apiKey: 'pk_test_...' });
// Automatically uses the SDK's configured/default sandbox API URL.
// Pass sandboxUrl if your dashboard provides a different Sandbox URL.

Production (automatic):

const pac = new PacSpace({ apiKey: 'pk_live_...' });
// Automatically uses production API URL

Custom URLs:

// Override sandbox URL
const pac = new PacSpace({
  apiKey: 'pk_test_...',
  sandboxUrl: 'https://custom-sandbox.example.com',
});

// Override production URL
const pac = new PacSpace({
  apiKey: 'pk_live_...',
  productionUrl: 'https://custom-production.example.com',
});

// Override with explicit baseUrl (disables auto-routing)
const pac = new PacSpace({
  apiKey: 'pk_test_...',
  baseUrl: 'https://custom-api.example.com',
});

Requirements

  • Node.js 18+ (uses native fetch)
  • TypeScript 5+ (for full type inference)