> ## 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.

# Going live

> What is already working, what is refused until you do something, and the fields to read instead of trusting this page. Every refusal here names itself, so you can find out from the product rather than from prose.

## What already works, the moment you sign up

`account.signup` returns an account, a project, both environments, and four keys — a secret and a publishable one per environment, shown once and never again.

**You can send email immediately, with nothing verified.** Every project gets a sender on its own subdomain of Lath's sending domain, and transactional and sign-in mail go out from it. Verifying a domain of your own is what puts your name on it and what marketing needs; it is not what sending needs.

Sign-in by email code and by email link work out of the box. Passwords are the one method off by default.

The owner seat is invited rather than active until somebody follows the emailed link. The keys work either way, which is why a script can sign up and send before anyone has opened the mail.

## Before marketing email

Seven things are checked, and you do not have to discover them one at a time: `email.broadcast.create` returns them all as readiness problems, each with its own fix, long before anything sends. `email.broadcast.send` then refuses on the first one that still stands.

A sender you are allowed to send from, a topic that exists, a segment that exists if you named one, a template that exists and **is published**, not one of the reserved sign-in templates, a working unsubscribe link, and a postal address in the email footer.

Each problem carries its own code in that list, so your own code can branch on which one it is rather than matching prose. They are readiness codes rather than refusal codes — a distinction worth keeping straight, because two of them, `sender_unverified` and `topic_unknown`, are also what you are refused with if you ignore readiness and send anyway.

The last one catches almost everybody, because it is law rather than plumbing and it is empty by default. It lives in the theme's copy, and it must be published, not merely saved as a draft.

Two more can refuse at send time and are about the account rather than the message: a closed account, and an invoice past due — and past due pauses **marketing only**, after a grace period. Transactional mail keeps going.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://platform.trylath.com/account/theme/set \
    -H "Authorization: Bearer $LATH_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"copy":{"email.legal_address":"Northwind Labs, 100 Main St, Portland OR 97204"}}'
  ```

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

  const lath = createLath({ key: process.env.LATH_API_KEY });

  const { result } = await lath.account.theme.set({
    copy: {
      "email.legal_address": "Northwind Labs, 100 Main St, Portland OR 97204",
    },
  });
  ```

  ```bash CLI theme={null}
  lath account theme set \
    --copy '{"email.legal_address":"Northwind Labs, 100 Main St, Portland OR 97204"}'
  ```
</CodeGroup>

## Before text messages

Two separate things: a carrier registration that has reached **active** for the project, and a phone number this environment owns. Registration is filed once per project and moves draft → registering → active on its own; `sms.registration.get` returns a plain-language blocker for whatever state it is in.

**`sms.send` does not refuse while you wait.** It stores the message and answers with a `blocked` object beside it, saying why and what would unblock it. The message is real, findable and not sent — which is a different thing from an error, and the reason a send that "worked" may not have gone anywhere. Read the reply.

Quiet hours are **on by default, 21:00 to 08:00, with no timezone set** — and without a timezone there is no clock to measure them against, so marketing text is refused until you set one or turn quiet hours off. The readiness problem names the missing timezone, and `sms.settings.get` reports it on its own. Messages caught by quiet hours are delayed, never dropped.

A marketing text must tell people how to stop, and readiness says so when it does not. It is not added for you, because adding it would change the segment count you just measured.

## Before the hosted sign-in pages

**Allowed redirect origins start empty, so nothing is allowed.** Until you list yours, sending somebody back to your app is refused with `redirect_not_allowed`, and a magic link has nowhere to land. This is the first thing to set and the easiest to forget, because the hosted pages look finished without it.

Passkeys bind to an origin and are never bound to Lath's hostname. The relying-party id derives from your first allowed origin; with none, passkeys refuse with `passkey_unconfigured`.

Social sign-in works through Lath's own apps, which means the consent screen says Lath. Registering your own puts your name there instead — `auth.oauth.app.list` hands you the exact callback address to register with the provider.

Publish the theme. `account.theme.set` saves a draft; the hosted pages and your mail both read the published one. Publishing and resetting are live-only, and a palette below WCAG AA is refused with `contrast_too_low` — which names a nearby colour that would pass rather than leaving you to guess.

Lath will not let you switch off the last way in: a settings change that would leave no method both enabled and available is refused with `no_usable_signin_method`.

## What test mode will not do

Anything that changes what live users receive needs the live key, refused otherwise with `live_only`: publishing or resetting a theme, setting the sender, removing a domain, and setting your own OAuth app.

Test email only reaches **active members of your own account** — a plus-tagged address folds to the member's mailbox, and anyone else is refused with `test_mode_recipient`. An invited member who has not accepted yet counts as anyone else.

**Test mode sends no text messages at all**, to anybody, for the same reason: there is no safe pretend recipient for a carrier.

Fifty messages per environment per rolling day, refused with `test_mode_limit`. Test sends are never billed.

Broadcasts do not refuse on any of this — they count the recipients they held, so the number you see is the number that would have gone.

## Ask the product, not this page

This page will go out of date; the fields below cannot, because they are computed from the same code that does the refusing. Prefer them to any checklist, including this one.

`email.broadcast.create` and `email.automation.activate` return readiness problems with fixes. `sms.settings.get` returns whether texting is ready and what is in the way. `sms.registration.get` and `email.domain.get` each return a single blocker, null when there is nothing wrong. `auth.settings.get` returns every sign-in method with whether it is enabled, whether it is available, and why not.

In the dashboard, the same answers are on the page that owns them, and anything account-wide that needs you is on the environment's home page.
