# How to Create New API Endpoints in Open-SEO: A Step-by-Step Guide

> Learn to create new API endpoints in Open-SEO. Define routes, implement logic with createServerFn, and regenerate routeTree.gen.ts for seamless integration. Get started today!

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-16

---

**You create new API endpoints in Open-SEO by defining a TanStack Router route file under `src/routes/api/`, implementing the logic with `createServerFn`, and regenerating [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts) to register the new route.**

The Open-SEO project uses **TanStack Router** for its HTTP API layer, where every route—including API endpoints—lives under the `src/routes/` directory and is compiled into the auto-generated [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts) file. This file-based routing system enables type-safe API development with automatic route discovery.

## Understanding the Routing Architecture

Open-SEO leverages TanStack Router's convention-based routing system provided by `@tanstack/router-cli`. All API routes follow a predictable pattern where each endpoint is defined in its own [`route.ts`](https://github.com/every-app/open-seo/blob/main/route.ts) file within the `src/routes/api/` hierarchy. The build process scans these files and updates [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts) accordingly.

### The Route File Convention

Each API endpoint requires a dedicated directory containing a [`route.ts`](https://github.com/every-app/open-seo/blob/main/route.ts) file. For example, to create the endpoint `/api/example`, you create [`src/routes/api/example/route.ts`](https://github.com/every-app/open-seo/blob/main/src/routes/api/example/route.ts). The folder structure directly maps to the URL path, and the file must export a `Route` constant that TanStack Router consumes.

## Step-by-Step Guide to Creating API Endpoints

### 1. Create the Route Folder and File

Create a new directory under `src/routes/api/` matching your desired endpoint path. For an endpoint at `/api/example`, create the file [`src/routes/api/example/route.ts`](https://github.com/every-app/open-seo/blob/main/src/routes/api/example/route.ts).

### 2. Export the Route Definition

The route file must export a constant named `Route` instantiated from TanStack Router. This object requires an `id`, URL `path`, and a `serverFn` property pointing to your server function.

```typescript
// src/routes/api/example/route.ts
import { Route } from '@tanstack/router';
import { createServerFn } from '@tanstack/start';

export const exampleFn = createServerFn('GET', async () => {
  return { ok: true, message: 'Hello from /api/example' };
});

export const Route = new Route({
  id: '/api/example',
  path: '/api/example',
  serverFn: exampleFn,
});

```

Key requirements:

- The `id` and `path` must match the desired URL exactly.
- Use `createServerFn` for GET requests or `createServerAction` for POST/PUT mutations.
- The return value is automatically serialized to JSON and sent as the HTTP response.

### 3. Add Type Definitions

If your endpoint accepts complex inputs or returns custom shapes, define **Zod schemas** or TypeScript interfaces in `src/types/` and import them into your route file for runtime validation.

### 4. Regenerate the Route Tree

After creating the route file, run the code generation script to update [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts):

```bash
pnpm run generate:router

```

This command uses `@tanstack/router-cli` to scan `src/routes/**/route.ts` files and regenerate the route tree imports. The generated file will contain an import similar to existing API routes:

```typescript
import { Route as ApiExampleRouteImport } from './routes/api/example/route';

const ApiExampleRoute = ApiExampleRouteImport.update({
  id: '/api/example',
  path: '/api/example',
  getParentRoute: () => rootRouteImport,
} as any);

```

### 5. Apply Authentication Middleware

Most API routes in Open-SEO are protected by the `ensureUser` middleware located in [`src/middleware/ensure-user.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user.ts). To secure your endpoint, wrap the server function with this middleware:

```typescript
import { ensureUser } from '../../middleware/ensure-user';

export const profileFn = createServerFn('GET', async ({ request, ctx }) => {
  const user = await ensureUser(request, ctx);
  return { ok: true, email: user.email };
});

```

### 6. Write and Run Tests

Create test files adjacent to your route (e.g., [`src/routes/api/example/route.test.ts`](https://github.com/every-app/open-seo/blob/main/src/routes/api/example/route.test.ts)) or add to the existing test suite. Use `fetch` or TanStack's `createTestRouter` utilities to verify both success cases and authentication errors. Run the full suite with:

```bash
pnpm test

```

## Practical Code Examples

### Simple GET Endpoint

The following example in [`src/routes/api/ping/route.ts`](https://github.com/every-app/open-seo/blob/main/src/routes/api/ping/route.ts) implements a basic health check:

```typescript
// src/routes/api/ping/route.ts
import { Route } from '@tanstack/router';
import { createServerFn } from '@tanstack/start';

export const pingFn = createServerFn('GET', async () => ({
  ok: true,
  timestamp: Date.now(),
}));

export const Route = new Route({
  id: '/api/ping',
  path: '/api/ping',
  serverFn: pingFn,
});

```

### POST Endpoint with Zod Validation

For endpoints requiring input validation, use Zod schemas within the server function:

```typescript
// src/routes/api/slug/route.ts
import { Route } from '@tanstack/router';
import { createServerFn } from '@tanstack/start';
import { z } from 'zod';

const bodySchema = z.object({
  url: z.string().url(),
});

export const slugFn = createServerFn('POST', async ({ request }) => {
  const json = await request.json();
  const { url } = bodySchema.parse(json);
  
  const slug = url.split('//')[1].replace(/[/.]/g, '-');
  return { ok: true, slug };
});

export const Route = new Route({
  id: '/api/slug',
  path: '/api/slug',
  serverFn: slugFn,
});

```

### Protected User Profile Endpoint

Combine server functions with authentication middleware to create protected routes:

```typescript
// src/routes/api/user/profile/route.ts
import { Route } from '@tanstack/router';
import { createServerFn } from '@tanstack/start';
import { ensureUser } from '../../middleware/ensure-user';

export const profileFn = createServerFn('GET', async ({ request, ctx }) => {
  const user = await ensureUser(request, ctx);
  return { ok: true, email: user.email };
});

export const Route = new Route({
  id: '/api/user/profile',
  path: '/api/user/profile',
  serverFn: profileFn,
});

```

## Key Files in the API Architecture

Understanding these core files helps when extending the Open-SEO API:

- **[`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts)** — The auto-generated route map that stitches together all API and client routes. Never edit this manually; regenerate it using the router CLI.
- **`src/routes/api/**/route.ts`** — The location where each API endpoint is declared with its `Route` object and server function implementation.
- **[`src/middleware/ensure-user.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user.ts)** — The authentication middleware that enforces logged-in user sessions on protected API routes.
- **[`package.json`](https://github.com/every-app/open-seo/blob/main/package.json)** — Contains the `generate:router` script that rebuilds the route tree when new endpoints are added.
- **`src/types/**/*.ts`** — Shared TypeScript definitions and Zod schemas for request/response validation across multiple endpoints.

## Summary

- **Create route files** under `src/routes/api/` following the URL path structure you want to expose.
- **Implement logic** using `createServerFn` from `@tanstack/start`, which handles server-side execution and JSON serialization automatically.
- **Regenerate routes** by running `pnpm run generate:router` to update [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts) with your new endpoint.
- **Secure endpoints** by importing and calling the `ensureUser` middleware from [`src/middleware/ensure-user.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user.ts).
- **Validate inputs** using Zod schemas or TypeScript interfaces stored in `src/types/` for runtime type safety.

## Frequently Asked Questions

### What is TanStack Router and why does Open-SEO use it for API endpoints?

TanStack Router provides a type-safe, file-based routing system that handles both client-side navigation and server-side API routes. Open-SEO uses it because it automatically generates route trees, provides end-to-end type safety, and supports server functions through `@tanstack/start`, eliminating the need for a separate API framework.

### Do I need to manually edit the [`routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/routeTree.gen.ts) file?

No. The [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts) file is auto-generated by the `@tanstack/router-cli` through the `generate:router` npm script. You should never manually edit this file; instead, create your route files under `src/routes/` and run the generation command to update the tree automatically.

### How do I secure a new API endpoint with authentication?

Import the `ensureUser` middleware from [`src/middleware/ensure-user.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user.ts) and call it at the beginning of your server function. This middleware validates the session and returns the user object, or throws an authentication error if the request lacks valid credentials.

### What testing approach does Open-SEO recommend for new API routes?

Create test files adjacent to your route (e.g., [`src/routes/api/example/route.test.ts`](https://github.com/every-app/open-seo/blob/main/src/routes/api/example/route.test.ts)) or add to the existing test suite. Use standard `fetch` calls or TanStack's `createTestRouter` utilities to invoke endpoints, verifying both successful responses and proper error handling for authentication failures or validation errors.