Skip to main content

Base URL

All API endpoints are served from the PassAgent web application:
https://passagent.ai/api
For local development:
http://localhost:3000/api

Authentication

Most endpoints require authentication via Supabase JWT. The token can be provided in two ways:

CSRF protection

All mutation endpoints (POST, PATCH, DELETE) require a valid CSRF token. Obtain a token from the CSRF endpoint and include it in subsequent requests:
// 1. Get CSRF token
const res = await fetch('/api/auth/csrf-token')
const { csrfToken } = await res.json()

// 2. Include in mutation requests
await fetch('/api/passwords', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-csrf-token': csrfToken,
  },
  body: JSON.stringify({ ... }),
})
Requests to mutation endpoints without a valid CSRF token will receive a 403 Forbidden response.

Rate limiting

Sensitive endpoints enforce rate limits to prevent abuse:
Endpoint categoryLimitWindow
Authentication10 requests15 minutes
Password reset tasks5 requests5 minutes
2FA enrollment5 requests15 minutes
Password reveal30 requests1 minute
General API100 requests1 minute
Rate-limited responses return 429 Too Many Requests with a Retry-After header.

Error responses

All error responses follow a consistent format:
{
  "error": "Human-readable error message",
  "code": "ERROR_CODE",
  "status": 400
}

Common error codes

StatusCodeDescription
400VALIDATION_ERRORRequest body failed validation
401UNAUTHORIZEDMissing or invalid authentication
403FORBIDDENValid auth but insufficient permissions, or missing CSRF token
404NOT_FOUNDResource does not exist or is not accessible
409CONFLICTResource already exists (e.g., duplicate entry)
410GONEResource removed or feature deprecated (e.g., zero-trust TOTP code request)
422UNPROCESSABLERequest understood but cannot be processed
429RATE_LIMITEDToo many requests
500INTERNAL_ERRORServer error

Request validation

All request bodies are validated using Zod schemas. Invalid requests receive a 400 response with details about which fields failed validation:
{
  "error": "Validation failed",
  "code": "VALIDATION_ERROR",
  "details": [
    {
      "field": "password",
      "message": "String must contain at least 8 characters"
    }
  ]
}

Pagination

List endpoints support cursor-based pagination:
GET /api/passwords?limit=50&cursor=<last-item-id>
ParameterTypeDefaultDescription
limitinteger50Maximum items per page (max: 100)
cursorstringID of the last item from the previous page

Content type

All request and response bodies use JSON:
Content-Type: application/json
Streaming endpoints (reset progress, AI chat) use Server-Sent Events:
Content-Type: text/event-stream