# Functions and routes

## Functions

Put functions in `flatstack/functions/*.ts`. Each export must be an `fn()`:

```ts
import { fn, z } from "@flatstack/server";

export const createTodo = fn({
  input: z.object({ title: z.string().min(1).max(200) }),
  auth: "required",
  handler: async ({ input, ctx }) => {
    // ...
  },
});
```

Call it with `POST /fn/createTodo` and a JSON body. If the input doesn't match the schema, the call returns `400 validation_failed` with each field's problem in `details.fieldErrors`, and your handler doesn't run. If the handler returns nothing, the response is `204`.

| `auth` | Who can call it | `ctx.user` |
| --- | --- | --- |
| `required` | Signed-in users | Always set |
| `admin` | Signed-in users with the `admin` role | Always set |
| `optional` | Anyone | Set when signed in |
| `none` | Anyone | Not looked up |

A caller who isn't allowed gets `401 unauthenticated` or `403 forbidden` before the input is checked.

If your handler throws, the caller gets `500 internal_error` and the details go to your project's logs, not to the caller.

## Routes

Put HTTP routes, such as webhooks, in `flatstack/routes/*.ts`. They're served under `/api`:

```ts
import { router } from "@flatstack/server";

export const webhooks = router().post("/webhooks/shop", async (c) => {
  const ctx = c.get("ctx");
  return c.json({ ok: true });
});
```

`/api/data/*` and `/api/stripe/*` are reserved for Flatstack's data API and payments helper. A project with routes there won't deploy.

## ctx

| Field | What it is |
| --- | --- |
| `ctx.db` | Your database (Drizzle). `ctx.db.asUser()` applies your tables' access rules for the caller (see [Data and access rules](data.md)); `ctx.db.asAdmin()` ignores them. |
| `ctx.user` | The signed-in user, by auth mode. |
| `ctx.env` | Your environment variables. |
| `ctx.secrets.get(name)` | A secret's value. Never logged. |
| `ctx.log` | `info`, `warn` and `error`, written as JSON lines to your project's logs. Fields named like secrets are redacted. |
| `ctx.email.send(message)` | Sends a transactional email. See [Sending email](email.md). |
| `ctx.waitUntil(promise)` | Keeps work running after the response is sent. |
| `ctx.request` | The incoming request. |
| `ctx.cron` | While a [cron job](cron.md) runs the function: `{ schedule, scheduledFor, attempt }`. Otherwise `null`. |

`ctx.storage` is your project's [file storage](storage.md), and `ctx.email` sends [email](email.md).

These aren't available yet and answer `501 feature_unavailable` if used: `ctx.queue`, `ctx.realtime`, `ctx.vector`, `ctx.ai` and `ctx.org`. Sign-in for your app's users (`/auth/*`) isn't available yet either.

Each request can use up to 50 ms of CPU on Hobby, 200 ms on Pro and 500 ms on Studio.