Documentation
Integrate in one call
Ratchet has one important endpoint. Everything else exists to support it.
Machine-readable: OpenAPI · llms.txt · capability manifest · MCP tool schemas
1. Get a key
One request creates a workspace, seeds starter policies, and returns a key. The key is shown once and stored only as a keyed hash.
Or use the console if you'd rather click.
2. Ask before you act
Branch on decision. This is the whole contract.
| Decision | Meaning | What you must do |
|---|---|---|
| execute | You hold the lease. | Perform the action, then report. |
| duplicate | Already completed. | Use result. Do not act. |
| in_flight | Someone else holds a live lease. | Wait retry_after_seconds, ask again. |
| blocked | A prior attempt's outcome is unknown. | Verify at the vendor, then resolve. |
| approval_required | Operator decision pending. | Poll, or wait for the webhook. |
| denied | Policy, budget, or rejection. | Report the reason. Do not work around it. |
3. Report what happened
failed only when you know
the action did not reach the outside world. If you are unsure — a timeout, a dropped
connection, an ambiguous error — report nothing. The lease lapses and Ratchet records an
honest indeterminate. A false failed is worse than silence,
because it licenses a duplicate.
Designing idempotency keys
The key is the entire mechanism. Derive it from the work, deterministically, so a retry of the same logical action produces the same key.
Good
- welcome-email:user_123
- invoice:2026-08:acct_88123
- pr:acme/api:feature-auth
- refund:order_551:full
Broken
- uuid4()
- "send-" + Date.now()
- str(random.random())
- f"job-{attempt_number}"
A key that changes on every attempt makes every retry look like new work. The gate can only recognise a duplicate if the duplicate says the same thing.
Reusing one key for genuinely different arguments is rejected with
idempotency_key_reuse — that collision would otherwise hide a real, distinct
action behind an unrelated record.
Policy: what happens when things go wrong
Configured per effect type. The default for an unconfigured type is the safe one.
| Field | Values | Effect |
|---|---|---|
| mode | allow · require_approval · deny | Whether the type may run at all, and whether a human gates it. |
| on_indeterminate | block · retry · probe | The important one. What a later caller may do when
a prior attempt's outcome is unknown. Defaults to block. |
| lease_seconds | 5–3600 | How long a holder has to report before the effect goes indeterminate. |
| max_attempts | 1–50 | Ceiling on attempts for one key. Exceeding it denies the effect. |
| max_cost_micros | integer · null | Refuse a single effect declaring more than this. |
| daily_budget_micros | integer · null | Daily external-spend ceiling for this type. |
| retention_days | 1–400 | How long records and replayable results are kept. |
Choose retry only when the underlying vendor is genuinely idempotent, or a
duplicate is truly harmless. Ratchet will not assume that for you.
Recovering an indeterminate effect
Check the vendor, then record what you found. This is what unblocks the key.
Subscribe to effect.indeterminate to be told the moment one appears, or poll
GET /v1/effects?state=indeterminate.
Reversible effect groups
Rolling back a multi-step workflow
Declare several effects as one unit of work, and how to undo each. If the unit fails, Ratchet returns the exact compensation plan.
Then perform the plan
suggested_idempotency_key and set compensates_effect_id. That is
what stops a retried rollback from refunding twice — the failure that makes hand-rolled
compensation dangerous.
| Group state | Meaning |
|---|---|
| open | Accepting steps. |
| committed | Every step succeeded. Can still be unwound later. |
| unwinding | Rolling back. Refuses new forward steps. |
| unwound | Everything reversible was reversed. |
| unwind_failed | A step that succeeded had no compensation. Not a clean rollback, and it will not claim to be. |
Read unresolved before acting on a plan. If any step's outcome is unknown, the
rollback stops until you verify it — rolling back past a maybe is how a half-undone state
is created.
Payments
Card, or crypto without custody
Subscribe with a card, or top up prepaid credit on-chain.
- Non-custodial. Ratchet holds no private key. Payments go directly to an address the operator controls; Ratchet only watches the chain.
- Quoted in USD. Credit granted is the USD amount, never the token amount, so a price move between quote and settlement cannot mint credit.
- Underpayment is never rounded up. A short transfer credits nothing and waits for a human.
- Volatile assets are refused unless a price oracle is configured. Quoting one without a live rate would mean inventing a price.
MCP
Nine tools over stdio or streamable HTTP, backed by the same code as the REST API.
Works today with Claude Code, Claude Desktop, Cursor, and any MCP client — see Get started for each. OpenAI-compatible tool loops and Gemini-style clients use the REST API directly.
Loading tool list…
Connecting
Errors
Every failure returns {"error": {"code", "message", "detail"}}.
Branch on code; it is stable.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Schema validation failed. detail.validation says where. |
| 401 | unauthorized | Missing, malformed, or revoked key. |
| 402 | insufficient_credit | Allowance exhausted and balance too low. Replays still work. |
| 403 | forbidden | Missing scope. detail.required names it. |
| 403 | budget_exceeded | A daily spend ceiling would be breached. |
| 403 | cost_ceiling_exceeded | Declared cost exceeds the per-effect maximum. |
| 404 | not_found | No such record in this workspace. |
| 409 | idempotency_key_reuse | Same key, different payload. |
| 409 | lease_lost | Your lease was superseded. Do not assume your work counted. |
| 409 | invalid_state | The transition is not legal from the current state. |
| 413 | payload_too_large | Store large outputs elsewhere; record a reference. |
| 429 | rate_limited | detail.retry_after_seconds says how long to wait. |