All API errors return a JSON body with this shape:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message"
}
}
HTTP status codes
| Status | Code | Meaning |
|---|
400 | VALIDATION_ERROR | The request body or query parameters are invalid. |
401 | UNAUTHORIZED | The API key is missing, invalid, or has been revoked. |
401 | API_KEY_EXPIRED | The API key has passed its expiry date. |
403 | INSUFFICIENT_SCOPE | The API key does not have the required scope for this operation. |
404 | AGENT_NOT_FOUND | The agent ID does not exist in your workspace. |
404 | POLICY_NOT_FOUND | The policy ID does not exist in your workspace. |
404 | API_KEY_NOT_FOUND | The API key ID does not exist in your workspace. |
429 | RATE_LIMITED | You have exceeded the rate limit. Check the Retry-After header. |
500 | INTERNAL_ERROR | An unexpected server error occurred. |
POST /v1/authorize always returns 200, even when a request is denied. The authorization decision is in the allowed and outcome fields of the response body. HTTP errors from /v1/authorize indicate authentication or server failures only.
SDK error classes
The Veto Node.js SDK surfaces API errors as typed exceptions.
| Class | Status | Extra fields |
|---|
VetoError | any | code, statusCode — base class for all errors |
UnauthorizedError | 401 | Extends VetoError with code: "UNAUTHORIZED" |
RateLimitError | 429 | Extends VetoError; adds retryAfterMs (milliseconds to wait) |
Handling errors in TypeScript
import { VetoClient, VetoError, UnauthorizedError, RateLimitError } from "@useveto/node";
const veto = new VetoClient({ apiKey: process.env.VETO_API_KEY! });
try {
const result = await veto.authorize(
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"file.write",
{ path: "/home/user/doc.txt" },
);
if (!result.allowed) {
console.log("Action denied:", result.reason);
}
} catch (err) {
if (err instanceof UnauthorizedError) {
// 401 — invalid or expired API key
console.error("Check your VETO_API_KEY environment variable.");
} else if (err instanceof RateLimitError) {
// 429 — back off and retry
const waitMs = err.retryAfterMs;
console.log(`Rate limited. Retry in ${waitMs}ms.`);
await new Promise((resolve) => setTimeout(resolve, waitMs));
} else if (err instanceof VetoError) {
console.error(`API error ${err.statusCode}: ${err.code} — ${err.message}`);
} else {
throw err;
}
}