Skip to content

Authentication & x402

Crank has no accounts to create before you start. Authentication is about three things:

  1. Wallet binding — proving which public wallet an action belongs to.
  2. Payment — settling the technology service fee for value-bearing actions via the x402 payment rail.
  3. 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_address argument, never inferred from inside a tool's other arguments.
  • wallet_address is 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:

  1. Quote. Read fee_usd and the accepts payment requirements from the PAYMENT_REQUIRED envelope.
  2. Pay. Construct an x402 payment for that amount in USDC on Solana.
  3. Retry. Call the tool again with the payment_header argument set to your x402 payment payload.
  4. 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_LIMITED error envelope with retry_after_seconds in its details — wait that long and retry.
  • On /mcp/plugin-v1 and /mcp/agent-v1, tools/call additionally answers at the HTTP layer with status 429 and a Retry-After header, 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.