Authentication
Cloven supports two distinct authentication paths. They cover every deployment shape we have seen: humans clicking through a console, server-side agents pulling fresh context, and fully autonomous agents that no human ever logs into.
Mode 1 — Bearer API keys (credit-balance path)
A user-issued API key tied to a Supabase account and a prepaid credit balance. Use this when there is a human owner, when you want a dashboard with usage charts and key rotation, and when you want predictable cost from bulk credit packs.
Issuance
Open /console, claim your anonymous session with magic link or wallet, and click "New key". The key is shown exactly once, prefixed with cv_, then hashed with SHA-256 server-side. Cloven stores only the hash. If you lose the key, you must revoke and re-issue.
cv_<32 bytes of base62>The first 16 characters form the public keyId — safe to log. The rest is the secret. Cloven never displays the full key again after issuance.
Sending the key
All REST and HTTP MCP endpoints accept a standard Bearer header:
GET /v1/fresh?pack=crypto HTTP/1.1
Host: api.cloven.cloud
Authorization: Bearer cv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFor stdio MCP (Claude Desktop, Cursor), put the key in the env block of your claude_desktop_config.json:
{
"mcpServers": {
"cloven": {
"command": "npx",
"args": ["-y", "@cloven/mcp"],
"env": { "CLOVEN_API_KEY": "cv_xxx" }
}
}
}The SDK reads the same env var by default, or accepts apiKey as a constructor argument.
Validation flow
On every authenticated request the middleware:
- Extracts the Bearer token, hashes it with SHA-256.
- Looks up the hash in the
api_keystable (RLS-bypassing service-role read). - Checks
revoked_atis null. - Returns an
ApiKeyContextwithkeyId,userId,tier,creditBalance, and the list of pack ids the key is subscribed to. - Hands off to the rate-limiter (free-tier: 100 calls/day sliding window in Redis) then to the credit debit gate (paid calls: decrements
credit_balancevia thedebit_creditsPostgres fn).
Invalid bearer → 401 invalid_token. Revoked key → 401 key_revoked. Quota exhausted → 429 quota_exhausted with Retry-After header. Insufficient credits → 402 insufficient_credits.
Mode 2 — x402 anonymous (agent-to-agent path)
Use this when an autonomous agent needs context and no human is in the loop to provision a key. The agent signs a USDG transfer on Robinhood Chain for the per-call price; Cloven verifies the transaction and serves the response. No account, no dashboard, no monthly bill.
Flow at a glance
- Agent calls
GET /v1/fresh?pack=cryptowith no auth header. - Cloven responds
402 Payment RequiredwithPaymentRequirements(network, asset, recipient, amount, validUntil, nonce). - Agent signs a USDG
transferon Robinhood Chain for the quoted amount. - Agent retries the call with
x-402-payment: <base64-encoded payment proof>. - Cloven verifies the tx on-chain, caches the tx hash for 24h idempotency, and returns the
MindResponse.
The wallet needs USDG for the payment and a small amount of ETH for gas — ETH is Robinhood Chain's native token, not USDG.
This is a Cloven-native on-chain-receipt scheme: your agent broadcasts its own transfer and Cloven self-verifies the receipt. There is no hosted facilitator and no gasless settlement path today.
Full wire format and verification rules: x402 protocol guide.
The SDK handles this dance automatically when constructed with a viem WalletClient instead of an API key — see the SDK x402 mode page.
Mode 3 — SSE token (subscription-only)
The EventSource browser API cannot set custom request headers. SSE subscriptions therefore accept the API key as a token query parameter:
GET /v1/subscribe?pack=crypto&token=cv_xxxThe token is validated identically to a Bearer header (same hash, same RLS, same rate-limit consume). Use the same value you would pass as Authorization: Bearer …. Treat the URL as secret; SSE tokens leak through server logs and HTTP proxies if not handled carefully.
x402 is not currently supported on SSE because we cannot prompt mid-stream for a fresh payment.
Credit deposits via USDG on Robinhood Chain
To fund a key's credit balance, open /console/credits in the console and select a pack (Starter / Hobby / Pro / Team). The UI creates a deposit intent and presents:
- The exact USDG amount to send and the Cloven treasury address on Robinhood Chain.
- A QR code encoding the EIP-681 payment URI (chain id
4663, USDG contract0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168) for wallet-app scanning. - An expires-in countdown (30-minute window).
Send the USDG transfer from any wallet configured for Robinhood Chain. Once you have a tx hash, paste it into the "Submit tx hash" field for an immediate fast-path verify — or wait up to 60 seconds for the background cron to pick it up automatically.
Adding Robinhood Chain to your wallet
Robinhood Chain is an Arbitrum Orbit L2 and is not preloaded in most wallets. Add it manually:
Network name Robinhood Chain
Chain ID 4663
RPC URL https://rpc.mainnet.chain.robinhood.com
Currency ETH
Explorer https://robinhoodchain.blockscout.comThen add USDG as a custom token at 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 (6 decimals). The testnet chain id is 46630 if you're wiring against a staging deployment.
On verification the deposits row flips to status = verified and your api_keys.credit_balance is incremented atomically. Credits are shared across all your non-revoked keys.
Deposits that receive no matching on-chain transfer within 30 minutes flip to status = expired. No charge applies. Re-open /console/credits to start a new deposit.
Tier-gated pack access
A key's packIds array determines which packs it can call. Free tier is restricted to ["crypto"]. Keys with a credit balance unlock every registered pack. Calling ?pack=ai from a free-tier key with no credit balance returns:
{
"error": {
"code": "pack_access_denied",
"message": "your key does not have access to pack 'ai'; buy a credit pack to unlock all packs",
"requestId": "req_abc123"
}
}Pack access is gated on credit balance, not a separate subscription toggle.
Credit balance and revocation
Revoking a key does not destroy its remaining credits — the credits stay on the row. If you re-issue a replacement key, transfer the balance manually via ops@cloven.cloud or buy a new pack on the replacement key.
Rotation + revocation
Revoke a key from /console. Revoked keys are rejected instantly (Redis cache invalidates within 60 seconds; Postgres lookup catches the rest). Issue a replacement before revoking if you care about uptime. Keys cannot be edited or "rotated" — the only safe rotation pattern is issue-new, deploy, revoke-old.