Custom Routes
Custom Routes let you expose a Server Function as an HTTP endpoint. Each route has its own URL, access policy, and HTTP method, and maps to a specific handler on a server function. Use them for receiving webhooks from external systems, building API endpoints, serving file downloads, or any HTTP-driven integration.
Route configuration
Section titled “Route configuration”Each custom route is configured with:
| Field | Description |
|---|---|
| Route path | The URL path for this endpoint |
| Access | Anonymous - open to all callers; Secured - requires authentication |
| Auth methods | When secured: Token (OAuth bearer token) and/or API Key - one or both can be enabled |
| HTTP method | The allowed method for this route (GET, POST, PUT, PATCH, DELETE, etc.) |
| Server Function | The function that handles requests to this route - entry point is always process_request, falling back to run if not defined |
Handler implementation
Section titled “Handler implementation”On the server function side, the route calls process_request if it exists, or falls back to run if it does not. The handler receives { req, res, query, body } in its input:
| Field | Description |
|---|---|
req | Incoming HTTP request - method, headers, path |
res | Outgoing HTTP response object |
query | Parsed query string parameters |
body | Parsed request body (for POST, PUT, PATCH) |
req and res are only present when a function is invoked as a Custom Route handler. Server functions called from Database Workflows, portal actions, or the platform UI do not receive them.
handlers.process_request = async input => { const { req, body } = input;
if (req.method !== `POST`) { return api.http_error.method_not_allowed(`Method not allowed`); }
const result = await process(body); return { ok: true, data: result };};For response patterns, HTTP error helpers, and streaming responses, see Server Functions - Webhooks.
Access control
Section titled “Access control”Anonymous routes accept requests from any caller without authentication. Use for public webhooks where the external system cannot send credentials, or where payload verification (e.g. a signature header) is handled in the handler code itself.
Secured routes require at least one of:
- Token - a valid OAuth bearer token issued by the platform (
Authorization: Bearer <token>) - API Key - a platform-issued API key (prefixed
odk_), passed the same way (Authorization: Bearer odk_...)
Both can be enabled on the same route, allowing callers to authenticate with either method. The platform validates the credential before the handler is invoked - no auth logic is needed in the handler code.