Skip to main content
Usage events feed both billing paths: they deduct credits at track-time and meter usage for invoice-time aggregation. Track a few events per request with unitpay.usage.track; for firehose volumes, use the stateful UnitPayIngestion batcher.

unitpay.usage.track

Tracks one billable event, or an array of them in a single request. Also exposed as unitpay.track(...). ParametersTrackEventInput | TrackEventInput[]:
customerId
string
required
The customer the event belongs to.
eventName
string
required
The billable event, e.g. ai-generation or api-call.
quantity
number
default:"1"
How much usage to record.
properties
Record<string, unknown>
Arbitrary event metadata for aggregation and filtering.
timestamp
string
ISO-8601 event time. Defaults to now if omitted.
idempotencyKey
string
Dedupe key so retries don’t double-count.
ReturnsPromise<TrackEventResult> with accepted: number, rejected: number, and optional rejections ({ index, reason, message }[]).
import { UnitPay } from '@unitpay/node';

const unitpay = new UnitPay({ apiKey: process.env.UNITPAY_API_KEY });

// Single event
await unitpay.track({
  customerId: 'cus_123',
  eventName: 'ai-generation',
  quantity: 1,
  properties: { model: 'opus' },
});

// Batch — one request, one result
const result = await unitpay.usage.track([
  { customerId: 'cus_123', eventName: 'api-call', quantity: 10 },
  { customerId: 'cus_456', eventName: 'api-call', quantity: 3 },
]);
// result.accepted === 2

UnitPayIngestion

A separate, stateful client for high-throughput pipelines. Events are buffered and auto-flushed on an interval or when the batch fills; retries and buffer overflow are handled for you. Construct it once and keep it alive for the process lifetime. ConstructorUnitPayIngestionConfig:
apiKey
string
required
Your secret key (upay_sk_…).
autoBatch
boolean
default:"true"
Flush on a timer. Set false to flush only manually.
flushIntervalMs
number
default:"1000"
How often the timer flushes the buffer.
maxBatchSize
number
default:"100"
Flush immediately once the buffer reaches this size.
maxBufferSize
number
default:"10000"
Hard cap; the oldest event is dropped on overflow (surfaced via onFlushError).
maxRetries
number
default:"3"
Retries on 5xx / network errors before events go back in the buffer.
timeout
number
default:"30000"
Per-request timeout in ms.
onFlushError
(error, events) => void
Called when a flush fails or an event is dropped.
baseUrl
string
fetch
typeof fetch
Methods
  • track(event) — buffer one event (TrackEventParams); non-blocking. Fills in quantity, timestamp, and idempotencyKey if omitted.
  • flush() — force-flush the buffer now. Returns Promise<FlushResult> ({ accepted, rejected, rejections }).
  • check(params) — synchronous entitlement check, bypassing the buffer. Takes { customerId, featureSlug, requestedUsage? }, returns Promise<CheckResponse> ({ access: boolean, deniedReason? }).
  • shutdown() — stop the timer and flush what’s left. Call on process exit.
  • bufferSize — current number of buffered events.
import { UnitPayIngestion } from '@unitpay/node';

const ingestion = new UnitPayIngestion({
  apiKey: process.env.UNITPAY_API_KEY!,
  onFlushError: (err, events) => console.error('flush failed', err, events.length),
});

// Fire-and-forget on the hot path
ingestion.track({ customerId: 'cus_123', eventName: 'api-call' });

// Gate an action before doing expensive work
const { access } = await ingestion.check({
  customerId: 'cus_123',
  featureSlug: 'ai-generation',
  requestedUsage: 1,
});
if (!access) throw new Error('over quota');

// Drain on shutdown
process.on('SIGTERM', () => ingestion.shutdown());

See also

Customers & subscriptions

Read who you’re billing.

Errors & pagination

Typed errors and retry behavior.