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/api

Authentication

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 data
  • write: push versions, upload files
  • admin: 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 statusLimit
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 window
  • X-RateLimit-Remaining: requests remaining
  • X-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 credentials
  • 403: Insufficient permissions (wrong scope)
  • 404: Resource not found
  • 409: 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)

Endpoints