Authentication & x402¶
Crank has no accounts to create before you start. Authentication is about three things:
- Wallet binding — proving which public wallet an action belongs to.
- Payment — settling the technology service fee for value-bearing actions via the x402 payment rail.
- Caller identity — for autonomous agents, a scoped, expiring, revocable pairing token on the authenticated agent-v1 surface. That surface, the pairing flow, the scope table, expiry and revocation are covered in Agent authentication (agent-v1).
Reads need none of these. You can call every free read tool anonymously on the public surface; value-bearing calls belong on agent-v1.
Wallet binding¶
Crank is non-custodial. It only ever handles public keys. No code path transmits, persists, or logs a private key or seed phrase.
- The wallet a value-bearing action belongs to is taken from the top-level
wallet_addressargument, never inferred from inside a tool's other arguments. wallet_addressis always a public key you supply.- Value-bearing tools return an unsigned transaction (or, for venue-custodied Tier-B perps venues, a signing payload). You sign it with your own key, in your own process, and broadcast it. Crank never signs for you.
That is the whole binding model: you assert the public key, you keep the private key, you sign locally.
Free tier vs. paid¶
Each caller gets a daily free-tier allowance of value-bearing calls before the payment gate activates. The gate classifies every tool:
- Free tools — all reads (quotes, balances, market data, discovery,
classification, usage reports). Always
$0, no payment ever required. - Paid tools — value-bearing actions (swaps, perps, lending, staking, shorting, equity trades, premium intelligence tiers).
When you call a paid tool, the gate returns one of three outcomes:
| Reason | Meaning |
|---|---|
disabled |
Billing is off for this deployment; call proceeds free. |
free_tier |
Within your daily allowance; call proceeds free. The response reports free_tier_remaining. |
paid |
Allowance exhausted; the technology service fee applies. |
The x402 payment flow¶
When a fee is owed and no valid payment is attached, the call fails with a
PAYMENT_REQUIRED envelope (an HTTP 402-style result):
{
"ok": false,
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Payment required for jupiter_swap",
"fee_usd": 0.18,
"facilitator": "https://facilitator.example/...",
"accepts": [ { "scheme": "exact", "network": "solana", "asset": "USDC", "amount": "..." } ]
}
}
Steps:
- Quote. Read
fee_usdand theacceptspayment requirements from thePAYMENT_REQUIREDenvelope. - Pay. Construct an x402 payment for that amount in USDC on Solana.
- Retry. Call the tool again with the
payment_headerargument set to your x402 payment payload. - Verify & settle. Crank verifies the payment through the Coinbase CDP facilitator. The facilitator moves the USDC straight to the Crank treasury — Crank never holds your funds in between. The verified call then executes and returns the unsigned transaction.
The fee is a technology service fee, charged as a percentage of the action's notional value, with a per-action floor. Exact rates, tiers, and discounts: Fee schedule.
Pay in $CRANK for a discount¶
Value-bearing tools accept pay_in_crank=true. Paying the technology service fee
in $CRANK applies an additional discount that stacks multiplicatively with any
staker discount. See the Fee schedule.
Premium feature billing¶
Some intelligence tools (get_market_briefing pro/platinum tiers,
get_consensus, get_contrarian_signals) are flat per-call premium features
rather than percentage-of-notional. They are covered by an active $CRANK-staker
subscription, or you pay the per-call x402 fee with payment_header. The billing
outcome is reported in the response billing field. Pricing model and cost
basis: see docs/X402_COSTING.md.
Agent wallet provisioning (managed wallets)¶
For autonomous agents you can provision a managed wallet: a non-custodial control plane that applies policy guardrails to an agent's public wallet. This does not give Crank custody — it governs what actions the policy gate will allow.
| Tool | Purpose |
|---|---|
create_agent_wallet |
Provision a managed wallet for an agent_id. It starts on the balanced policy preset by default; pick another with policy_preset (conservative / balanced / aggressive), or pass unlimited=true to start with no policies (recorded in the decision journal as your explicit choice). This is a default you can change at any time with set_wallet_policy, not a platform cap. Supply the agent's public key, or omit it to provision managed signing. |
set_wallet_policy |
Set trading limits: max_trade_size, daily_limit, approved_tokens, banned_tokens, position_limit, kill_switch, drawdown_limit. |
wallet_status |
Current state, policy summary, recent activity, total volume, and fee tier. |
kill_wallet |
Emergency freeze: the policy gate then refuses every value-bearing action for that wallet. |
The policy gate runs before the x402 fee is ever charged, so an agent is never billed for a trade that policy will refuse. Hosted scoped-key signing (Turnkey) is provisioned separately; until then a managed strategy returns an unsigned transaction per due tick for the owner to sign.
create_agent_wallet puts that choice explicitly in your hands via the
wallet_address argument. Omit it and Crank provisions a Turnkey TEE-managed
signer: the agent can trade autonomously between due-tick windows with no
owner present, but the key is generated and held inside Turnkey's enclave and
is not exportable by design — not a current limitation, but a deliberate
security posture (the platform cannot get the key out even if asked). Supply
wallet_address and you keep self-custody instead: the key is fully portable
and stays wherever you generated it, but every transaction still needs the
owner to sign it, so there is no unattended autonomous ticking. Choose
TEE-managed signing when autonomy matters more than key portability, and
self-signing when portability matters more than autonomy.
Rate limits¶
Limits bind to who the caller really is, not to any self-asserted identifier:
the verified pairing token on /mcp/plugin-v1 and /mcp/agent-v1, and the
client IP on the anonymous surfaces (the default /mcp and
/mcp/chatgpt-v1). The caller_id tool argument is an analytics label only
— rotating it never resets a bucket. Buckets live in a shared store, so they
survive restarts and are shared across server replicas.
Four published tiers (defaults; the live values are always available from
the free get_rate_limits tool):
| Tier | Default | Applies to |
|---|---|---|
anonymous |
60 calls / 60 s | Unauthenticated callers, per client IP. |
paired |
240 calls / 60 s | Pairing-token and API-key callers (cpat_ / cak_), per credential. |
elevated |
960 calls / 60 s | An API key Crank staff granted the elevated rate tier. Same per-credential bucket key, larger base bucket. |
value_bearing |
20 calls / 60 s | A separate, lower bucket additionally consumed by value-bearing (fee-classified) tools on every surface, on top of the caller's base tier. Not raised by the elevated tier. |
A credential's rate tier is a property of the key itself (default unless
staff set it to elevated at issuance); it only sizes the bucket and never
changes which bucket a call lands in.
What an exhausted caller sees:
- Every surface returns the standard
RATE_LIMITEDerror envelope withretry_after_secondsin its details — wait that long and retry. - On
/mcp/plugin-v1and/mcp/agent-v1,tools/calladditionally answers at the HTTP layer with status429and aRetry-Afterheader, so SDK retry machinery that keys on HTTP status works without parsing the body.
Failure posture, by design: if the shared rate-limit store errors,
value-bearing tools fail closed (refused with RATE_LIMITED and a
reason of rate_limit_store_unavailable) and reads fail open (allowed).
A degraded limiter never waves through fee-bearing writes unmetered, and
never takes the free read surface down with it.
The REST agent bridge (/api/v1/agent/*)¶
The REST bridge (Gemini / OpenAI dispatch, per-tool GPT Actions, OpenClaw
provisioning) follows the same identity-keyed contract. Dispatch authenticates
with a Crank API key (cak_..., issued from Settings -- see
Agent authentication) or a pairing token,
sent as Authorization: Bearer <key> or X-API-Key. The key's scopes are
checked on every dispatched tool (an under-scoped call is refused with HTTP
403 and an insufficient_scope envelope before any gate or fee runs), and
the call acts only for the key owner's wallet. Requests are limited per the
identity resolved from that key -- rotating any self-asserted label,
body field, or header never resets a bucket, and two different keys get
independent buckets. Anonymous surfaces (the read-only catalogues and OpenClaw
provisioning) are limited per client IP. Legacy operator-configured bridge
keys still work for one deprecation window and will be removed; move to a
cak_ key.
Default limits match the tiers above: 240 / 60 s per resolved key,
60 / 60 s per anonymous IP, plus the same separate 20 / 60 s
value-bearing bucket additionally consumed when a dispatch names a
fee-classified tool. Buckets live in a shared store across replicas. An
exhausted caller receives HTTP 429 with a Retry-After header and the
standard RATE_LIMITED error envelope (retry_after_seconds in its
details).
Error codes you will see¶
| Code | Meaning |
|---|---|
PAYMENT_REQUIRED |
Fee owed; attach payment_header and retry. |
RATE_LIMITED |
Bucket exhausted (or the limit store is down and the tool is value-bearing); wait retry_after_seconds and retry. |
POLICY_VIOLATION |
A managed-wallet policy limit was breached. |
KILL_SWITCH_ACTIVE |
Platform-wide emergency stop engaged. |
SOFT_LAUNCH_BLOCKED |
Pre-mainnet rollout control blocked the action. |
UNVERIFIED_TOKEN |
Target token failed authenticity checks (override with allow_unverified=true where offered; hard scam signals are never overridable). |
UNSAFE_TRANSACTION |
Constructed transaction touched a program outside the known-good allow-list. |
CONFIG_ERROR |
The payment facilitator is not configured for this deployment. |