Guides
Connectors
Clavis ships with 11 ready-to-use connectors. To use any connector, register a service with that connector_name, store credentials, and call get_token(). The connector handles all auth logic.
connector_name is the string you pass when registering a service. It must exactly match one of the names listed in each section below (e.g.,
"openai", "brave-search").
OpenAI
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | OpenAI API key. Must start with sk-. Get one at platform.openai.com/api-keys. |
python — register & use
# 1. Register the service import httpx async with httpx.AsyncClient() as http: svc = (await http.post("https://clavisagent.com/v1/services", headers={"Authorization": f"Bearer {jwt}"}, json={"name": "my-openai", "connector_name": "openai"})).json() # 2. Store credentials await http.post(f"https://clavisagent.com/v1/services/{svc['id']}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "sk-..."}}) # 3. Get token in your agent token = await client.get_token("my-openai") # token.access_token = "sk-..." — inject into Authorization: Bearer
Anthropic
Header differs from OpenAI. Anthropic uses
x-api-key, not Authorization: Bearer. Clavis injects the correct header automatically when proxying.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Anthropic API key. Must start with sk-ant-. Get one at console.anthropic.com. |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "sk-ant-..."}}) # Proxy injects x-api-key + anthropic-version headers automatically response = await client.proxy("my-anthropic", "POST", "/v1/messages", body={"model": "claude-sonnet-4-6", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]})
GitHub
Live validation: Clavis calls
GET /user when credentials are first stored to confirm the token is valid.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Personal Access Token (classic: ghp_, fine-grained: github_pat_). Create at github.com/settings/tokens. |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "ghp_..."}}) # List repos via proxy response = await client.proxy("my-github", "GET", "/user/repos", params={"sort": "updated", "per_page": 10})
Stripe
Live validation: Clavis calls
GET /v1/balance when credentials are first stored to verify the key.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Stripe secret key (sk_live_ or sk_test_) or restricted key (rk_live_ / rk_test_). Get one at dashboard.stripe.com/apikeys. |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "sk_test_..."}}) # Create a payment intent via proxy response = await client.proxy("my-stripe", "POST", "/v1/payment_intents", body={"amount": 2000, "currency": "usd"})
Brave Search
Custom header: Brave Search uses
X-Subscription-Token, not Authorization: Bearer. Clavis injects the correct header automatically when proxying.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Brave Search API key. Get one at api.search.brave.com/app/keys. |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "BSA..."}}) # Web search via proxy — X-Subscription-Token injected automatically response = await client.proxy("my-brave", "GET", "/res/v1/web/search", params={"q": "AI agent authentication", "count": 10})
Kalshi
Session token auth: Unlike API key connectors, Kalshi authenticates with email + password and receives a 24-hour session token. Clavis stores the credentials and re-authenticates automatically when the token expires.
Required credentials
| Field | Description |
|---|---|
| emailrequired | Your Kalshi account email address. |
| passwordrequired | Your Kalshi account password. |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"email": "you@example.com", "password": "..."}}) # Token fetched and cached; re-login happens automatically at expiry token = await client.get_token("my-kalshi") response = await client.proxy("my-kalshi", "GET", "/trade-api/v2/markets")
Coinbase Advanced Trade
HMAC signing: Coinbase requires per-request HMAC-SHA256 signatures using a timestamp + method + path. Clavis handles this automatically when proxying — use the proxy endpoint rather than extracting the token directly.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Coinbase API key. Get one at coinbase.com/settings/api. |
| api_secretrequired | Coinbase API secret corresponding to the key above. |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "...", "api_secret": "..."}}) # Use proxy — Clavis signs each request with HMAC-SHA256 response = await client.proxy("my-coinbase", "GET", "/api/v3/brokerage/accounts")
Alpaca Markets
Paper trading by default. Set
environment to "live" in the credential data to target the live trading endpoint. Both domains are allowed in SSRF validation.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Alpaca API key ID. Get one at app.alpaca.markets. |
| api_secretrequired | Alpaca API secret corresponding to the key above. |
| environment | Optional. "paper" (default) or "live". |
python — register & use
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "PKXXXXXXXX", "api_secret": "...", "environment": "paper"}}) # Injects APCA-API-KEY-ID + APCA-API-SECRET-KEY headers automatically response = await client.proxy("my-alpaca", "GET", "/v2/positions")
Kalshi RSA
Per-request signing required. The Kalshi RSA API requires each request to be signed with an RSA-PSS signature. Use
POST /v1/credentials/{name}/headers to get the signed headers for each request, then attach them to your outbound call.
Required credentials
| Field | Description |
|---|---|
| key_idrequired | Your Kalshi API key ID (a UUID). Find it in the Kalshi dashboard under API settings. |
| private_key_pemrequired | RSA private key in PEM format (PKCS#8). Generated alongside your Kalshi API key. |
python — register & get signed headers
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "jwt", "data": {"key_id": "uuid-...", "private_key_pem": "-----BEGIN PRIVATE KEY-----\n..."}}) # Get signed headers for each outbound request r = await http.post("https://clavisagent.com/v1/credentials/my-kalshi-rsa/headers", headers={"Authorization": f"Bearer {jwt}"}, json={"method": "GET", "path": "/trade-api/v2/balance", "body": ""}) # r.json() = {"headers": {"KALSHI-ACCESS-KEY": ..., "KALSHI-ACCESS-TIMESTAMP": ..., "KALSHI-ACCESS-SIGNATURE": ...}}
Coinbase Advanced Trade (JWT)
CDP API JWT auth. Each request requires a fresh ES256-signed JWT (2-minute TTL). Use
POST /v1/credentials/{name}/headers to generate the signed Authorization: Bearer <jwt> header, or use POST /v1/credentials/{name}/ws_headers for Coinbase WebSocket connections.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Full Coinbase CDP API key path: organizations/<org-id>/apiKeys/<key-id>. |
| private_key_pemrequired | EC private key in PEM format (ES256). Generated in the Coinbase Developer Platform. |
python — register & get signed JWT header
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "jwt", "data": {"api_key": "organizations/abc/apiKeys/xyz", "private_key_pem": "-----BEGIN EC PRIVATE KEY-----\n..."}}) # Get a fresh signed JWT for one REST request r = await http.post("https://clavisagent.com/v1/credentials/my-coinbase-jwt/headers", headers={"Authorization": f"Bearer {jwt}"}, json={"method": "GET", "path": "/api/v3/brokerage/accounts", "body": ""}) # r.json() = {"headers": {"Authorization": "Bearer eyJ..."}}
Generic API Key
Generic Bearer-token connector. The built-in
api_key registration targets api.resend.com and injects Authorization: Bearer <key>. Use it for Resend or any compatible REST API at that base URL.
Required credentials
| Field | Description |
|---|---|
| api_keyrequired | Static API key injected as Authorization: Bearer <key>. |
python — register & use (Resend example)
await http.post(f"https://clavisagent.com/v1/services/{svc_id}/credentials", headers={"Authorization": f"Bearer {jwt}"}, json={"token_type": "api_key", "data": {"api_key": "re_..."}}) # Proxy injects Authorization: Bearer re_... automatically response = await client.proxy("my-resend", "POST", "/emails", body={"from": "noreply@example.com", "to": "user@example.com", "subject": "Hello", "text": "Hi!"})