Skip to main content

What is the Toots API?

The Toots API is built using oRPC, a modern type-safe RPC framework that provides end-to-end type safety between your server and client. Instead of traditional REST endpoints, Toots uses remote procedure calls with automatic type inference.

Why oRPC?

oRPC brings several advantages to the Toots API:
  • Type safety: Full TypeScript type inference from server to client
  • Developer experience: Auto-complete and type checking in your IDE
  • No code generation: Types are inferred directly from your router definitions
  • Framework agnostic: Works with Next.js, React, and other frameworks
The Toots API uses oRPC version ^1.13.4 for both client and server packages.

How it works

The Toots API architecture consists of three main components:

Server router

The server defines procedures grouped by resource type. Each router is defined in apps/web/server/base.ts:10-14:
const router = {
  projects: projectsRouter,
  messages: messagesRouter,
  tickets: ticketsRouter,
}

RPC handler

Requests are handled through a Next.js API route at /rpc that processes all RPC calls. From apps/web/app/rpc/[[...rest]]/route.ts:6-12:
const handler = new RPCHandler(router, {
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
})

Client access

The client creates a typed RPC client that can be used in both server and client components. From apps/web/lib/orpc.ts:29-36:
/**
 * Typed RPC client. Use from server or client components.
 * On the server, uses the direct router client when available (SSR optimization).
 * In the browser, uses HTTP to /rpc.
 *
 * @example
 * const result = await rpc.projects.list({ limit: 10 })
 */
export const rpc = ...

Making API calls

To call the API, import the rpc client and invoke procedures:
import { rpc } from "@/lib/orpc"

// List projects with pagination
const result = await rpc.projects.list({ 
  limit: 10, 
  cursor: 0 
})

// Get a specific project
const project = await rpc.projects.get({ id: "project-id" })

// Create a new project (requires authentication)
const newProject = await rpc.projects.create({
  name: "My Project",
  description: "A new project"
})
All types are automatically inferred, so you’ll get IDE auto-complete for both inputs and return values.

Available routers

The Toots API provides the following routers:
  • projects: CRUD operations for projects
  • messages: Message management for projects
  • tickets: Ticket operations

Context and middleware

Each RPC procedure receives a context object that includes request headers and session information. The context type is defined in apps/web/server/context.ts:3-6:
export type RpcContext = {
  headers: Headers
  session: { user: { id: string; email: string; name?: string }; session: object } | null
}
Learn more about authentication in the Authentication guide.

Error handling

The API uses oRPC’s built-in error handling. When an error occurs:
  • Errors are logged server-side via the onError interceptor
  • Client receives detailed error information
  • TypeScript types include potential error states
try {
  const project = await rpc.projects.get({ id: "invalid-id" })
} catch (error) {
  console.error("Failed to fetch project:", error)
}

Build docs developers (and LLMs) love