How authentication works
Every request to the Veto API must include a valid API key as a Bearer token in the Authorization header:
Authorization: Bearer veto_<32 hex chars>
The SDK handles this for you when you pass your key to VetoClient. If you’re making raw HTTP requests, include the header yourself.
Veto API keys follow this format:
For example: veto_a3f8b2c1d4e5f6071829304a5b6c7d8e
The first 12 characters (the prefix) are stored in the dashboard for identification. The full key is only available at the time of creation.
Create an API key
You can create API keys through the dashboard or directly via the API.
Via the dashboard
- Sign in at app.veto.tools.
- Navigate to Settings → API keys.
- Click New API key, give it a name, and select the scopes you need.
- Copy the key shown — it is displayed once and cannot be retrieved again.
Via the API
Send a POST request to /v1/api-keys with a name and the scopes you want to grant.curl -X POST https://api.veto.tools/v1/api-keys \
-H "Authorization: Bearer $VETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "production",
"scopes": ["admin"]
}'
The response includes the raw key in the key field:{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "production",
"prefix": "veto_a3f8b2",
"scopes": ["admin"],
"expiresAt": null,
"createdAt": "2025-01-15T10:00:00.000Z",
"key": "veto_a3f8b2c1d4e5f6071829304a5b6c7d8e"
}
The key field is returned once at creation and never shown again. Store it immediately in a secrets manager or environment variable.
Use the key in the SDK
Pass the key to VetoClient via the apiKey option. Load it from an environment variable, not from source code.
import { VetoClient } from "@useveto/node";
const veto = new VetoClient({ apiKey: process.env.VETO_API_KEY! });
Use the key in direct HTTP requests
If you’re calling the API directly without the SDK, include the key as a Bearer token:
curl https://api.veto.tools/v1/agents \
-H "Authorization: Bearer $VETO_API_KEY"
API key scopes
Scopes control what an API key is allowed to do. Currently, one scope is available:
| Scope | Description |
|---|
admin | Full access — required for creating and deleting agents, policies, and API keys. |
read | Read-only access — can call POST /v1/authorize, and all GET endpoints for agents, policies, audit logs, and API keys. Cannot create or delete resources. |
When creating an API key for a production service, grant only the scopes it needs.
Error codes
| Status | Code | Description |
|---|
401 | UNAUTHORIZED | The API key is missing, invalid, or expired. Check that the key is correct and has not been revoked. |
When the SDK receives a 401, it throws an UnauthorizedError:
import { VetoClient, UnauthorizedError } from "@useveto/node";
const veto = new VetoClient({ apiKey: process.env.VETO_API_KEY! });
try {
await veto.listAgents();
} catch (error) {
if (error instanceof UnauthorizedError) {
console.error("Invalid or expired API key");
}
}
Security
Keep your API keys secret. Do not commit them to source control, include them in client-side code, or log them to output. If a key is compromised, revoke it immediately from the dashboard or via DELETE /v1/api-keys/:id.
Store API keys in environment variables or a secrets manager such as AWS Secrets Manager, HashiCorp Vault, or Doppler. Rotate keys periodically and issue separate keys for each environment.