Pre-Authorization and Reservations
Explains how MarkDocket pre-authorizes billing capacity before agent turns and other operations, documents the turn state machine and CAS transitions, describes reservation lifecycle, and explains what happens to reservations and files on expiry or cancellation.
MarkDocket reserves billing capacity before any agent work begins — before file uploads are accepted, before messages are committed, and before any LLM call is made. This page explains what a billing reservation is, how it fits into the agent turn lifecycle, and what happens when a turn expires or is cancelled.
Why Pre-Authorization Exists
Agent turns involve a sequence of potentially costly steps: accepting file attachments, issuing LLM calls, executing tool calls against external services, and streaming results back. Without upfront capacity verification, a turn could reach mid-execution before discovering that the account lacks the capacity to pay for it.
Pre-authorization solves this by gating every turn behind a billing check that happens atomically with the turn's state transition. If authorization is denied, the turn never starts and no resources are consumed.
The Agent Turn State Machine
Every agent turn is persisted in MarkDocket's database and moves through a well-defined sequence of states. State transitions use compare-and-swap (CAS) operations, meaning a transition only succeeds if the turn is currently in the expected prior state. This prevents race conditions between concurrent requests or retries.
| State | Meaning |
|---|---|
authorizing | Turn has been initiated; billing reservation is being created |
authorized | Billing reservation created successfully; file uploads are now permitted |
uploading | Attached files are being accepted and bound to this turn |
running | The agent is actively executing the turn loop |
completed | Turn finished successfully |
denied | Billing authorization was rejected; turn never ran |
failed | Turn encountered a non-billing error during execution |
expired | Turn was not completed within its allowed window |
cancelled | Turn was explicitly cancelled before or during execution |
Authorization Is Atomic with State Transition
The billing reservation is created atomically with the authorizing → authorized CAS update. There is no window between "turn created" and "billing reserved" during which a turn could proceed without a reservation. If the CAS update fails for any reason — including insufficient capacity — the transition does not complete, no reservation is held, and the turn moves to denied.
Only once a turn reaches authorized does the system permit file uploads or message commits for that turn.
File Uploads Are Reservation-Scoped
File attachments uploaded as part of an agent turn are validated against the active billing reservation and bound to the turn's message in a single database transaction. An upload that cannot be validated against a current reservation is rejected.
To support idempotent re-uploads without a database read on every attempt, upload identifiers are derived deterministically from the turn ID and the idempotency key provided at submission time. This means submitting the same upload twice under the same idempotency key returns the same result without creating a duplicate record.
What Happens on Expiry
Turns that are not completed within their allowed window transition to expired. When this happens:
- The billing reservation is released. No charges are applied for the incomplete turn's reserved capacity.
- Orphaned files are cleaned up. Any files uploaded to blob storage for the turn but not associated with a completed message are deleted by a background sweep.
This cleanup is handled automatically. You do not need to take any action when a turn expires.
What Happens on Cancellation
If a turn is cancelled — either explicitly by the user or programmatically during an error path — the same cleanup applies:
- The billing reservation for the turn is released.
- Any partially uploaded files that were not committed to a completed message are removed.
The four-phase turn submission process (reservation → upload → message/stream → cancellation on error) is designed so that if any phase fails, cancellation is triggered before re-throwing. This means a failed submission does not leave dangling reservations or orphaned blob files.
Billing Blocks During Authorization
If your account does not have sufficient capacity to authorize a new agent turn, the API returns a billing block response. In the web application, this surfaces as a dialog describing the specific reason and the action required — for example, adding a payment method or upgrading your plan.
In the CLI and MCP surfaces, billing blocks are returned as structured error values with a machine-readable reason and required action, so integrations can handle them programmatically.
Billing blocks are not errors
A billing block means your account needs attention before the operation can proceed. The turn is cleanly denied — no partial work is done and no charges are incurred. Once you resolve the underlying issue (for example, by adding a payment method), you can resubmit the turn.
Reservations in Automation Runs
Automation runs that include agent nodes follow the same pre-authorization model. Each agent node within an automation run must obtain a billing reservation before its turn begins. If a billing block is encountered during an automation run, the run is suspended cleanly — it is not marked as failed. The run can be resumed or retried once the billing issue is resolved.
Summary
- A billing reservation is created atomically with the turn's first state transition; there is no unguarded window.
- File uploads and message commits are only permitted after a reservation is established.
- Expired and cancelled turns have their reservations released and their orphaned files cleaned up automatically by a background process.
- Billing blocks surface as structured, actionable responses — not generic errors — at every interface: web app, CLI, MCP, and automation runs.
Pay-As-You-Go Pricing Catalog
Documents the MarkDocket PAYG pricing catalog structure, how live prices are fetched at SSR time via the shared customer-pricing-contract library, why no hardcoded prices appear in any UI, and how the system handles pricing unavailability gracefully.
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.