Documentation
Documentation
Introduction

Getting Started

Getting started
Getting StartedInstallationQuick StartProject Structure

Configuration

Configuration
ConfigurationEnvironment ConfigurationEdge ConfigDatabaseAuth SecretStripeFirebaseStorageGoogle Maps And Cloud Service AccountOAuth ProvidersEmail DeliverySentryFeature Flags

Architecture

Architecture
Architecture OverviewTech StackoRPC MiddlewareDesign Principles

Patterns

Patterns
Code Patterns & ConventionsFeature ModulesError HandlingType Safety

Database

Database
DatabaseSetupSchema DefinitionDatabase OperationsMigrationsCaching
Data Tables

API

oRPCProceduresRoutersoRPC Proxy Setup
APIsOpenAPIREST Endpoints

Auth & Access

AuthenticationConfigurationOAuth ProvidersRolesSession Management
AuthorizationUser RolesPermissions

Routing & i18n

RoutingDeclarative RoutingNavigation
InternationalizationTranslationsLocale Routing

Components & UI

ComponentsButtonsFormsNavigationDialogs
StylesTailwind CSSThemingTypography

Storage

Storage
StorageConfigurationUsageBuckets
Stripe Billing

Extra

Caching

Templates

Templates
Template GuidesCreate New FeatureCreate New PageCreate Database TableCreate oRPC RouterAdd Translations

Development

Development
DevelopmentCommandsAI AgentsBest Practices
Pulling Updates

APIs

OpenAPI and REST endpoints powered by oRPC

Overview

REST endpoints are generated from oRPC procedures that define explicit .route(...) metadata.

Architecture

External Client
  -> /api/<path>
  -> OpenAPI handler (`@orpc/openapi`)
  -> appRouter procedures
  -> db/services

Expose a Procedure as REST

import { authProcedure } from "@/rpc/procedures/rpc";
import { actionResponseSchema } from "@/lib/utils/schema-utils";
import { z } from "zod";

export const todosRouter = createRPCRouter({
  list: authProcedure
    .meta({ rateLimit: "QUERY", acceptApiKey: true })
    .route({
      method: "GET",
      path: "/todos/list",
      tags: ["todos"],
      summary: "List todos",
    })
    .input(z.object({ organizationId: z.string().uuid() }))
    .output(actionResponseSchema(z.array(z.object({ id: z.string() }))))
    .query(async ({ ctx, input }) => {
      const items = await ctx.db.todos.getByOrganizationId(input.organizationId);
      return { success: true, payload: items };
    }),
});

API Key Authentication

For procedures with acceptApiKey: true, send:

x-api-key: pk_...

If you do not use API keys, authenticated browser calls can still use session cookies.

Docs Endpoints

  • OpenAPI JSON: /api/openapi.json
  • Docs selector page: /api/docs
  • Scalar UI: /api/docs/scalar
  • Swagger UI: /api/docs/swagger

Docs pages are controlled by:

  • Config.Auth.DISABLE_OPENAPI
  • Config.Api.API_DOCS_ENABLED

Next Steps

  • OpenAPI Details
  • REST Examples
  • oRPC Procedures

On this page

Overview
Architecture
Expose a Procedure as REST
API Key Authentication
Docs Endpoints
Next Steps