Skip to content
Documentation menu

Requests & billing

Quote, reserve, dispatch, capture. Every billable request follows the same lifecycle and ends with a receipt.

Quotes

A quote locks the price for a specific input for a few minutes. It returns an exact amount, or a ceiling when the supplier meters usage (is_ceiling: true).

bash
curl https://api.uselocal.sh/v1/quotes \
  -H "Authorization: Bearer $LOCAL_API_KEY" -H "Content-Type: application/json" \
  -d '{"tool":"{provider}/{slug}","input":{...}}'
# → { quote_id, tool, tool_version, pricing_mode, amount_usd, is_ceiling, currency: "USD", expires_at, request_hash }

Pass quote_id to execute. The input must hash to the same request_hash or you get 409 quote_mismatch; after expires_at you get 409 quote_expired.

Execute

text
POST /v1/tools/{provider}/{slug}/execute
Headers: Authorization, Idempotency-Key (required), Content-Type: application/json
Body:    { input, quote_id? , max_charge_usd?, project_id?, async? }
→ 200 ExecuteResponse | 202 ExecuteResponse with "job" | error envelope

Without a quote, max_charge_usd is your hard ceiling. We reserve min(ceiling, price) before dispatch and never charge above it. If the ceiling is lower than the tool’s minimum charge you get 422 ceiling_too_low and nothing is reserved.

Idempotency

Idempotency-Key is required on every billable call. The scope is (workspace, operation, key). Retrying with the same key and the same body replays the original outcome without charging again. Reusing a key with a different body returns 409 idempotency_conflict. A key whose first attempt is still running returns 409 idempotency_in_progress.

Recommended pattern

Generate one UUID per logical attempt. Retry network failures with the same key. Generate a new key only when the input changes.

Billing states

StateMeaningFinal
noneNothing was reserved (validation failed, free tool, or rejected before pricing).Yes
reservedFunds held, dispatch pending or in progress.No
capturedFinal charge posted; the remainder of the hold was released.Yes
releasedConfirmed unbilled failure; the hold was returned.Yes
reconcilingOutcome uncertain (timeout or ambiguous supplier response). We check the supplier receipt and then capture or release.No
manual_reviewCould not be resolved automatically; an operator decides. Funds stay held until then.No

Dispatched reservations are never released by a timer. A request in reconciling shows “We’re checking this request’s final charge.” in the dashboard until it is resolved.

Receipts

GET /v1/requests/{request_id} returns the request record with receipt: { charged_usd, reserved_usd, final, note }. GET /v1/usage lists requests with filters and totals; add format=csv for an export.

Response headers

  • X-Local-Request-Id — always present; quote it when contacting support.
  • X-Local-Charged-Usd, X-Local-Billing-State, X-Local-Reserved-Usd — on billable responses.