Scrawn LogoScrawn Docs
SDK ReferenceFunctions

Usage Tracking

Track billable events with basicUsageEventConsumer and middlewareEventConsumer

Events are the core of Scrawn every API call, AI generation, or billable action produces an event. Track them manually where you need control, or automatically with middleware.

Manual Tracking

Call basicUsageEventConsumer whenever a billable action happens:

Debit a fixed amount (smallest currency unit):

import { biller } from "./scrawn/biller";

await biller.basicUsageEventConsumer({
  userId: "user-123",
  debit: 500,
});

Use a price tag managed on the backend:

await biller.basicUsageEventConsumer({
  userId: "user-123",
  debit: biller.tag("PREMIUM_CALL"),
});

Or use a pricing expression - wrap with biller.expr():

import { mul } from "@scrawn/core";

await biller.basicUsageEventConsumer({
  userId: "user-123",
  debit: biller.expr(mul(biller.tag("PER_CALL"), 3)),
});

Parameters

Prop

Type

The debit field accepts a number (smallest currency unit), a biller.tag() reference (e.g. biller.tag("PREMIUM_CALL")), or any pricing expression wrapped in biller.expr() (e.g. biller.expr(mul(biller.tag("RATE"), 3))). Raw mul(), add(), etc. must be wrapped in biller.expr() to be accepted.

Options

The second argument accepts an optional options object:

Prop

Type

Automatic Tracking (Middleware)

middlewareEventConsumer drops into any Express-compatible framework and tracks events automatically based on your extractor function.

import { biller } from "./scrawn/biller";

app.use(biller.middlewareEventConsumer({
  extractor: (req) => ({
    userId: req.headers["x-user-id"] as string,
    debit: biller.tag("API_CALL"),
  }),
}));

Use whitelist to only track specific paths:

app.use(biller.middlewareEventConsumer({
  extractor: (req) => ({
    userId: req.headers["x-user-id"] as string,
    debit: biller.tag("API_CALL"),
  }),
  whitelist: ["/api/**"],
}));

Use blacklist to exclude specific paths:

app.use(biller.middlewareEventConsumer({
  extractor: (req) => ({
    userId: req.headers["x-user-id"] as string,
    debit: biller.tag("API_CALL"),
  }),
  blacklist: ["/api/collect-payment"],
}));

Configuration

Prop

Type

Best Practices

Place after authentication:

app.use(authMiddleware);
app.use(biller.middlewareEventConsumer({ /* ... */ }));

Middleware runs tracking in the background - your handler is not blocked:

app.post("/api/generate", async (req, res) => {
  const result = await generateContent(req.body);
  res.json(result);
  // Tracking already happened in parallel
});

Framework Compatibility

The middleware uses standard (req, res, next) signatures. For Fastify, Next.js, or Hono, call basicUsageEventConsumer directly in route handlers or check framework recipes for adapters.

Next Steps