API Overview
The Underlay API is a JSON REST API served at /api. All request and response bodies are JSON (except file uploads/downloads). A machine-readable reference is available at /llms.txt.
Base URL
https://underlay.org/apiAuthentication
All GET requests are public; no authentication required to read public data. All write requests (POST, PATCH, PUT, DELETE) require authentication.
There are two authentication methods:
API Keys (recommended for scripts & apps)
Pass your key as a Bearer token:
Authorization: Bearer ul_a1b2c3d4e5...Keys have three scopes:
read: list and download datawrite: push versions, upload filesadmin: delete collections, manage keys
Keys can optionally be scoped to a single collection. Create keys in your organization settings or via POST /api/auth/api-key/create.
Session Cookies (browser)
The web UI authenticates via OAuth2/PKCE sign-in through KF Auth, handled by better-auth at /api/auth/*. Sessions expire after 30 days.
Invalid Credentials
If a Bearer token is provided but does not match any key, the request is immediately rejected with 401. It will not fall through to anonymous access.
Rate Limits
All API requests are rate-limited per IP (unauthenticated) or per account (authenticated). Authenticated requests get a significantly higher allowance:
| Auth status | Limit |
|---|---|
| Unauthenticated (by IP) | 60 requests / minute |
| Authenticated (by account) | 5,000 requests / minute |
Every response includes rate limit headers:
X-RateLimit-Limit: max requests in the current windowX-RateLimit-Remaining: requests remainingX-RateLimit-Reset: seconds until the window resets
When you exceed the limit, you'll receive a 429 Too Many Requests response with a Retry-After header indicating how long to wait.
For any automated or scripted access, always use an API key to get the higher rate limit.
Error Responses
Errors return a JSON body with error and statusCode:
{
"error": "Authentication required",
"statusCode": 401
}Common status codes:
400: Bad request (invalid input)401: Authentication required or invalid credentials403: Insufficient permissions (wrong scope)404: Resource not found409: Version conflict (re-fetch and retry)413: Payload too large (file upload exceeds size limit)422: Validation error (e.g. missing files)429: Rate limited (wait and retry)