Get a blockchain API key with a wallet signature (SIWE)
Sign a message locally with your wallet and get an API key plus 30,000,000 free CU, no payment first. 3 BlockVectra HTTP requests and a local wallet signature in 4 steps, no browser, for developers and AI agents.
A wallet signature is enough to get a BlockVectra API key and 30,000,000 free CU; no payment is needed first. Developers and AI agents complete 4 steps without a browser: 3 HTTP requests to BlockVectra and a local wallet signature. Request a SIWE challenge, sign it locally with your Ethereum wallet, log in, then POST /keys. The first login creates the account. Start with the first call (Checked ):
BASE=https://console-api.blockvectra.com/v1
curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
-d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}"The same flow serves autonomous AI agents, CI pipelines, and scripts running without a browser. It uses an EIP-4361 / SIWE message signed with personal_sign (EIP-191).
Key security
Never paste private keys, session tokens, or API keys into conversations with AI or pass them as MCP tool arguments.
Before signing up, you can try the keyless public endpoint https://api.blockvectra.com/v1/robinhood_mainnet/public first (on Robinhood Chain this endpoint allows wallet JSON-RPC methods only; the allowed methods differ per chain, so check public.methods in list_chains or GET /v1/chains; the Data API requires a key); sign up for an account if the quota is not enough.
Workflow overview
The programmatic registration and key provisioning flow consists of four steps:
- Request challenge: Send a request to
POST /auth/siwe/challengeto obtain a server-generated sign-in message. - Sign message: Sign the exact EIP-4361 message with an Ethereum EOA wallet using
personal_sign(EIP-191). - Log in / open account: Submit the verbatim message and signature to
POST /auth/siwe/login. On the first sign-in for a wallet, an account is created automatically (account_created: true). New accounts get 30,000,000 CU on sign-up — no credit card. - Create API key: Use the session token to call
POST /keysand create an API key.
Shortest curl sequence
3 HTTP requests to BlockVectra plus local wallet signing (4 steps), followed by a separate authenticated HTTP request to verify the key with eth_blockNumber. ADDR is the wallet address (0x...) and PK its private key, loaded from a secrets manager; this needs curl, jq, and Foundry cast. A new key takes a few seconds to become active, so retry a 401 invalid_api_key after a short wait (the full examples below retry automatically).
BASE=https://console-api.blockvectra.com/v1
# 1. Challenge: the server returns the exact message to sign
MSG=$(curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
-d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}" | jq -r .message)
# 2. Sign it with EIP-191 personal_sign
SIG=$(cast wallet sign --private-key "$PK" "$MSG")
# 3. Login: the first sign-in for a wallet creates the account
TOKEN=$(jq -n --arg m "$MSG" --arg s "$SIG" '{message: $m, signature: $s}' |
curl -s "$BASE/auth/siwe/login" -H 'Content-Type: application/json' -d @- | jq -r .session.token)
# 4. Create the API key (the secret is returned only once)
KEY=$(curl -s "$BASE/keys" -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"label":"agent-key"}' | jq -r .api_key)
# 5. Call JSON-RPC with the key in the x-api-key header
RESP=$(curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" -H "x-api-key: $KEY" -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' \
-w '\n%{http_code}') &&
printf '%s' "${RESP%$'\n'*}" | jq -es --arg status "${RESP##*$'\n'}" '
if length == 1 and (.[0] | type) == "object" and ($status | test("^2[0-9][0-9]\\z")) and
(.[0] | .jsonrpc == "2.0" and (.id | type) == "number" and .id == 1 and has("error") == false and
(.result | type) == "string" and (.result | test("^0x(0|[1-9a-fA-F][0-9a-fA-F]*)\\z")))
then .[0] else empty end'Complete runnable examples
Start here: use a local Ethereum EOA signer, create a key, and verify it with eth_blockNumber. For the Bash example, you need curl, jq, and Foundry cast. Keep wallet credentials in your local signing environment.
Complete starter template: blockvectra/agent-quickstart
The following scripts read the wallet credentials, complete the challenge and login sequence, provision an API key, export or print export BLOCKVECTRA_API_KEY=... for environment configuration, and send a verification eth_blockNumber request:
New keys take a few seconds to become active; these examples retry automatically.
BASE=https://console-api.blockvectra.com/v1
# $ADDR: Ethereum wallet address (0x...)
# $PK: wallet private key, loaded from a secrets manager (never hardcode in scripts)
# 1. Fetch server-generated SIWE message (omit Origin header)
curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
-d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}" > challenge.json
jq -r .message challenge.json > msg.txt
# 2. Sign the exact message with EIP-191 personal_sign
SIG=$(cast wallet sign --private-key "$PK" "$(cat msg.txt)")
# 3. Submit verbatim message and signature (omit Origin header) to log in (ref is optional)
jq -n --rawfile m msg.txt --arg s "$SIG" '{message: ($m | rtrimstr("\n")), signature: $s, ref: "docs-signup"}' |
curl -s "$BASE/auth/siwe/login" -H 'Content-Type: application/json' -d @- > session.json
TOKEN=$(jq -r .session.token session.json)
# 4. Create an API key (the secret is returned only once)
KEY_RESP=$(curl -s "$BASE/keys" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"label":"agent-key"}')
export BLOCKVECTRA_API_KEY=$(echo "$KEY_RESP" | jq -r .api_key)
# 5. Call JSON-RPC with the key in the x-api-key request header
RPC_DEADLINE=$((SECONDS + 10))
while true; do
RPC_TIMEOUT=$((RPC_DEADLINE - SECONDS))
if ((RPC_TIMEOUT <= 0)); then
printf '%s' "${RPC_BODY:-}"
echo "RPC verification failed: retry budget exhausted" >&2
exit 1
fi
RPC_RESP=$(curl -s --max-time "$RPC_TIMEOUT" -w '\n%{http_code}' "https://api.blockvectra.com/v1/robinhood_mainnet" \
-H "x-api-key: $BLOCKVECTRA_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}') || { rc=$?; echo "request failed (curl exit $rc)" >&2; exit $rc; }
RPC_STATUS=${RPC_RESP##*$'\n'}
RPC_BODY=${RPC_RESP%$'\n'*}
if ((SECONDS + 2 < RPC_DEADLINE)) &&
printf '%s' "$RPC_BODY" | jq -es --arg status "$RPC_STATUS" '
length == 1 and (.[0] | type) == "object" and (
($status == "401" and .[0].error.data.reason == "invalid_api_key") or
($status == "503" and .[0].error.code == -32021))
' >/dev/null 2>&1; then
sleep 2
continue
fi
printf '%s' "$RPC_BODY"
printf '%s' "$RPC_BODY" | jq -es --arg status "$RPC_STATUS" '
length == 1 and (.[0] | type) == "object" and ($status | test("^2[0-9][0-9]\\z")) and
(.[0] | .jsonrpc == "2.0" and (.id | type) == "number" and .id == 1 and has("error") == false and
(.result | type) == "string" and (.result | test("^0x(0|[1-9a-fA-F][0-9a-fA-F]*)\\z")))
' >/dev/null 2>&1 || { echo "RPC verification failed (HTTP $RPC_STATUS)" >&2; exit 1; }
break
doneBase URL and programmatic mode
All authentication and key management endpoints use the official base URL:
https://console-api.blockvectra.com/v1Omitting the Origin header
Programmatic requests operate in programmatic mode:
- Both the challenge (
POST /auth/siwe/challenge) and login (POST /auth/siwe/login) requests must not include theOriginheader (curland standard HTTP clients omit this header by default; do not add it manually). - If an
Originheader is sent but is not a configured web console domain (including empty string ornull), the challenge request returns HTTP 400invalid_request. - If the mode at login does not match the challenge mode (for instance, requesting a programmatic challenge without
Originand then submitting login with anOriginheader, or vice versa), the login request returns HTTP 400siwe_invalidwithreason: domain_mismatch.
Message integrity and wallet requirements
- Verbatim signature and submission: Clients must sign and submit the message text exactly as returned by the challenge endpoint. Do not alter whitespace, domain, chain ID, or any fields. Any modification results in HTTP 400
siwe_invalidwithreason: signature. - Supported wallets: Ethereum mainnet (Chain ID 1) Externally Owned Accounts (EOA). The signature must be a 65-byte ECDSA signature (
personal_sign). Contract wallets (EIP-1271) and smart accounts are not supported. - Challenge validity: Each challenge nonce is single-use and expires after 5 minutes.
Request body and sign-up attribution (optional)
The POST /auth/siwe/login request body accepts required authentication parameters and optional signup attribution fields:
- Required fields:
message: The complete SIWE message string obtained from the challenge endpoint.signature: The 65-byte hexadecimal signature (0xprefixed) produced by signing the EIP-4361messagewithpersonal_sign(EIP-191) from an Ethereum wallet.
- Optional attribution fields (saved only once when a new account is created; ignored on subsequent logins):
ref: A lowercase channel token matching^[a-z0-9._-]{1,64}$(lowercase ASCII letters, digits,.,_,-, 1–64 characters). For example, autonomous agents can set this to their framework or runtime identifier (e.g.my-agent.v1). Non-compliant values (including uppercase letters, empty strings, excess length, or unsupported characters) return HTTP 400invalid_requestwithout case folding and prevent account creation; omit or passnullwhen not applicable.referrer: A source URL or hostname string. Omission ornullis accepted as not provided; blank strings or strings without a usable hostname are discarded. Only non-null, non-string values return HTTP 400invalid_request.
Sending undefined fields such as signup_method returns HTTP 400 invalid_request.
Session tokens and API keys
Session token lifecycle
- Format:
rgs_followed by 64 lowercase hexadecimal characters. - Validity: Absolute lifetime of 7 days; expires automatically after 24 hours of idle time.
- No refresh token: When a session token expires, initiate a new challenge and login flow.
- Header: Pass the session token in the
Authorization: Bearer rgs_...request header.
API key creation
- Call
POST /keyswith the session token to create an API key (rgw_followed by 64 hexadecimal characters). - The default policy allows at most 20 unrevoked, unexpired (
active+disabled) keys per account. A key counts only if it is unrevoked andexpires_atisnullor strictly later than the current time; expired keys do not count. Exceeding the configured cap returns HTTP 409key_limit_reachedwitherror.reason: active_keysand the configured maximum inerror.limit; revoke a key first. The cap applies across all the account's identities, sessions, and chains. The default rolling-24-hour creation limit is also 20; exceeding it returns HTTP 429rate_limitedwitherror.reason: daily_creationsandRetry-After: 3600. - Within the creation quota checks, the live-key cap is checked before the rolling-24-hour creation limit: if both are reached, creation returns the active-key HTTP 409, not the daily HTTP 429. Rotation requires an enabled, unrevoked, unexpired target key; it does not increase the live-key count but still uses the daily creation quota. Revoking or expiring a key does not remove its creation from the rolling-24-hour count.
- Optional cap and expiry: you can provide
cu_cap(lifetime CU cap for the key, which is a soft cap) and expiry (expires_in_secsorexpires_at, up to the maximum days allowed by key policy); once expired or the cap is exhausted, the server returns 403 (JSON-RPC-32025, reasonkey_expiredorkey_cap_exhausted). - The secret
api_keyis returned only once upon creation. Store it securely immediately in your secrets manager or environment variables. - One API key works across all supported chains on JSON-RPC and the Data API.
Lost your session or API key?
In BlockVectra, an agent's account identity is bound to the Ethereum wallet address used during sign-up. If your session token expires or an API key is lost or leaked, you can recover full control using only that wallet:
- Re-authenticate with the same wallet: Request a challenge, sign it with the same wallet, and submit the login request (
POST /auth/siwe/login). The server verifies the signature, logs into the existing account withaccount_created: false, and issues a new session token. - Create a new API key: With the new session token, call
POST /keyswith{"label": "..."}and theAuthorization: Bearer <token>header. The endpoint returns HTTP 201 with the created key details inkeyand the one-time secret inapi_key. Save this key immediately in your environment variables or secrets manager. - List all keys for the account:
- Endpoint:
GET /keys - Header:
Authorization: Bearer <token> - Query parameter: optional
include_revoked=true(whentrue, includes revoked keys; defaults to active/disabled keys only). - Response: HTTP 200 with JSON
{"items": [...]}. Each element in theitemsarray includes:key_id: unique key identifier (string)label: key label (string ornull)status: status ("active","disabled", or"revoked")created_at: creation timestamp (ISO 8601 string)revoked_at: revocation timestamp (string, ornullif not revoked)
- Endpoint:
- Revoke unused or compromised keys:
- Endpoint:
POST /keys/{key_id}/revoke(note: usesPOSTwith the targetkey_idin the path; empty request body) - Header:
Authorization: Bearer <token> - Behavior: idempotent; keys with
activeordisabledstatus can both be revoked. If already revoked, it returns HTTP 200 unchanged. After revocation, requests using that key are rejected. - Response: HTTP 200 returning the revoked key object (fields match the key object above, with
status: "revoked"and a timestamp inrevoked_at).
- Endpoint:
Key and secret security
Store wallet private keys and API keys in environment variables or a secrets manager. Never commit them to code repositories, write them to logs, or paste them into AI chat conversations.
Security recommendations
- Use short-term keys and revoke when done: For automated or ephemeral tasks, create short-lived keys with
expires_in_secsand revoke them immediately viaPOST /keys/{key_id}/revokeonce work is complete.
Sign-up rate limits (signup_rate_limited)
Account creation is subject to sign-up rate limits. The per-IP token bucket has capacity for 100 accounts and refills at 100 accounts/hour per IPv4 address or IPv6 /64 prefix, shared by SIWE and OAuth signup:
- When exceeding sign-up limits,
POST /auth/siwe/loginreturns HTTP 429signup_rate_limitedwith aRetry-Afterheader indicating the number of seconds to wait. - The
reasonfield distinguishes the limit scope:per_ip: the registration budget for the requesting IP prefix has been exhausted.global: the aggregate platform sign-up limit has been exhausted.
- Sign-up rate limits only evaluate new account registrations. Existing accounts logging in are not blocked by sign-up rate limits.
FAQ
Do I need to pay or top up before I get a key?
No. The first wallet login creates the account and grants 30,000,000 CU. Use the session token from login to create the key. Up to the first top-up, the account is limited to 25 calls per second; see what the Free Plan covers.
Does it need a browser, a password, or gas?
No browser is needed. The HTTP requests use plain HTTPS JSON without an Origin header; sign the message locally in your own wallet environment. There is no password; the wallet signature is the credential. Signing is off-chain, so it costs no gas and sends no transaction. The wallet must be an Ethereum EOA; contract wallets (EIP-1271) are not supported.
What if I lose the API key?
The secret is shown only once and cannot be retrieved again. Log in again with the same wallet to get a new session token, create a new key, and revoke the old one; see Lost your session or API key.
Related resources
- Read the AI agents integration guide to learn about the keyless MCP server and machine-readable context files.
- Review Quickstart for multi-language client examples.
- Inspect the Error reference for full error codes, reasons, and automated recovery actions.
Next steps
- Send your first JSON-RPC or Data API call with
x-api-key: $BLOCKVECTRA_API_KEY. - Check account balance and limits using
GET /v1/account. - Follow the Agent programmatic top-up guide to maintain balance.
Last updated:
Coinbase AgentKit
Use BlockVectra as the Base RPC provider for Coinbase AgentKit: point ViemWalletProvider's viem client at the keyless public endpoint, then add a key.
Stablecoin Payments
Build a payment receiver and polling cursor. Verify token contracts, recipients and integer amounts, deduplicate events and reconcile missing or replaced blocks.