API Keys
API keys let you call any profile-scoped Ethos endpoint without a browser session. You sign a one-time SIWE message with your wallet, receive a key, and include it in the X-Ethos-Api-Key header on every request.
Prerequisites: an Ethos profile linked to your wallet, and API key access enabled for your account.
Quick start
Section titled “Quick start”Create a key, send an XP tip, revoke the key — all in one script. Or try the interactive playground to run each step in your browser.
import { privateKeyToAccount } from "viem/accounts";import { createSiweMessage } from "viem/siwe";
const API = "https://api.ethos.network/api/v2";const CLIENT = "my-bot@1.0.0"; // identifies your app
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
// --- 1. Create API key ---
const message = createSiweMessage({ domain: "api.ethos.network", address: account.address, statement: "Create Ethos API key", uri: "https://api.ethos.network", version: "1", chainId: 8453, // Base nonce: crypto.randomUUID().replaceAll("-", ""), issuedAt: new Date(), expirationTime: new Date(Date.now() + 10 * 60 * 1000), // must be within 10 min});
const signature = await account.signMessage({ message });
const keyResp = await fetch(`${API}/api-keys`, { method: "POST", headers: { "Content-Type": "application/json", "X-Ethos-Client": CLIENT }, body: JSON.stringify({ address: account.address, message, signature, name: "my-bot", }),});
if (!keyResp.ok) throw new Error(`Create key failed: ${await keyResp.text()}`);
const { id: keyId, token } = await keyResp.json();console.log("Key created:", keyId);
// --- 2. Send XP tip ---
const tipResp = await fetch(`${API}/xp/tip`, { method: "POST", headers: { "Content-Type": "application/json", "X-Ethos-Api-Key": token, "X-Ethos-Client": CLIENT, }, body: JSON.stringify({ receiverUserkey: "profileId:1", amount: 5, message: "5 XP, 10 lines of code — developers.ethos.network", }),});
if (!tipResp.ok) throw new Error(`Tip failed: ${await tipResp.text()}`);
const tip = await tipResp.json();console.log(`Tip #${tip.tipId} sent. Balance: ${tip.senderNewBalance} XP`);
// --- 3. Revoke key ---
const revokeResp = await fetch(`${API}/api-keys/${keyId}`, { method: "DELETE", headers: { "X-Ethos-Api-Key": token, "X-Ethos-Client": CLIENT },});
if (!revokeResp.ok) throw new Error(`Revoke failed: ${await revokeResp.text()}`);console.log("Key revoked");from datetime import datetime, timedelta, timezonefrom eth_account import Accountfrom eth_account.messages import encode_defunctfrom siwe import SiweMessageimport requests, secrets
API = "https://api.ethos.network/api/v2"CLIENT = "my-bot@1.0.0" # identifies your app
account = Account.from_key("0xYOUR_PRIVATE_KEY")now = datetime.now(timezone.utc)
# --- 1. Create API key ---
msg = SiweMessage( domain="api.ethos.network", address=account.address, statement="Create Ethos API key", uri="https://api.ethos.network", version="1", chain_id=8453, # Base nonce=secrets.token_hex(16), issued_at=now.isoformat(), expiration_time=(now + timedelta(minutes=10)).isoformat(), # must be within 10 min)message_text = msg.prepare_message()signature = "0x" + account.sign_message( encode_defunct(text=message_text)).signature.hex()
key_resp = requests.post(f"{API}/api-keys", headers={"X-Ethos-Client": CLIENT}, json={ "address": account.address, "message": message_text, "signature": signature, "name": "my-bot", },)key_resp.raise_for_status()
data = key_resp.json()token, key_id = data["token"], data["id"]print(f"Key created: {key_id}")
# --- 2. Send XP tip ---
tip_resp = requests.post(f"{API}/xp/tip", headers={"X-Ethos-Api-Key": token, "X-Ethos-Client": CLIENT}, json={ "receiverUserkey": "profileId:1", "amount": 5, "message": "5 XP, 10 lines of code — developers.ethos.network", },)tip_resp.raise_for_status()
tip = tip_resp.json()print(f"Tip #{tip['tipId']} sent. Balance: {tip['senderNewBalance']} XP")
# --- 3. Revoke key ---
revoke_resp = requests.delete( f"{API}/api-keys/{key_id}", headers={"X-Ethos-Api-Key": token, "X-Ethos-Client": CLIENT},)revoke_resp.raise_for_status()print("Key revoked")PRIVATE_KEY="0xYOUR_PRIVATE_KEY"ADDRESS=$(cast wallet address "$PRIVATE_KEY")API="https://api.ethos.network/api/v2"CLIENT="my-bot@1.0.0"NONCE=$(openssl rand -hex 16)NOW=$(date -u '+%Y-%m-%dT%H:%M:%SZ')# macOS: date -u -v+10M Linux: date -u -d "+10 min"EXP=$(date -u -v+10M '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \ || date -u -d "+10 min" '+%Y-%m-%dT%H:%M:%SZ')
# --- 1. Create API key ---
MESSAGE="api.ethos.network wants you to sign in with your Ethereum account:${ADDRESS}
Create Ethos API key
URI: https://api.ethos.networkVersion: 1Chain ID: 8453Nonce: ${NONCE}Issued At: ${NOW}Expiration Time: ${EXP}"
SIGNATURE=$(cast wallet sign --private-key "$PRIVATE_KEY" "$MESSAGE")
KEY_JSON=$(curl -s -X POST "$API/api-keys" \ -H "Content-Type: application/json" \ -H "X-Ethos-Client: $CLIENT" \ -d "{ \"address\": \"${ADDRESS}\", \"message\": $(printf '%s' "$MESSAGE" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))"), \"signature\": \"${SIGNATURE}\", \"name\": \"my-bot\" }")
TOKEN=$(echo "$KEY_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")KEY_ID=$(echo "$KEY_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")echo "Key created: $KEY_ID"
# --- 2. Send XP tip ---
curl -s -X POST "$API/xp/tip" \ -H "Content-Type: application/json" \ -H "X-Ethos-Api-Key: $TOKEN" \ -H "X-Ethos-Client: $CLIENT" \ -d '{ "receiverUserkey": "profileId:1", "amount": 5, "message": "5 XP, 10 lines of code — developers.ethos.network" }'
# --- 3. Revoke key ---
curl -s -X DELETE "$API/api-keys/$KEY_ID" \ -H "X-Ethos-Api-Key: $TOKEN" \ -H "X-Ethos-Client: $CLIENT"echo "Key revoked"Creating a key
Section titled “Creating a key”Key creation uses a SIWE (Sign-In with Ethereum) signature to prove wallet ownership. The server verifies the signature and returns a JWT-based API key.
SIWE message requirements
Section titled “SIWE message requirements”| Field | Value | Notes |
|---|---|---|
domain |
api.ethos.network |
Must match exactly |
chainId |
8453 |
Base mainnet |
expirationTime |
Within 10 minutes | Required — messages without it are rejected |
nonce |
Random hex string | Single-use — the server rejects replayed nonces. Generate a fresh one for every request. |
uri |
https://api.ethos.network |
|
version |
1 |
Request: POST /api/v2/api-keys
Section titled “Request: POST /api/v2/api-keys”| Field | Type | Required | Description |
|---|---|---|---|
address |
string | Yes | Your Ethereum address (0x-prefixed, checksummed) |
message |
string | Yes | The SIWE message you signed |
signature |
string | Yes | ECDSA signature (0x-prefixed, 132 hex chars) |
name |
string | Yes | Label for this key (1-100 chars) |
expiresAt |
string | No | ISO 8601 datetime. Default: 90 days. Max: 365 days. |
Response
Section titled “Response”{ "id": "cm...", "token": "ethos_eyJhbGci...", "name": "my-bot", "expiresAt": "2026-06-25T00:00:00.000Z"}Authenticating requests
Section titled “Authenticating requests”Include the key in the X-Ethos-Api-Key header on every request:
X-Ethos-Api-Key: ethos_eyJhbGci...X-Ethos-Client: my-bot@1.0.0The key authenticates as the Ethos profile that created it. All profile-scoped endpoints (tips, reviews, votes, vouches) work the same way they do with browser session auth.
Revoking a key
Section titled “Revoking a key”DELETE /api/v2/api-keys/{id}Pass the id returned when you created the key. Revocation takes effect immediately — subsequent requests with the revoked key return 401 Unauthorized.
You can revoke a key using the key itself (as shown in the quick start) or with browser session auth.
Reference
Section titled “Reference”Key lifecycle
Section titled “Key lifecycle”| Property | Value |
|---|---|
| Default expiry | 90 days |
| Maximum expiry | 365 days |
| Active keys per profile | 25 |
| Usage tracking | lastUsedAt updated per request (throttled to once per minute) |
Endpoints
Section titled “Endpoints”| Method | Path | Auth |
|---|---|---|
POST |
/api/v2/api-keys |
None (SIWE signature in body) |
GET |
/api/v2/api-keys |
API key or browser session |
DELETE |
/api/v2/api-keys/{id} |
API key or browser session |
Error codes
Section titled “Error codes”| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_AMOUNT |
XP tip amount must be a positive integer |
| 400 | CANNOT_TIP_SELF |
Sender and receiver are the same profile |
| 400 | INSUFFICIENT_XP |
Not enough XP in your balance |
| 401 | — | Invalid, expired, or revoked API key |
| 403 | — | API key access not enabled for this profile |
| 404 | RECEIVER_NOT_FOUND |
No Ethos user matches the receiver userkey |
| 404 | KEY_NOT_FOUND |
Key ID not found or not owned by you |