> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trylath.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Every Lath operation is POST https://platform.trylath.com/<operation name with dots replaced by slashes>, with a JSON body and `Authorization: Bearer <key>`. `email.send` is POST /email/send.
> Branch on `error.code`, never on `error.message`. Every refusal also carries `error.fix`, which names the next step.
> Send an `Idempotency-Key` header on any operation that is not retry-safe, so a retry cannot run it twice.
> A `lath_test_` key emails only the account's own members and sends no SMS; a `lath_live_` key reaches real recipients and is billed.
> The OpenAPI document, generated from the same registry as the routes, is at https://platform.trylath.com/openapi.json.

# Express and Node

> One middleware, and every route behind it has the signed-in user on the request. Or verify by hand, with no framework at all.

<Steps>
  <Step title="Send">
    The client is the same everywhere — it is `fetch` and a key, with no Node-only dependency in the call path.

    ```ts theme={null}
    import { createLath } from "@trylath/sdk";

    const lath = createLath({ key: process.env.LATH_API_KEY });
    await lath.email.send({ to: "you@example.com", subject: "Hello", text: "First one." });
    ```
  </Step>

  <Step title="Protect routes">
    `lathExpress` verifies the bearer token and puts the user on `req.lath`. A request without a valid one is answered 401 with `www-authenticate: Bearer` and the usual `{ error: { code, message, fix } }` body — the middleware never hands a half-authenticated request to your handler.

    ```ts theme={null}
    import express from "express";
    import { lathExpress } from "@trylath/sdk";

    const app = express();
    app.use("/api", lathExpress({ environmentId: process.env.LATH_ENV_ID! }));

    app.get("/api/me", (req, res) => res.json(req.lath));
    ```
  </Step>

  <Step title="Without a framework">
    `userFromNodeRequest` takes a raw Node request and returns the user or `null`, which is everything Fastify, Koa or `node:http` needs.

    ```ts theme={null}
    import { createServer } from "node:http";
    import { userFromNodeRequest } from "@trylath/sdk";

    createServer(async (req, res) => {
      const user = await userFromNodeRequest(req, { environmentId: process.env.LATH_ENV_ID! });
      if (!user) {
        res.statusCode = 401;
        return res.end();
      }
      res.end(JSON.stringify({ userId: user.userId }));
    }).listen(3000);
    ```
  </Step>
</Steps>
