Usage Metering
Explains how MarkDocket records usage events through a transactional outbox, the retry and dead-letter behavior of the drain loop, and the distinction between product usage metering and direct COGS metering.
MarkDocket records every billable action through a metering outbox — a database table that acts as a durable queue between your activity and the billing system. This design means usage events are never lost due to a process restart or a temporary outage in the billing pipeline, and gives you a consistent, auditable record of everything that has been charged.
How the Outbox Works
Whenever you (or an automated workflow, agent turn, or API call) perform a billable action, MarkDocket writes a usage event to an internal outbox table in the same database transaction as the action itself. Nothing is sent to the billing system inline — the event is persisted first, then delivered asynchronously.
A periodic drain loop processes the outbox:
- Claim: Rows are claimed with a row-level lock so that multiple drain iterations never send the same event twice, even if the API server is running in multiple instances.
- Deliver: Each claimed event is sent to the billing system. On success the row is marked as delivered.
- Retry with backoff: If delivery fails, the event is retried with exponential backoff. Retries are capped at a maximum of 12 attempts, with the delay between attempts capped at 5 minutes.
- Dead-letter: Events that exhaust all retry attempts are marked permanently failed (dead-lettered) rather than silently dropped.
- Prune: Terminal rows — both successfully delivered and dead-lettered — are swept and pruned on a 6-hour cycle to keep the outbox table compact.
This approach provides exactly-once delivery semantics tied to your application's transaction boundaries. A process crash between a billable action and its delivery attempt does not lose the event; the outbox entry persists until the next drain cycle picks it up.
Operator visibility
Two Types of Usage Events
MarkDocket emits two distinct categories of metering event. Keeping them separate prevents double-counting in a platform where multiple services can participate in a single user action.
Product Usage Events
Product usage events record what you did — the feature you used, the unit being counted, and the quantity consumed. They carry no provider-level cost information.
Examples of what product usage events track:
- An agent turn being completed
- A trademark search being run
- A due-diligence report being generated
- An automation step being executed
Product usage events are emitted for all completed actions, including those where MarkDocket delegated work to an internal worker service on your behalf. The platform records the product-level outcome once, regardless of how many internal services were involved.
Direct COGS Events
COGS events (Cost of Goods Sold) record direct AI provider costs incurred by MarkDocket on your behalf — specifically, the provider, the operation type, the model, and whether the call used a platform-managed key or your own key (BYOK).
COGS events are emitted only for LLM calls that the MarkDocket API server makes directly. Worker services that independently call AI providers emit their own COGS events. The API server is explicitly prohibited from emitting a COGS event for work it has delegated to a sibling worker — doing so would count the same provider cost twice.
This separation is enforced through two distinct function signatures in the metering layer, not through application-level conditional logic, so the boundary cannot be accidentally bypassed.
BYOK and COGS metering
Why This Matters for Your Bill
Because the two event types are separate, your usage summary reflects:
- What you used (features, actions, units) — always tracked regardless of how work was fulfilled internally.
- What MarkDocket spent on your behalf in direct AI provider costs — tracked only once, at the service that made the call, never double-counted.
This means your bill is accurate even for complex workflows where an agent turn triggers multiple internal services, or where an automation run mixes platform AI calls with BYOK calls.
Retry Behavior Reference
| Parameter | Value |
|---|---|
| Maximum delivery attempts | 12 |
| Backoff strategy | Exponential |
| Maximum backoff interval | 5 minutes |
| Dead-letter after | All retries exhausted |
| Prune cycle (terminal rows) | Every 6 hours |
Relation to Billing Blocks
The metering outbox records usage after an action completes. Before a billable action can start — particularly for agent turns — MarkDocket creates a billing reservation as part of the turn authorization step. If your account cannot support the action, a billing block is returned before any work begins and no outbox entry is created.
See the Billing Block Envelope page for details on how billing blocks surface in the UI, the API, the CLI, and automation workflows.
Billing Block Errors
Explains what a billing block is, how BillingBlockEnvelope errors surface across the HTTP API, agent SSE stream, CLI, and MCP server, and how users and developers can resolve them.
CLI OAuth and Dynamic Client Registration
How the MarkDocket CLI performs browser-based OAuth 2.1 login using RFC 7591 dynamic client registration and PKCE, with no embedded client_id in the distributed package.