API Reference
Authentication
All endpoints except POST /v1/auth/register and POST /v1/auth/login require a Bearer token in the Authorization header:
Authorization: Bearer eyJ...
Obtain a token by calling POST /v1/auth/login. Tokens expire after 24 hours.
Auth Endpoints
Create a new developer account. Returns the developer profile including the permanent api_key prefixed with cla_.
Request body
| Field | Type | Description |
|---|---|---|
| email* | string | Valid email address. Must be unique. |
| password* | string | Minimum 8 characters. |
$ curl -sX POST https://clavisagent.com/v1/auth/register \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"yourpassword"}'
{
"id": "uuid",
"email": "you@example.com",
"is_active": true,
"created_at": "2026-03-08T00:00:00Z",
"api_key": "cla_..."
}
Authenticate and receive a JWT. Pass this token as Authorization: Bearer <token> on all subsequent requests. Expires in 24 hours.
Request body
| Field | Type | Description |
|---|---|---|
| email* | string | Registered email address. |
| password* | string | Account password. |
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 86400
}
Return the authenticated developer's profile. Useful to verify a token is valid and retrieve your permanent api_key.
{
"id": "uuid",
"email": "you@example.com",
"is_active": true,
"created_at": "2026-03-08T00:00:00Z",
"api_key": "cla_..."
}
Services
A service is a named instance of a connector that holds your credentials and rate limit settings.
Register a new third-party service. The name you choose is how you identify it in get_token() and proxy calls.
Request body
| Field | Type | Description |
|---|---|---|
| name* | string | Your identifier for this service (e.g., "my-openai-prod"). 1โ100 chars. |
| connector_name* | string | Built-in connector to use: openai, anthropic, github, stripe, brave-search, kalshi, or coinbase. |
| display_nameopt | string | Human-friendly display name. |
| descriptionopt | string | Free-text description. |
| rate_limit_rulesopt | array | Custom rate limit rules. Overrides connector defaults. Each rule: {"requests": N, "window_seconds": N}. |
$ curl -sX POST https://clavisagent.com/v1/services \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{"name":"my-openai","connector_name":"openai"}'
{
"id": "a1b2c3d4-...",
"name": "my-openai",
"connector_name": "openai",
"auth_type": "api_key",
"is_active": true,
"rate_limit_rules": [],
"created_at": "2026-03-08T00:00:00Z"
}
List all active services registered by the current developer, ordered by creation date descending.
Get details for a specific service by UUID.
Update service metadata or toggle the active flag. All fields are optional.
Request body
| Field | Type | Description |
|---|---|---|
| display_nameopt | string | New display name. |
| descriptionopt | string | New description. |
| is_activeopt | bool | Set to false to soft-delete; true to reactivate. |
Soft-delete a service (sets is_active = false). The record and its credentials are retained for audit purposes. Use PATCH with is_active: true to reactivate. Returns 204 No Content.
Credentials
Credentials are Fernet-encrypted before storage. The plaintext is never written to disk. See the Connectors guide for required fields per connector.
Encrypt and store credentials for a service. Can only be called once โ use PUT to update.
Request body
| Field | Type | Description |
|---|---|---|
| token_type* | string | One of "api_key", "oauth2", or "jwt". Use "api_key" for all 7 built-in connectors. |
| data* | object | Credential fields. For api_key: {"api_key": "..."}. For oauth2: {"client_id": "...", "client_secret": "..."}. |
$ curl -sX POST https://clavisagent.com/v1/services/a1b2c3d4-.../credentials \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{"token_type":"api_key","data":{"api_key":"sk-..."}}'
$ curl -sX POST https://clavisagent.com/v1/services/a1b2c3d4-.../credentials \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{"token_type":"api_key","data":{"email":"you@example.com","password":"..."}}'
Return credential metadata โ never the plaintext secret or encrypted blob. Useful to check when credentials were created or last used.
{
"id": "uuid",
"service_id": "uuid",
"token_type": "api_key",
"expires_at": null,
"last_used_at": "2026-03-08T10:00:00Z",
"created_at": "2026-03-08T00:00:00Z"
}
Replace credential data. Re-encrypts the new payload, clears the cached access token, and invalidates the Redis token cache. Use this to rotate credentials.
Request body
| Field | Type | Description |
|---|---|---|
| data* | object | New credential fields (same shape as POST). |
Permanently remove stored credentials. Returns 204 No Content.
Tokens
The token endpoints return ready-to-use tokens, handling decryption, caching, refresh, and retries transparently.
Get a valid access token for the named service. Auto-refreshes if expired. Uses Redis cache for <5ms response on cache hit.
name you chose when registering the service (e.g., my-openai) โ not the connector name.
$ curl -s https://clavisagent.com/v1/tokens/my-openai \
-H 'Authorization: Bearer eyJ...'
{
"service_name": "my-openai",
"token_type": "Bearer",
"access_token": "sk-...",
"expires_at": null
}
Response headers
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the rate limit window. |
| X-RateLimit-Remaining | Requests remaining in the current window. |
| X-RateLimit-Reset | Unix timestamp when the window resets. |
Force-invalidate the cached token for a service, triggering a fresh fetch on the next get_token() call. Useful after external credential rotation. Returns 204 No Content.
Proxy
The proxy endpoints forward requests to the upstream service with auth injected and rate limits tracked. Clavis handles signing (e.g., Coinbase HMAC) and injects the correct headers per connector.
Proxy a request. The target path is in the request body.
Request body
| Field | Type | Description |
|---|---|---|
| methodopt | string | HTTP method. Default: "GET". |
| path* | string | Path on the target service (e.g., "/v1/chat/completions"). |
| paramsopt | object | URL query parameters. |
| bodyopt | object | JSON request body. |
| headersopt | object | Extra headers to merge (auth headers take precedence). |
$ curl -sX POST https://clavisagent.com/v1/proxy/my-openai \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{
"method": "POST",
"path": "/v1/chat/completions",
"body": {"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}]}
}'
{
"status_code": 200,
"headers": { "content-type": "application/json", "...": "..." },
"body": { "id": "chatcmpl-...", "choices": [...] }
}
Alternative proxy form โ target path comes from the URL instead of the body. Useful for REST-style integrations.
Request body
| Field | Type | Description |
|---|---|---|
| methodopt | string | HTTP method. Default: "GET". |
| paramsopt | object | URL query parameters. |
| bodyopt | object | JSON request body. |
| headersopt | object | Extra headers. |
$ curl -sX POST \
https://clavisagent.com/v1/proxy/my-openai/v1/chat/completions \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{"method":"POST","body":{"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}]}}'
Error Codes
All errors return a JSON body with a detail field explaining the issue:
{ "detail": "Human-readable explanation with a suggested fix." }
| Status | Meaning |
|---|---|
| 400 | Bad request โ missing or invalid fields. Check the detail message. |
| 401 | Unauthorized โ missing or expired Bearer token. Re-login at POST /v1/auth/login. |
| 403 | Forbidden โ account is inactive. |
| 404 | Not found โ service, credential, or resource doesn't exist. |
| 409 | Conflict โ resource already exists (duplicate service name, duplicate credentials). |
| 422 | Validation error โ field type or constraint violation. |
| 429 | Rate limit exceeded. Check X-RateLimit-Reset and Retry-After headers. |
| 503 | Token unavailable โ connector could not authenticate. Check stored credentials. |