---
title: "Record internal usage (batched, high throughput)"
method: POST
path: "/v1/usage/internal/batch"
tags: ["Usage"]
---

# Record internal usage (batched, high throughput)

`POST /v1/usage/internal/batch`

Batch-optimized variant of `POST /v1/usage/internal`.

Events are buffered in memory and flushed to the database every ~2 seconds
using a single bulk INSERT. This reduces per-event DB overhead by ~99% and
is designed for customers sending 1M+ events/day.

Returns 202 immediately. The event will be persisted within 2 seconds.
Idempotency is still enforced via `idempotencyKey` — duplicates are
silently skipped during the bulk insert.

> **Requires a secret key (`sk_*`) with at least the `OPERATOR` role.**

## Request body

- object
  - `customerId` string — Drip customer ID (cus_*). One of customerId, externalCustomerId, or stripeCustomerId is required.
  - `externalCustomerId` string — Your own database's customer ID. If no Drip customer exists yet for (business, externalCustomerId), one is auto-provisioned as an internal customer on first use.
  - `stripeCustomerId` string — Stripe customer ID (`cus_…`) from your connected Stripe account. If no Drip customer exists yet for (business, stripeCustomerId), one is auto-provisioned and usage is forwarded to Stripe's Billing Meter Events. Intended for merchants who just finished Stripe OAuth, so you can start sending usage against Stripe IDs immediately without waiting for the background customer import.
  - `usageType` string — Usage type matching a pricing plan (defaults to "generic" if omitted)
  - `quantity` number — Quantity of usage (defaults to 1 if omitted)
  - `units` string — Human-readable unit label for display (e.g., "tokens", "API calls", "seconds")
  - `description` string — Human-readable description for support/finance teams (e.g., "Chat completion for Customer XYZ")
  - `idempotencyKey` string, required — Unique key to prevent duplicate charges. Required. Use a stable identifier like `{customerId}_{action}_{timestamp}` so retries produce the same key.
  - `metadata` object — Optional metadata
  - `workflowId` string — Link this usage to a workflow
  - `runId` string — Link this usage to an agent run
  - `eventType` 'USAGE' | 'INFERENCE' | 'TOOL_CALL' | 'DELEGATION' | 'RETRIEVAL' | 'CUSTOM' — Classify the type of usage event
  - `actionName` string — Name of the action performed (e.g., "chat_completion", "image_generation")
  - `outcome` 'SUCCEEDED' | 'FAILED' | 'PENDING' | 'SKIPPED' | 'CANCELLED' — Outcome of the action
  - `explanation` string — Human-readable explanation of what happened
  - `parentEventId` string — ID of the parent event (for building causality trees)
  - `retryOfEventId` string — ID of the event this is retrying (for retry chain tracking)
  - `attemptNumber` integer — Attempt number (1 = first try, 2 = first retry, etc.)
  - `inputHash` string — SHA-256 hash of the input for verification
  - `outputHash` string — SHA-256 hash of the output for verification
  - `input` object — Raw input data (will be hashed for verification)
  - `output` object — Raw output data (will be hashed for verification)

## Response `202`

Usage accepted for batched insert

- object — Usage accepted for batched insert
  - `success` boolean
  - `customerId` string
  - `usageType` string
  - `quantity` number
  - `idempotencyKey` string
  - `pendingEvents` integer — Number of events waiting to be flushed
  - `message` string

## Other responses

- `400` — Validation error
- `401` — Unauthorized
- `404` — Customer not found
- `429` — Rate limit exceeded

---

[API](https://skmtc.net/usedrip/apis/drip-api.md) · [All operations](https://skmtc.net/usedrip/apis/drip-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/usedrip/drip-api/revisions/2cb1567969ca/schema)
