SDK & API

SDK Installation

The @recurcite/sdk is a server-first Node.js package for sending evidence events to RecurCite. It handles authentication, payload validation, HMAC signing, and batch operations.

Installation

bash
npm install @recurcite/sdk

Or with your preferred package manager:

bash
yarn add @recurcite/sdk
# or
pnpm add @recurcite/sdk

Initialization

Import and initialize the SDK with your API key. The client is stateless — you can create it once and reuse across your application.

lib/recurcite.ts
import { init } from "@recurcite/sdk";

export const recurcite = init({
  apiKey: process.env.RECURCITE_API_KEY!,
  // Optional: HMAC signing for tamper-proof events
  signingSecret: process.env.RECURCITE_SIGNING_SECRET,
});

Server-side only

Never expose your API key or signing secret in client-side code. The SDK is designed for Node.js server environments only.

Sending events

track()

Send a single evidence event. Every event must include a type, payload, and ideally stripe_refs to link it to a Stripe customer.

typescript
await recurcite.track({
  type: "terms.accepted",
  payload: {
    version: "2.0",
    accepted_at: new Date().toISOString(),
  },
  stripe_refs: {
    stripe_customer_id: "cus_abc123",
  },
});

batchTrack()

Send multiple events in a single request. Useful for bulk imports or high-throughput scenarios.

typescript
await recurcite.batchTrack([
  {
    type: "product.used",
    payload: {
      feature_key: "api_calls",
      count: 150,
      occurred_at: new Date().toISOString(),
    },
    stripe_refs: { stripe_customer_id: "cus_abc123" },
  },
  {
    type: "user.login",
    payload: {
      occurred_at: new Date().toISOString(),
      ip: "203.0.113.42",
    },
    stripe_refs: { stripe_customer_id: "cus_abc123" },
  },
]);

Idempotency

By default, the SDK generates a unique event_id for each event. To ensure retries don't create duplicates, provide your own deterministic ID:

typescript
import { generateEventId } from "@recurcite/sdk";

await recurcite.track({
  event_id: generateEventId("terms.accepted", userId),
  type: "terms.accepted",
  payload: {
    version: "2.0",
    accepted_at: new Date().toISOString(),
  },
});

Tip

Use generateEventId(type, uniqueKey) to create deterministic IDs based on the event type and a unique identifier like the user ID or transaction ID.

HMAC signing

When you provide a signingSecret during initialization, the SDK automatically signs every request with an X-Recurcite-Signature header. The server verifies the signature and stores the verification status. Events with verified signatures carry more weight in evidence Packets.

typescript
const recurcite = init({
  apiKey: process.env.RECURCITE_API_KEY!,
  signingSecret: process.env.RECURCITE_SIGNING_SECRET,
});

// All subsequent track() calls are automatically signed

Error handling

The SDK throws typed errors for common failure cases:

typescript
try {
  await recurcite.track({ ... });
} catch (err) {
  if (err instanceof Error) {
    // err.message contains the server error detail
    console.error("RecurCite error:", err.message);
  }
}
StatusMeaningAction
400Invalid payload — missing required fields or unknown event typeFix the payload and retry
401Invalid or missing API keyCheck your RECURCITE_API_KEY
409Duplicate event_id (idempotency conflict)Event already recorded — safe to ignore
429Rate limitedBack off and retry with exponential delay
500Server errorRetry with backoff; contact support if persistent

TypeScript types

The SDK is fully typed. Key types you'll work with:

typescript
import type {
  TrackEvent,
  StripeRefs,
  EventType,
} from "@recurcite/sdk";

// EventType: "terms.accepted" | "user.login" | "product.used" | ...
// StripeRefs: { stripe_customer_id?, stripe_subscription_id?, ... }
// TrackEvent: { type, payload, stripe_refs?, event_id? }

Integration examples

Express middleware

middleware/recurcite.ts
import { recurcite } from "../lib/recurcite";

// Track logins on authentication
app.post("/auth/login", async (req, res) => {
  const user = await authenticate(req.body);

  await recurcite.track({
    type: "user.login",
    payload: {
      occurred_at: new Date().toISOString(),
      ip: req.ip,
      user_agent: req.headers["user-agent"],
    },
    stripe_refs: {
      stripe_customer_id: user.stripeCustomerId,
    },
  });

  res.json({ token: generateToken(user) });
});

Next.js API route

app/api/accept-terms/route.ts
import { recurcite } from "@/lib/recurcite";

export async function POST(req: Request) {
  const { userId, stripeCustomerId, termsVersion } = await req.json();

  await recurcite.track({
    type: "terms.accepted",
    payload: {
      version: termsVersion,
      accepted_at: new Date().toISOString(),
    },
    stripe_refs: {
      stripe_customer_id: stripeCustomerId,
    },
  });

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

Get your API key

  1. Go to Dashboard → Developers
  2. Click Create key
  3. Copy the key (shown only once)
  4. Add to your environment: RECURCITE_API_KEY=rc_live_…

Next steps