# Lath > Documentation for Lath: auth, email and SMS behind one API, one MCP server and one CLI. > ## Agent Instructions > Every Lath operation is POST https://platform.trylath.com/, with a JSON body and `Authorization: Bearer `. `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. - [Lath documentation](https://docs.trylath.com/index.md): Auth, email and SMS behind one API, one key and one customer record. - [Quickstart](https://docs.trylath.com/get-started/quickstart.md): From no account to a sent message in three calls. Nothing here needs a dashboard, a credit card, or a person. - [Send your first email](https://docs.trylath.com/get-started/send-email.md): One call, and no domain to verify first. Every project can send from its own address on this platform from the day it signs up — the domain you own is an upgrade, not a prerequisite. - [Sign in your first user](https://docs.trylath.com/get-started/sign-in-a-user.md): Two calls: send a code to an address, then exchange the code for a session. The user does not have to exist first — verifying the code is what creates them. - [Send your first text](https://docs.trylath.com/get-started/send-sms.md): One call, in the same shape as an email. The two things worth knowing before you send are what a message costs and why your first one is probably not going to arrive yet. - [Next.js](https://docs.trylath.com/frameworks/nextjs.md): Send from a server action or a route handler, drop in the sign-in components, and protect an API route with one call. The secret key never reaches the browser. - [Express and Node](https://docs.trylath.com/frameworks/express.md): One middleware, and every route behind it has the signed-in user on the request. Or verify by hand, with no framework at all. - [Hono, Workers and Bun](https://docs.trylath.com/frameworks/hono.md): The client is fetch and nothing else, so it runs wherever fetch does — Cloudflare Workers, Deno, Bun, Vercel Edge. One import needs Node, and it is worth knowing which before you deploy. - [Any other language](https://docs.trylath.com/frameworks/other-languages.md): There is no Python, Ruby, Go, PHP or Java client yet — the only typed clients are @trylath/sdk and @trylath/react. Everything is a POST with a bearer token, and the OpenAPI document generates a client for most languages in one command. - [Templates](https://docs.trylath.com/sending/templates.md): Write a message once, in every language you need, and publish it when it is right. A draft cannot send. - [Broadcasts and automations](https://docs.trylath.com/sending/broadcasts.md): One message to an audience, and messages that send themselves when something happens. Both refuse to start until every reason they would fail is fixed. - [Domains and deliverability](https://docs.trylath.com/sending/deliverability.md): Five DNS records — three required, two strongly recommended — and what each one is actually for. Then the small number of things that genuinely decide whether mail arrives. - [Authentication](https://docs.trylath.com/platform/authentication.md): What a key is, what it names, and why only one operation can do without one. - [API conventions](https://docs.trylath.com/platform/api-conventions.md): The rules every one of the 206 operations follows — how a call is addressed, how a list is paged, how a retry is made safe, and what happens when you go too fast. - [Test mode](https://docs.trylath.com/platform/test-mode.md): Every project has a test environment beside the live one. It is for building against, and it is fenced so a loop left running cannot reach a stranger or cost anything. - [Rate limits](https://docs.trylath.com/platform/rate-limits.md): Every request counts against a ceiling per credential, which API conventions covers. This page is the other layer: exact limits on the operations worth attacking — starting a sign-in, redeeming a link, creating an account, sending a text — counted in the database so every API process shares them. - [Errors](https://docs.trylath.com/platform/errors.md): Every error says what happened and what to do about it, in a shape meant to be read by whatever is calling. - [Consent and suppression](https://docs.trylath.com/platform/consent.md): One question is asked before any message leaves: may this address receive this kind of message on this channel? This is how it is answered, and how you prove the answer later. - [Spending caps](https://docs.trylath.com/platform/spending-caps.md): How a cap is enforced, what a send does when it would cross one, and what the cap does not cover. - [Data and retention](https://docs.trylath.com/platform/data-and-retention.md): Where your data is processed, when each kind is removed, and what closing an account erases. Every window here is a job the worker runs, not only a sentence in a policy. - [REST](https://docs.trylath.com/surfaces/rest.md): One POST per operation, and an OpenAPI document generated from the same definitions the API runs on. - [MCP](https://docs.trylath.com/surfaces/mcp.md): Every operation is a tool, carrying the input schema and the result schema an agent needs before it calls. - [CLI](https://docs.trylath.com/surfaces/cli.md): Every operation, from a terminal or a CI job. No subcommand is hand-written — the command list is generated from the same registry as the REST routes, so the CLI cannot be missing something the API has. - [SDK](https://docs.trylath.com/surfaces/sdk.md): A typed client generated from the operation registry, and the middleware that turns a Lath access token into a user on a request you already have. - [Dashboard](https://docs.trylath.com/surfaces/dashboard.md): A screen for every operation you would otherwise do by hand, built on the same API a customer uses. - [Webhooks](https://docs.trylath.com/surfaces/webhooks.md): Events arrive signed, with the timestamp inside the signature so a captured request cannot be replayed at you later. Every attempt keeps its own row, so a delivery that failed can be read before it is replayed. - [For agents](https://docs.trylath.com/surfaces/agents.md): An agent can do all 206 operations, discover them without being told, and provision its own account. - [auth.device.approve](https://docs.trylath.com/api-reference/auth/authdeviceapprove.md): Approves or denies a device sign-in by user code, on behalf of a signed-in person. The person's access token proves who is approving; the device then receives a session for that user on its next poll. Approving needs a recent sign-in, and a session that passed the second factor when the account has… - [auth.device.describe](https://docs.trylath.com/api-reference/auth/authdevicedescribe.md): Public, for the hosted approval page: given a user code, returns the environment it belongs to, the device's name and when it expires, so the page can show the right brand and sign the person in. - [auth.device.poll](https://docs.trylath.com/api-reference/auth/authdevicepoll.md): Polls a device sign-in. Returns status pending, denied or expired, or approved with the session exactly once. Polling faster than the interval is refused with slow_down. Callable with a publishable key. - [auth.device.start](https://docs.trylath.com/api-reference/auth/authdevicestart.md): Starts a device sign-in for a CLI or a device without a browser. Returns a secret device code to poll with, a short user code to show the person, and the hosted URL where they approve it. Callable with a publishable key. - [auth.factor.list](https://docs.trylath.com/api-reference/auth/authfactorlist.md): Lists the signed-in user's second factors with their status and how many recovery codes remain. - [auth.factor.recovery.regenerate](https://docs.trylath.com/api-reference/auth/authfactorrecoveryregenerate.md): Replaces the recovery codes of the active factor with eight new ones, shown once. Needs a recent sign-in that passed the second factor. - [auth.factor.remove](https://docs.trylath.com/api-reference/auth/authfactorremove.md): Turns off a second factor. Needs a recent sign-in that itself passed the second factor (or a passkey), so a stolen first factor cannot switch MFA off. Refused while this environment or one of the user's organizations requires MFA. - [auth.factor.totp.activate](https://docs.trylath.com/api-reference/auth/authfactortotpactivate.md): Completes enrolment with the first code the app shows. From now on every sign-in asks for a code. Returns eight one-time recovery codes; they are shown once and never again. When called with an mfaToken (a sign-in that had to enrol), also returns the session. - [auth.factor.totp.enroll](https://docs.trylath.com/api-reference/auth/authfactortotpenroll.md): Starts enrolling an authenticator app: returns a fresh secret and an otpauth URI to show as a QR code. Nothing counts until auth.factor.totp.activate proves the app shows the right code. Accepts an access token, or the mfaToken of a sign-in that was told to enrol. - [auth.identity.add](https://docs.trylath.com/api-reference/auth/authidentityadd.md): Starts attaching a new address to the signed-in user: an email (a code is sent to it) or a phone number in E.164 (a code by SMS, once the environment's number has an active carrier registration; until then channel_unavailable names the fix). Exactly one of email or phone. The user's access token is… - [auth.identity.remove](https://docs.trylath.com/api-reference/auth/authidentityremove.md): Removes one of the signed-in user's addresses. Needs a session opened in the last 15 minutes (reauth_required otherwise): a stolen access token must not be enough to lock the owner out. The last remaining address can never be removed, whatever passkeys or password the account has. If the removed add… - [auth.identity.verify](https://docs.trylath.com/api-reference/auth/authidentityverify.md): Completes attaching a new address with the code that was sent to it. The address becomes a verified identity of the signed-in user and, if the user had no email, their primary email. - [auth.link.complete](https://docs.trylath.com/api-reference/auth/authlinkcomplete.md): Completes a magic-link sign-in from the hosted landing page using the link token as the credential. Returns where to send the user and a one-time code appended to it as lath_code, which their app exchanges for the session with auth.session.exchange; or, when a second factor is owed, an mfaToken the… - [auth.mfa.verify](https://docs.trylath.com/api-reference/auth/authmfaverify.md): Finishes a sign-in that returned mfaToken: takes the six digits from the authenticator app, or one of the recovery codes, and issues the session (or, for a magic link, the redirect with the one-time code). Five attempts, then the sign-in must start again. A used recovery code never works twice; a TO… - [auth.oauth.app.list](https://docs.trylath.com/api-reference/auth/authoauthapplist.md): Lists every provider, whether it is turned on, whether this project uses its own app or the deployment's shared one, and the exact callback URL to register with the provider. Secrets are never returned. - [auth.oauth.app.remove](https://docs.trylath.com/api-reference/auth/authoauthappremove.md): Removes this project's own OAuth app for a provider and mode. Sign-in with that provider keeps working through the deployment's shared app, so this is a change of branding rather than a switch-off. - [auth.oauth.app.set](https://docs.trylath.com/api-reference/auth/authoauthappset.md): Gives this project its own OAuth app for a provider, so the consent screen shows the customer's name instead of Lath's. Registered per mode, because live and test send people back to different addresses. The secret is stored sealed and never returned. Without one, the deployment's shared app is used… - [auth.oauth.complete](https://docs.trylath.com/api-reference/auth/authoauthcomplete.md): Finishes a sign-in the provider sent back. Exchanges the code, reads the profile, then creates the user and identity on first sign-in and issues a session, returning a one-time handoff code on the customer's redirect URL exactly as a magic link does. An existing account is joined only when the provi… - [auth.oauth.start](https://docs.trylath.com/api-reference/auth/authoauthstart.md): Begins a sign-in with Google, Microsoft or GitHub. Returns the URL to send the person to, and the challenge id the callback needs. The state is single-use and bound to this environment and this provider; the PKCE verifier never leaves Lath. Refuses when the method is turned off for this environment,… - [auth.org.create](https://docs.trylath.com/api-reference/auth/authorgcreate.md): Creates an organization with the signed-in user as its owner, switches the session into it, and returns a fresh access token carrying it. - [auth.org.delete](https://docs.trylath.com/api-reference/auth/authorgdelete.md): Deletes an organization. The owner only, and only with a recent sign-in, because it removes every member's access at once and cannot be undone. Members are removed, outstanding invitations are revoked, and any session currently acting in the organization is moved out of it rather than left holding a… - [auth.org.get](https://docs.trylath.com/api-reference/auth/authorgget.md): Returns one organization the signed-in user belongs to, with its members and pending invitations (invitations only for admins and owners). - [auth.org.invite.accept](https://docs.trylath.com/api-reference/auth/authorginviteaccept.md): Joins the organization named by an invitation token. The signed-in user must hold the invited email address as a verified identity; the token is spent on use. Switches the session into the organization. - [auth.org.invite.create](https://docs.trylath.com/api-reference/auth/authorginvitecreate.md): Invites an email address into the organization with a role, by an emailed link to the hosted accept page (seven days). Admins and owners only; only an owner may invite an owner. Inviting the same address again re-sends. - [auth.org.invite.revoke](https://docs.trylath.com/api-reference/auth/authorginviterevoke.md): Cancels a pending invitation. Admins and owners only. - [auth.org.list](https://docs.trylath.com/api-reference/auth/authorglist.md): Lists the organizations the signed-in user belongs to, with their role in each and which one the session is acting in. - [auth.org.member.remove](https://docs.trylath.com/api-reference/auth/authorgmemberremove.md): Removes a member (admins and owners), or, with your own user id, leaves the organization. The last owner cannot leave or be removed. Sessions acting in the organization are moved out of it. - [auth.org.member.update](https://docs.trylath.com/api-reference/auth/authorgmemberupdate.md): Changes a member's role. Admins may set admin or member; only owners may grant or remove owner. The last owner cannot be demoted. - [auth.org.switch](https://docs.trylath.com/api-reference/auth/authorgswitch.md): Makes the session act in one of the user's organizations (or in none, with null) and returns a fresh access token carrying the org claim. Refused with mfa_required when the organization requires two-step sign-in and this session has not passed it. - [auth.org.update](https://docs.trylath.com/api-reference/auth/authorgupdate.md): Renames an organization or changes its settings (mfaRequired: members must pass two-step sign-in to act in it). Admins and owners only. - [auth.organization.get](https://docs.trylath.com/api-reference/auth/authorganizationget.md): Returns one end-user organization with its members and their roles. - [auth.organization.list](https://docs.trylath.com/api-reference/auth/authorganizationlist.md): Lists the environment's end-user organizations newest first with member counts. `query` matches the start of a name or slug. Pages with `before`, like every other list here. - [auth.passkey.list](https://docs.trylath.com/api-reference/auth/authpasskeylist.md): Lists the signed-in user's passkeys: name, device type, whether it is synced, when it was last used. - [auth.passkey.register.start](https://docs.trylath.com/api-reference/auth/authpasskeyregisterstart.md): Starts adding a passkey to the signed-in user: returns WebAuthn creation options for navigator.credentials.create, bound to the project's configured origin, excluding passkeys the user already has. The access token is the proof. - [auth.passkey.register.verify](https://docs.trylath.com/api-reference/auth/authpasskeyregisterverify.md): Completes adding a passkey with the authenticator's response from navigator.credentials.create. Stores the public key and tells the account's other addresses. - [auth.passkey.remove](https://docs.trylath.com/api-reference/auth/authpasskeyremove.md): Removes one of the signed-in user's passkeys. Needs a recent sign-in. A passkey that is the user's only way in cannot be removed. - [auth.passkey.signin.start](https://docs.trylath.com/api-reference/auth/authpasskeysigninstart.md): Starts a passkey sign-in: returns WebAuthn request options for navigator.credentials.get. Every Lath passkey is discoverable, so the browser offers the person's own; the optional identifier is recorded on the challenge as a hint and never changes the options, so nothing about whether an address exis… - [auth.passkey.signin.verify](https://docs.trylath.com/api-reference/auth/authpasskeysigninverify.md): Completes a passkey sign-in with the authenticator's response from navigator.credentials.get and issues a session. User verification is required, so a passkey sign-in counts as two factors and never asks for a code afterwards. - [auth.password.remove](https://docs.trylath.com/api-reference/auth/authpasswordremove.md): Removes the signed-in user's password so only codes, links and passkeys sign them in. Needs a recent sign-in. - [auth.password.set](https://docs.trylath.com/api-reference/auth/authpasswordset.md): Sets or replaces the signed-in user's password after checking the environment's rules (length) and, unless turned off, the breach corpus through a k-anonymity range lookup. Needs a recent sign-in when a password already exists. Every other address on the account is told. - [auth.password.signin](https://docs.trylath.com/api-reference/auth/authpasswordsignin.md): Signs in with an email or phone and a password. An unknown address and a wrong password get the same answer. Rate limited per address and per IP. Returns a session, or mfa.mfaToken when a second factor is owed. - [auth.session.exchange](https://docs.trylath.com/api-reference/auth/authsessionexchange.md): Exchanges the one-time code from a hosted sign-in for the session tokens. The code works once and expires two minutes after it was issued. Callable with the publishable key, because the code is the credential: it is what the browser at the end of a magic link is holding. - [auth.session.list](https://docs.trylath.com/api-reference/auth/authsessionlist.md): Lists a user's sessions, live and revoked, newest first, with device and network facts. - [auth.session.mine](https://docs.trylath.com/api-reference/auth/authsessionmine.md): Lists the signed-in end user's own sessions, newest first, marking which one is making the request. The access token is the proof, so a browser or app calls this with the publishable key. Only live sessions: a revoked one is not somewhere they are still signed in. - [auth.session.refresh](https://docs.trylath.com/api-reference/auth/authsessionrefresh.md): Exchanges a refresh token for a new access token and a new refresh token. Presenting a refresh token that was already exchanged revokes every session in its family, because a reused token may have leaked. - [auth.session.revoke](https://docs.trylath.com/api-reference/auth/authsessionrevoke.md): Revokes a session by id (including every refresh it has rotated into since sign-in), or every live session of a user. Revoked refresh tokens stop working immediately; access tokens expire within their lifetime. - [auth.session.revokeMine](https://docs.trylath.com/api-reference/auth/authsessionrevokemine.md): Ends one of the signed-in end user's own sessions, named by the family id auth.session.mine returns, or every session except the one making the request. The access token is the proof. Refusing to touch anyone else's sessions is structural: there is no way to name them. - [auth.session.signout](https://docs.trylath.com/api-reference/auth/authsessionsignout.md): Signs the end user out of the session whose refresh token is presented: that session and every refresh it has rotated into are revoked. Possession of the refresh token is the proof, so a browser or app calls this with the publishable key. Nothing is revealed about a token that does not exist. - [auth.settings.get](https://docs.trylath.com/api-reference/auth/authsettingsget.md): Returns this environment's sign-in settings with defaults filled in: enabled methods and whether each is available today (and why not), code and link lifetimes, session lifetimes, allowed redirect origins, signup policy and rate limits. Also shows exactly what the public settings endpoint tells a br… - [auth.settings.reset](https://docs.trylath.com/api-reference/auth/authsettingsreset.md): Returns every sign-in setting in this environment to its default, including the allowed redirect origins. - [auth.settings.set](https://docs.trylath.com/api-reference/auth/authsettingsset.md): Changes sign-in settings for this environment. Objects merge key by key; redirect.allowedOrigins replaces the whole list. Takes effect on the next request. Ranges: code.length 4–8, code.ttlSeconds 60–1800, code.maxAttempts 3–10, link.ttlSeconds 60–3600, session.accessTtlSeconds 300–3600, session.ref… - [auth.signin.start](https://docs.trylath.com/api-reference/auth/authsigninstart.md): Begins a sign-in for an end user: creates a one-time code or link, queues the message from the project's default sender, and returns the challenge id. Never reveals whether the user already exists. - [auth.signin.verify](https://docs.trylath.com/api-reference/auth/authsigninverify.md): Completes a sign-in with the code or link token. Creates the user and a verified identity on first sign-in, then issues a session: a short-lived access token and a rotating refresh token. When the user has a second factor (or the environment requires one), returns mfa.mfaToken instead of a session;… - [auth.signingKey.list](https://docs.trylath.com/api-reference/auth/authsigningkeylist.md): Lists the environment's JWT signing keys, newest first: which one is signing now, which are still accepted for verification, and which are retired. Never returns a private key. - [auth.signingKey.retire](https://docs.trylath.com/api-reference/auth/authsigningkeyretire.md): Retires a signing key: it leaves the JWKS and any access token still signed by it stops verifying at once. Do this an access-token lifetime after rotating for routine hygiene, or immediately if the key may have been exposed. The active key cannot be retired. - [auth.signingKey.rotate](https://docs.trylath.com/api-reference/auth/authsigningkeyrotate.md): Mints a new JWT signing key and signs everything from now on with it. Nobody is signed out: tokens signed by the previous key keep verifying until that key is retired, which is a separate act. Rotating twice in a row leaves three keys in the JWKS, which is fine and is why retire exists. - [auth.user.ban](https://docs.trylath.com/api-reference/auth/authuserban.md): Bans a user: every session is revoked now and sign-in is refused until unbanned. - [auth.user.create](https://docs.trylath.com/api-reference/auth/authusercreate.md): Creates an end user with a verified email and/or phone identity, without a sign-in. Use it to import users or pre-provision accounts. - [auth.user.delete](https://docs.trylath.com/api-reference/auth/authuserdelete.md): Deletes a user: sessions revoked, identities released so the email or phone can sign up again as a new person, the row kept for audit and hidden from reads. - [auth.user.export](https://docs.trylath.com/api-reference/auth/authuserexport.md): Exports users in full — identities, custom fields, ban state and organization memberships — oldest first, paging with `after` until it returns fewer than `limit`. Credentials are never included: password hashes, passkeys and authenticator secrets belong to the person and are useless anywhere else. D… - [auth.user.get](https://docs.trylath.com/api-reference/auth/authuserget.md): Returns one user with their identities, and a count of what they can sign in with: passkeys, active authenticators, whether a password is set, and how many recovery codes remain. Those are read-only here — adding or removing any of them is the person's own act, through an access token they hold. - [auth.user.impersonate](https://docs.trylath.com/api-reference/auth/authuserimpersonate.md): Issues an access token that acts as this user, for support. A reason is required and is recorded on the session and in the audit trail. The session says 'impersonation' in the token's amr, never carries the user's MFA state, lasts at most thirty minutes whatever the environment's session lifetime is… - [auth.user.list](https://docs.trylath.com/api-reference/auth/authuserlist.md): Lists users newest first. `query` matches the start of an email, phone or display name. - [auth.user.me](https://docs.trylath.com/api-reference/auth/authuserme.md): Returns the signed-in end user behind an access token: id, email, phone, display name, custom fields and identities. The token is the proof, so a browser or app calls this with the publishable key. A revoked session is refused. - [auth.user.unban](https://docs.trylath.com/api-reference/auth/authuserunban.md): Lifts a ban. Existing sessions stay revoked; the user signs in again. - [auth.user.update](https://docs.trylath.com/api-reference/auth/authuserupdate.md): Changes a user's display name, language or custom fields. Custom fields are replaced as a whole; set locale to null to go back to not knowing. - [auth.user.updateMe](https://docs.trylath.com/api-reference/auth/authuserupdateme.md): Lets the signed-in end user change their own display name and language. Custom fields stay the application's to set (auth.user.update with a key). The access token is the proof. - [email.automation.activate](https://docs.trylath.com/api-reference/email/emailautomationactivate.md): Turns an automation on. Refused with the first readiness problem while any send in it cannot go out. From then on every matching event enrols its contact and the worker advances runs. - [email.automation.archive](https://docs.trylath.com/api-reference/email/emailautomationarchive.md): Retires an automation: no new enrolments, every run in progress is cancelled, the definition and history stay readable. - [email.automation.create](https://docs.trylath.com/api-reference/email/emailautomationcreate.md): Creates an automation as a draft: an event that enrols a contact, an optional payload filter, and a tree of steps (wait, send, branch on a contact property, consent or event field, property.set). Returns readiness problems (unverified sender, unknown topic, unpublished template, missing legal addres… - [email.automation.get](https://docs.trylath.com/api-reference/email/emailautomationget.md): Returns one automation with its readiness and run counts by status. - [email.automation.list](https://docs.trylath.com/api-reference/email/emailautomationlist.md): Lists automations newest first, archived ones only when asked. - [email.automation.pause](https://docs.trylath.com/api-reference/email/emailautomationpause.md): Stops new enrolments and freezes runs in progress where they are; activate again to resume them. - [email.automation.run.cancel](https://docs.trylath.com/api-reference/email/emailautomationruncancel.md): Stops one contact's run where it is. Messages already queued by earlier steps are not recalled. - [email.automation.run.list](https://docs.trylath.com/api-reference/email/emailautomationrunlist.md): Lists runs newest first, filtered by automation, contact or status. Each run carries its position in the step tree and the log of every step taken with its outcome. - [email.automation.update](https://docs.trylath.com/api-reference/email/emailautomationupdate.md): Changes an automation's name, trigger, steps or re-entry rule. Runs already in progress keep the steps they started with only until their next step, so change an active automation with care; pause it first if the tree changes shape. - [email.broadcast.cancel](https://docs.trylath.com/api-reference/email/emailbroadcastcancel.md): Cancels a broadcast: a draft is closed, and any of its messages still queued (not yet handed to delivery) are cancelled. Messages already sent are not recalled. - [email.broadcast.create](https://docs.trylath.com/api-reference/email/emailbroadcastcreate.md): Creates a marketing broadcast as a draft: a published template sent from a verified domain to every contact with current consent for a topic, optionally narrowed by a segment. Returns readiness problems (unverified sender, missing legal address, unknown topic) so they can be fixed before email.broad… - [email.broadcast.get](https://docs.trylath.com/api-reference/email/emailbroadcastget.md): Returns a broadcast with its status, the fan-out counts (recipients, queued, suppressed, held), and — once sent — `progress`: what has actually become of its messages, counted live from the messages themselves, so delivered and bounced totals keep moving as receipts arrive. For drafts, returns what… - [email.broadcast.list](https://docs.trylath.com/api-reference/email/emailbroadcastlist.md): Lists broadcasts newest first. - [email.broadcast.pause](https://docs.trylath.com/api-reference/email/emailbroadcastpause.md): Holds a broadcast that is sending: its messages that have not yet been handed to delivery stop, and nothing else about it changes. Messages already sent are not recalled. email.broadcast.resume releases them. - [email.broadcast.resume](https://docs.trylath.com/api-reference/email/emailbroadcastresume.md): Releases a paused broadcast: its held messages go back in the queue and send from where they stopped. Nobody is sent to twice — the messages that already went are untouched, and the audience policy is checked again for each one at send. - [email.broadcast.send](https://docs.trylath.com/api-reference/email/emailbroadcastsend.md): Sends a draft broadcast: refuses unless the sender is on a verified domain, the template is published, the topic exists and the footer has a postal address; then queues one message per consenting, unsuppressed contact with the contact's properties as variables and a personal unsubscribe link. Schedu… - [email.broadcast.update](https://docs.trylath.com/api-reference/email/emailbroadcastupdate.md): Changes a draft broadcast. Sent or cancelled broadcasts cannot change. An omitted field keeps its stored value; the three optional ones — subject, segmentId and scheduledAt — accept null to clear them, which is how a schedule is cancelled or a segment widened back to everyone with consent for the to… - [email.domain.add](https://docs.trylath.com/api-reference/email/emaildomainadd.md): Adds a domain you own for sending. Returns the DNS records to create: three required (DKIM, return-path MX, return-path SPF) and two recommended (SPF, DMARC). Verify with email.domain.verify once they resolve; marketing sends need a verified domain. - [email.domain.get](https://docs.trylath.com/api-reference/email/emaildomainget.md): Returns one sending domain: status, the DNS records to create, the last check per record, and the blocker if any. - [email.domain.list](https://docs.trylath.com/api-reference/email/emaildomainlist.md): Lists the project's sending identities: the default identity every project has, and every added domain with its status. - [email.domain.receiving.set](https://docs.trylath.com/api-reference/email/emaildomainreceivingset.md): Turns receiving on or off for a verified domain. Turning it on adds one more DNS record — an MX on the domain itself — and returns it. That record replaces wherever this domain's mail goes today: every message anybody sends to any address at this domain arrives at Lath, is stored, and reaches your w… - [email.domain.remove](https://docs.trylath.com/api-reference/email/emaildomainremove.md): Retires a sending domain. Messages already queued from it are unaffected; new sends from it are refused. The DNS records can be deleted afterwards. - [email.domain.verify](https://docs.trylath.com/api-reference/email/emaildomainverify.md): Looks the domain's DNS records up right now and reports each one. Flips the domain to verified when every required record resolves, or names exactly what is missing. - [email.inbound.delete](https://docs.trylath.com/api-reference/email/emailinbounddelete.md): Deletes a received message's contents: bodies, headers, attachments and every recipient beyond the one it was addressed to. The record that it arrived — from whom, to what, and when — is kept, because that is what answers a later question about whether it was received. It disappears from email.inbou… - [email.inbound.get](https://docs.trylath.com/api-reference/email/emailinboundget.md): Returns one received message in full: text and HTML bodies, every header, every recipient, and attachments with their content as base64. - [email.inbound.list](https://docs.trylath.com/api-reference/email/emailinboundlist.md): Lists messages received on this project's verified domains, newest first, as summaries: sender, recipient, subject, attachment count, a text preview. Filter by domain, recipient or sender. - [email.message.cancel](https://docs.trylath.com/api-reference/email/emailmessagecancel.md): Stops an email that has not left yet. A queued message — including one held by sendAfter — is cancelled and never sent. A message already handed to the mail provider cannot be recalled and is refused with its current status, since saying otherwise would be a lie about something the recipient may alr… - [email.message.get](https://docs.trylath.com/api-reference/email/emailmessageget.md): Returns one email message: recipient, sender, subject, template, current status, any error, and the rendered bodies. A message reaches 'sent' when the provider accepts it, and 'delivered', 'bounced' or 'complained' when the provider's notification says what became of it; deliveredAt, vendorStatus an… - [email.message.list](https://docs.trylath.com/api-reference/email/emailmessagelist.md): Lists email messages newest first, optionally filtered by status, recipient, template, broadcast or contact. `contactId` matches mail linked to that contact and mail merely addressed to their email, which is how a message sent before the contact existed is still theirs. Bodies are not included; use… - [email.send](https://docs.trylath.com/api-reference/email/emailsend.md): Sends one transactional email to one recipient, from the project's default sender, either from a named template with variables or from inline subject and body. Asks the audience policy first: a suppressed address is recorded as suppressed, not sent. Returns the message id and its status. - [email.sender.get](https://docs.trylath.com/api-reference/email/emailsenderget.md): Returns the project's own sending identity on the shared parent: the full address, its local part, the subdomain it sits on, and the display name that appears beside it. Any address on this subdomain may be used as a sender without verifying anything, because the parent is already a verified identit… - [email.sender.set](https://docs.trylath.com/api-reference/email/emailsenderset.md): Changes the project's sending identity on the shared parent: the local part before the @, the subdomain label, and the display name. Every field is optional; omitted fields are left alone. Changing the label changes the address every future message comes from, and frees the old one for reuse by anot… - [email.template.delete](https://docs.trylath.com/api-reference/email/emailtemplatedelete.md): Removes a custom template (all versions become history). Without a `locale` it removes every language variant; with one it removes only that translation and the others keep sending. A reserved name goes back to its built-in default. Messages already queued keep the body they were rendered with. - [email.template.get](https://docs.trylath.com/api-reference/email/emailtemplateget.md): Returns a named template: the published version and draft of one language variant, every locale that has a variant, and for reserved names the built-in default and the variables it needs. - [email.template.list](https://docs.trylath.com/api-reference/email/emailtemplatelist.md): Lists every email template in the project, including the reserved sign-in templates, whether each is the default or a custom version, and which language variants exist. Version and draft numbers describe the default variant; `locales` names the translations. - [email.template.preview](https://docs.trylath.com/api-reference/email/emailtemplatepreview.md): Renders a template with the given variables exactly as email.send would, including the brand frame, without sending. Give a `locale` to see what a recipient in that language gets, including which variant the fallback chose. Reports any variables the template needs that were not supplied. - [email.template.publish](https://docs.trylath.com/api-reference/email/emailtemplatepublish.md): Makes the draft of a named template the version email.send and sign-in messages use from now on. Publishes one language variant; the others are untouched. The previous published version is kept as history. - [email.template.set](https://docs.trylath.com/api-reference/email/emailtemplateset.md): Saves a new draft version of a named email template: subject, HTML and text with {{variables}}, {{#if}} and {{#each}}. Give a `locale` to write that language's variant; each language has its own versions and publishes on its own. Refuses syntax errors with line numbers. Nothing is sent from a draft… - [sms.broadcast.cancel](https://docs.trylath.com/api-reference/sms/smsbroadcastcancel.md): Cancels an SMS broadcast: a draft is closed, and any of its messages still queued (not yet handed to the carrier) are cancelled. Messages already sent cannot be recalled. - [sms.broadcast.create](https://docs.trylath.com/api-reference/sms/smsbroadcastcreate.md): Creates an SMS marketing broadcast as a draft: a published SMS template sent to every contact with current SMS consent for a topic, optionally narrowed by a segment. There is no sender to choose — the number belongs to the deployment. Returns readiness problems (unknown topic, unpublished template,… - [sms.broadcast.get](https://docs.trylath.com/api-reference/sms/smsbroadcastget.md): Reads one SMS broadcast with its readiness problems and, once sent, its counts. - [sms.broadcast.list](https://docs.trylath.com/api-reference/sms/smsbroadcastlist.md): Lists SMS broadcasts, newest first. Email broadcasts are not included; they are email.broadcast.list. - [sms.broadcast.pause](https://docs.trylath.com/api-reference/sms/smsbroadcastpause.md): Holds an SMS broadcast that is sending: its messages not yet handed to the carrier stop, and nothing else about it changes. Messages already sent cannot be recalled. sms.broadcast.resume releases them. - [sms.broadcast.resume](https://docs.trylath.com/api-reference/sms/smsbroadcastresume.md): Releases a paused SMS broadcast: its held messages go back in the queue. A message a quiet-hours rule had held until morning keeps that time — resuming does not send a text at midnight. - [sms.broadcast.send](https://docs.trylath.com/api-reference/sms/smsbroadcastsend.md): Sends a draft SMS broadcast: refuses unless the template is published, carries STOP wording and fits in the segment limit, and the topic exists; then queues one message per consenting, unsuppressed contact with a phone number, using the contact's properties as variables. Billing counts real segments… - [sms.broadcast.update](https://docs.trylath.com/api-reference/sms/smsbroadcastupdate.md): Changes a draft SMS broadcast. A broadcast that has been sent or cancelled cannot change; create a new one. - [sms.conversation.get](https://docs.trylath.com/api-reference/sms/smsconversationget.md): Reads one SMS conversation: every message exchanged with one number, oldest first, with the direction of each. Reply with sms.send to the same number — a reply is an ordinary message, and routing it through the same operation keeps consent, segment counting and quiet hours in one place. - [sms.conversation.list](https://docs.trylath.com/api-reference/sms/smsconversationlist.md): Lists SMS conversations, most recently active first: one row per number this environment has exchanged messages with, carrying the latest message, its direction, and how many have gone each way. A conversation with an unanswered inbound message is the one worth looking at, so `awaitingReply` says wh… - [sms.message.cancel](https://docs.trylath.com/api-reference/sms/smsmessagecancel.md): Stops a message that has not left yet. A queued message — including one held by sendAfter — is cancelled and never sent, and its billing counter is credited back. A message already handed to the carrier cannot be recalled and is refused with its current status, since saying otherwise would be a lie… - [sms.message.get](https://docs.trylath.com/api-reference/sms/smsmessageget.md): Returns one SMS: recipient, body, current status, the carrier's reference once it has one, how many attempts it has taken, and any error in the carrier's own words. A message reaches 'sent' when the carrier accepts it and 'delivered' or 'bounced' when the carrier's status callback says what became o… - [sms.message.list](https://docs.trylath.com/api-reference/sms/smsmessagelist.md): Lists SMS newest first, optionally filtered by status or recipient. `nextBefore` continues from where a page ended. - [sms.number.list](https://docs.trylath.com/api-reference/sms/smsnumberlist.md): Lists the phone numbers this environment sends from, including one still being assigned. A number belongs to one environment, which is how an inbound message — a STOP, a HELP, a reply — is attributed to the right tenant. Status is `pending` while the carrier is being asked, `active` once it can send… - [sms.registration.get](https://docs.trylath.com/api-reference/sms/smsregistrationget.md): Returns this project's carrier registration and, in one field, what is stopping SMS from sending. 'blocker' is null only when the registration is active. - [sms.registration.submit](https://docs.trylath.com/api-reference/sms/smsregistrationsubmit.md): Files this project's carrier registration, or refiles it when the carrier asked for changes. US carriers refuse application-to-person traffic from an unregistered sender, so SMS cannot send until this reaches 'active'. A sole_proprietor brand needs no tax id and carries lower throughput; a standard… - [sms.send](https://docs.trylath.com/api-reference/sms/smssend.md): Sends one SMS to one number in E.164 form, from the environment's configured sender. The body may carry {{variables}}. Asks the audience policy first: a number that has replied STOP is recorded as suppressed, not sent. Billing counts segments, not messages — a body outside the GSM alphabet costs mor… - [sms.settings.get](https://docs.trylath.com/api-reference/sms/smssettingsget.md): Returns this environment's SMS settings with defaults filled in. Quiet hours are the window in which marketing texts are held rather than sent, judged in the recipient's own timezone (their contact property if set, otherwise the environment's). Transactional messages — anything sent without a consen… - [sms.settings.reset](https://docs.trylath.com/api-reference/sms/smssettingsreset.md): Returns every SMS setting in this environment to its default. Quiet hours go back to on, 21:00–08:00, with no timezone — which stops marketing sends until one is set. - [sms.settings.set](https://docs.trylath.com/api-reference/sms/smssettingsset.md): Changes SMS settings for this environment; keys not mentioned are left alone. Quiet hours hold marketing texts until the window opens in the recipient's local time rather than dropping them; times are 24-hour HH:MM and the window may wrap midnight, and setting timezone to null clears it, which stops… - [sms.template.delete](https://docs.trylath.com/api-reference/sms/smstemplatedelete.md): Removes an SMS template. Without a `locale` it removes every language variant; with one it removes only that translation and the others keep sending. A reserved name reverts to the built-in text rather than disappearing, since the message it carries still has to be sent. Versions already used by mes… - [sms.template.get](https://docs.trylath.com/api-reference/sms/smstemplateget.md): Returns one SMS template: the published version and unpublished draft of one language variant, every locale that has a variant, the variables each references, and the segment count each costs. A reserved name with nothing saved returns the built-in default, marked as such, so it can be read before i… - [sms.template.list](https://docs.trylath.com/api-reference/sms/smstemplatelist.md): Lists this project's SMS templates with the published version and any unpublished draft, which language variants exist, and includes reserved names that have not been overridden so the built-in sign-in text is visible rather than invisible. Version numbers describe the default variant; `locales` nam… - [sms.template.preview](https://docs.trylath.com/api-reference/sms/smstemplatepreview.md): Renders an SMS template with the variables given and returns the exact body that would be sent, its encoding and its segment count, without sending anything or spending anything. Names any variable the template needs and the call did not supply. - [sms.template.publish](https://docs.trylath.com/api-reference/sms/smstemplatepublish.md): Publishes the current draft of an SMS template. From then on sms.send with this template name uses it. Publishes one language variant; the others are untouched. The previously published version is archived and kept. - [sms.template.set](https://docs.trylath.com/api-reference/sms/smstemplateset.md): Saves a new draft version of a named SMS template: one body with {{variables}}, {{#if}} and {{#each}}. Give a `locale` to write that language's variant; each language has its own versions and publishes on its own. Refuses syntax errors with line numbers. Reports the segment count the body will cost,… - [audience.consent.grant](https://docs.trylath.com/api-reference/audience/audienceconsentgrant.md): Records that a contact opted in to a channel and topic, storing what they were shown and where. A fresh grant lifts an unsubscribe or STOP suppression on that address. It does not lift a bounce or a complaint: those are facts about deliverability rather than permission, and only the person acting th… - [audience.consent.list](https://docs.trylath.com/api-reference/audience/audienceconsentlist.md): Returns the full consent history for a contact, newest first, for proving opt-in when asked. - [audience.consent.revoke](https://docs.trylath.com/api-reference/audience/audienceconsentrevoke.md): Records that a contact opted out of a channel and topic. Appends to the history; the previous grant is not erased. - [audience.contact.create](https://docs.trylath.com/api-reference/audience/audiencecontactcreate.md): Creates a contact with an email and/or phone, an optional language and optional properties. The language decides which template variant they receive. Consent is recorded separately with audience.consent.grant. - [audience.contact.delete](https://docs.trylath.com/api-reference/audience/audiencecontactdelete.md): Deletes a contact. The row is kept for audit; its addresses are released and its consent history stays readable through the ledger. - [audience.contact.export](https://docs.trylath.com/api-reference/audience/audiencecontactexport.md): Exports contacts in full — properties, locale, the linked user, and every consent record for each — oldest first, paging with `after` until it returns fewer than `limit`. An audience without its consent history cannot lawfully be mailed by anyone, so the two travel together. - [audience.contact.get](https://docs.trylath.com/api-reference/audience/audiencecontactget.md): Returns one contact with the current consent per channel and topic, and any active suppressions on its addresses. - [audience.contact.import](https://docs.trylath.com/api-reference/audience/audiencecontactimport.md): Imports up to 1,000 contacts, merging by email or phone. A row grants marketing consent only if it carries a consentSource or the batch carries an attestation; rows with neither import without consent and are counted. Purchased or scraped lists are prohibited. - [audience.contact.list](https://docs.trylath.com/api-reference/audience/audiencecontactlist.md): Lists contacts newest first. `query` matches the start of an email or phone. - [audience.contact.update](https://docs.trylath.com/api-reference/audience/audiencecontactupdate.md): Changes a contact's email, phone, language or properties. Properties are merged key by key; set a key to null to remove it, and set locale to null to go back to not knowing. - [audience.optin.get](https://docs.trylath.com/api-reference/audience/audienceoptinget.md): The complete opt-in record for one address: every consent grant and revocation with the wording shown, the source and the time; the suppression history including STOP, START, bounces and complaints; and whether a message may be sent right now for each topic, transactional and marketing. Keyed by the… - [audience.preferences.get](https://docs.trylath.com/api-reference/audience/audiencepreferencesget.md): Public, for the hosted preferences page: given the token from a message's unsubscribe link, returns the project name, the contact's masked email and phone, and per channel — email and sms — every topic and whether the contact is subscribed to it. A channel the contact has no address for is still des… - [audience.preferences.set](https://docs.trylath.com/api-reference/audience/audiencepreferencesset.md): Public, for the hosted preferences page and one-click unsubscribe: given the token from a message's link, subscribes or unsubscribes the contact per topic on either channel, or unsubscribes from all marketing on one. Every change is an appended consent record naming the preference page as its source… - [audience.segment.create](https://docs.trylath.com/api-reference/audience/audiencesegmentcreate.md): Saves a segment: a named filter over contacts by property, address, consent and creation time. - [audience.segment.delete](https://docs.trylath.com/api-reference/audience/audiencesegmentdelete.md): Deletes a segment. Contacts are untouched. - [audience.segment.get](https://docs.trylath.com/api-reference/audience/audiencesegmentget.md): Returns one segment's name and definition. - [audience.segment.list](https://docs.trylath.com/api-reference/audience/audiencesegmentlist.md): Lists this environment's segments. - [audience.segment.preview](https://docs.trylath.com/api-reference/audience/audiencesegmentpreview.md): Counts the contacts a segment matches and returns a small sample, without sending anything. Pass a saved segmentId or an inline definition. - [audience.segment.update](https://docs.trylath.com/api-reference/audience/audiencesegmentupdate.md): Changes a segment's name or definition. - [audience.suppression.add](https://docs.trylath.com/api-reference/audience/audiencesuppressionadd.md): Adds an address to the suppression list so no channel sends to it. Use for a manual do-not-contact or a recorded unsubscribe. - [audience.suppression.lift](https://docs.trylath.com/api-reference/audience/audiencesuppressionlift.md): Lifts a suppression you added by hand or from an unsubscribe. Bounce and complaint suppressions cannot be lifted this way: they lift only when the person opts in again through audience.consent.grant. - [audience.suppression.list](https://docs.trylath.com/api-reference/audience/audiencesuppressionlist.md): Lists active suppressions in this environment, newest first, optionally by channel or reason. - [audience.topic.archive](https://docs.trylath.com/api-reference/audience/audiencetopicarchive.md): Retires a topic: it disappears from lists, from the hosted preference page, and from what a broadcast may be sent to. Nothing is deleted — the key and every consent record naming it stay exactly as they are, because those are what proves somebody agreed to be mailed. audience.topic.restore brings it… - [audience.topic.create](https://docs.trylath.com/api-reference/audience/audiencetopiccreate.md): Creates a subscription topic. A topic is a name to record consent against; creating one subscribes nobody. Every contact reached under it needs its own consent grant, because that is the only thing a send checks. - [audience.topic.list](https://docs.trylath.com/api-reference/audience/audiencetopiclist.md): Lists this environment's subscription topics, each with how many contacts currently consent to it on each channel — the number that decides what a broadcast to it would actually reach, and which no surface reported. - [audience.topic.restore](https://docs.trylath.com/api-reference/audience/audiencetopicrestore.md): Brings an archived topic back. It keeps its original key, so the consent already recorded against it counts again exactly as it did before. - [audience.topic.update](https://docs.trylath.com/api-reference/audience/audiencetopicupdate.md): Changes a topic's name or description. The key does not change. - [developers.activity.list](https://docs.trylath.com/api-reference/developers/developersactivitylist.md): Lists what happened in this environment, newest first, with who or which key did it. - [developers.agent.config](https://docs.trylath.com/api-reference/developers/developersagentconfig.md): Returns the ways an agent connects: the MCP endpoint and header, ready-made Claude Code and Cursor snippets, the CLI install line, and the OpenAPI URL. Contains a placeholder, never a real key. - [developers.agent.prompt](https://docs.trylath.com/api-reference/developers/developersagentprompt.md): Returns the paste-in instructions for an agent without MCP: every operation with its fields, how to authenticate, the error shape, worked examples, and this environment's current state. Regenerated on every call. - [developers.events.list](https://docs.trylath.com/api-reference/developers/developerseventslist.md): Lists state-change events in this environment, newest first, optionally filtered by type and by the subject they are about — pass `subjectId` with a message, contact, user, broadcast or endpoint id to get that thing's timeline rather than the environment's. - [developers.events.types](https://docs.trylath.com/api-reference/developers/developerseventstypes.md): Lists every event type Lath emits, grouped by product, with the wildcard term that covers each group. These are exactly the values developers.webhook.create accepts — anything else is refused rather than silently never delivered. - [developers.key.create](https://docs.trylath.com/api-reference/developers/developerskeycreate.md): Creates a key in this environment. A secret key carries the named permissions and stays on your server. A publishable key (kind: publishable, no permissions) is safe in a browser or CLI: it reaches only the end-user sign-in operations. The plaintext is returned once and never again. - [developers.key.list](https://docs.trylath.com/api-reference/developers/developerskeylist.md): Lists the keys in this environment, including revoked ones. Never returns a plaintext or a hash. - [developers.key.revoke](https://docs.trylath.com/api-reference/developers/developerskeyrevoke.md): Revokes a key immediately. Refused if it is the last key with developers:write in this environment. - [developers.key.rotate](https://docs.trylath.com/api-reference/developers/developerskeyrotate.md): Issues a new key with the same name and permissions and revokes the old one in the same transaction. The new plaintext is returned once. - [developers.key.update](https://docs.trylath.com/api-reference/developers/developerskeyupdate.md): Renames a key or changes the permissions it carries, in place. The key itself is untouched, so nothing has to be redeployed and no request fails while it happens. The new permissions take effect on the next request. A publishable key's one permission cannot be changed, permissions can only be set to… - [developers.webhook.create](https://docs.trylath.com/api-reference/developers/developerswebhookcreate.md): Registers a webhook endpoint for this environment. Empty eventTypes means every event. The signing secret is returned once and never again. - [developers.webhook.deliveries.list](https://docs.trylath.com/api-reference/developers/developerswebhookdeliverieslist.md): Lists webhook deliveries in this environment, newest first, with status, attempt count and the last response. - [developers.webhook.delivery.get](https://docs.trylath.com/api-reference/developers/developerswebhookdeliveryget.md): Returns one webhook delivery by the id in its lath-delivery-id header: which endpoint and event it is for, its status, when it will next be attempted, and every attempt made on it with the response code, the error and how long the receiver took. The event's own type and payload come with it, so a re… - [developers.webhook.disable](https://docs.trylath.com/api-reference/developers/developerswebhookdisable.md): Disables a webhook endpoint: no new deliveries are created for it, and any already queued or waiting to retry stop being attempted. They stay readable, and re-enabling the endpoint lets them resume. Returns how many were holding. - [developers.webhook.enable](https://docs.trylath.com/api-reference/developers/developerswebhookenable.md): Re-enables a disabled webhook endpoint. New events reach it again, and any deliveries that were holding while it was off are attempted from now — they were kept, not discarded. Returns how many resume. - [developers.webhook.list](https://docs.trylath.com/api-reference/developers/developerswebhooklist.md): Lists webhook endpoints in this environment, including disabled ones. Never returns a secret. - [developers.webhook.replay](https://docs.trylath.com/api-reference/developers/developerswebhookreplay.md): Requeues a failed or dead delivery for immediate retry with a fresh attempt count. Refused while its endpoint is disabled, since the point of disabling one is that nothing more reaches it. - [developers.webhook.replayDead](https://docs.trylath.com/api-reference/developers/developerswebhookreplaydead.md): Requeues dead deliveries in bulk after an endpoint has recovered, oldest first, with a fresh attempt count. Bounded per call — pointing an entire backlog at an endpoint that has just come back is how a recovery becomes a second outage — and the reply says how many remain so the rest can follow at yo… - [developers.webhook.secret.rotate](https://docs.trylath.com/api-reference/developers/developerswebhooksecretrotate.md): Issues a new signing secret for a webhook endpoint and returns it once, exactly as create does. The old secret stops verifying immediately: signing happens when a delivery is attempted, so everything after this — including retries of earlier failures — carries the new one. Update your receiver promp… - [developers.webhook.test](https://docs.trylath.com/api-reference/developers/developerswebhooktest.md): Emits a developers.webhook.test event so the endpoint receives one real, signed delivery through the normal path. Returns the event id to look for. - [developers.webhook.update](https://docs.trylath.com/api-reference/developers/developerswebhookupdate.md): Changes a webhook endpoint's URL, event filter or description. The secret does not change. - [billing.cap.get](https://docs.trylath.com/api-reference/billing/billingcapget.md): Returns the project's monthly spending cap in cents (null when none), this month's live metered spend so far (emails and SMS segments; active users are billed monthly and cannot be refused, so they are outside the cap), and whether the cap is currently enforced. A cap is enforced only when the deplo… - [billing.cap.set](https://docs.trylath.com/api-reference/billing/billingcapset.md): Sets or clears the project's monthly spending cap on metered sends (emails and SMS segments). With a cap set and rates published, any send or broadcast that would carry the live environment past the cap is refused with spending_cap_reached and nothing is queued. Pass null to remove the cap. - [billing.credit.list](https://docs.trylath.com/api-reference/billing/billingcreditlist.md): Lists this account's credits, refunds and adjustments, newest first, with what each one reverses. `outstandingCents` is what is left to come off future invoices: credits that have not been reversed and are not tied to a month already invoiced. - [billing.credit.record](https://docs.trylath.com/api-reference/billing/billingcreditrecord.md): Records a credit, refund or adjustment against this account. Append-only: nothing here is edited or deleted, and a mistake is corrected by recording its reverse. The amount is always positive; the kind says which direction it goes. - [billing.credit.reverse](https://docs.trylath.com/api-reference/billing/billingcreditreverse.md): Reverses a credit that should not have been given, by recording its opposite and joining the two. Neither row is altered: the ledger shows what was decided, then what was decided instead. A credit can be reversed once. - [billing.invoice.get](https://docs.trylath.com/api-reference/billing/billinginvoiceget.md): Returns one invoice by calendar month: the amount, the priced lines it was built from, its status, and any reason the last collection attempt failed. - [billing.invoice.list](https://docs.trylath.com/api-reference/billing/billinginvoicelist.md): Lists this account's invoices, newest period first: what was owed for each calendar month, the priced lines that produced it, and what became of the collection attempt. Statuses are open (owed, not yet attempted), paid, failed (the card refused; it will be retried), uncollectible (out of retries) an… - [billing.passthrough.list](https://docs.trylath.com/api-reference/billing/billingpassthroughlist.md): Lists the pass-through fees recorded for a period, newest first, with the provider reference behind each — so a line on a bill can be traced to the charges that made it. - [billing.passthrough.record](https://docs.trylath.com/api-reference/billing/billingpassthroughrecord.md): Records a fee the carrier charged, to be passed through at cost on this environment's bill for the period. Used for carrier registration fees, which have no unit price — the amount is what was actually charged. Recording the same providerRef twice is refused rather than billed twice. This does not m… - [billing.payment.get](https://docs.trylath.com/api-reference/billing/billingpaymentget.md): Returns what card is on file for this account — brand, last four digits and expiry — and whether it is currently working. `status` is none when no card has been added, ok when the last charge went through or none has been attempted, and past_due when a charge was refused. Card numbers are never stor… - [billing.payment.refresh](https://docs.trylath.com/api-reference/billing/billingpaymentrefresh.md): Re-reads the card on file from the payment processor and updates what Lath shows. The processor's callback normally does this within seconds of a card being added; call this to confirm immediately rather than waiting, or after changing the card elsewhere. - [billing.payment.setup](https://docs.trylath.com/api-reference/billing/billingpaymentsetup.md): Starts adding a card to this account. Returns a URL on the payment processor's own hosted page where the card is entered; nothing is charged there, and the card details never reach Lath. Open the URL, complete it, then call billing.payment.get to confirm what is on file. The link is single-use and e… - [billing.usage.get](https://docs.trylath.com/api-reference/billing/billingusageget.md): Returns this project's usage for one calendar month, per environment: emails accepted for sending (sign-in codes, invitations, transactional sends, broadcasts and automations alike), SMS segments, and monthly active end users, each with the published unit rate and amount. Test mode is counted and sh… - [account.close](https://docs.trylath.com/api-reference/account/accountclose.md): Closes the account. Nothing is deleted: messages, consent records and invoices outlive the closure, because a consent audit or a billing dispute arrives after someone leaves. Sending stops, and account.reopen undoes it. - [account.get](https://docs.trylath.com/api-reference/account/accountget.md): Returns the account this key or member belongs to: its name, country, when it was created, and whether it has been closed. Reads nothing about other accounts, because there is no way to name one. - [account.member.accept](https://docs.trylath.com/api-reference/account/accountmemberaccept.md): Public, for the dashboard: accepts an invitation. The token from the invitation link names the invite; the dashboard access token proves the person holds the invited address. The member becomes active and can open the account. - [account.member.invite](https://docs.trylath.com/api-reference/account/accountmemberinvite.md): Invites a person to the account by email with a role, and queues the invitation email (template account.member.invite). Inviting an address that is already invited re-sends the same link. The person becomes active when they accept in the dashboard with a sign-in on that address. - [account.member.list](https://docs.trylath.com/api-reference/account/accountmemberlist.md): Lists the account's members and pending invitations with their roles. - [account.member.remove](https://docs.trylath.com/api-reference/account/accountmemberremove.md): Removes a member or withdraws a pending invitation. Refuses to remove the account's only active owner. Their dashboard sessions end. - [account.member.update](https://docs.trylath.com/api-reference/account/accountmemberupdate.md): Changes a member's role. Refuses to demote the account's only active owner. - [account.reopen](https://docs.trylath.com/api-reference/account/accountreopen.md): Reopens a closed account and lets it send again. The closure and its reason stay in the event log. - [account.signup](https://docs.trylath.com/api-reference/account/accountsignup.md): Creates an account, a project, live and test environments, a secret and a publishable key per environment, and the owner's seat. Keys are returned once and never again and work immediately. The owner seat activates when the person accepts the returned (and emailed) link with a console sign-in on tha… - [account.theme.get](https://docs.trylath.com/api-reference/account/accountthemeget.md): Returns the project's theme: the published version hosted pages render, the draft being edited, the effective values with defaults filled in, and `overrides` — only the keys this project has actually set, which is what an editor needs to tell a customisation from a default. - [account.theme.publish](https://docs.trylath.com/api-reference/account/accountthemepublish.md): Makes the current draft the published theme. Hosted pages and components pick it up on their next request. - [account.theme.reset](https://docs.trylath.com/api-reference/account/accountthemereset.md): Discards the draft, or with `published: true` also unpublishes so end users see the defaults again. - [account.theme.set](https://docs.trylath.com/api-reference/account/accountthemeset.md): Writes a new draft of the project's theme by merging the given tokens and copy over the current draft (or the published version if no draft exists). A key you omit is left alone, a string sets it, and null removes that one override so the key goes back to the default. Refuses any text colour pair be… - [account.update](https://docs.trylath.com/api-reference/account/accountupdate.md): Renames the account or corrects its country. The name appears on invoices and in the dashboard; the country decides carrier and tax treatment, so changing it does not re-file any registration already submitted. - [Liveness and database reachability](https://docs.trylath.com/api-reference/platform/liveness-and-database-reachability.md): Answers 200 with { ok, database } when the database answers, and 503 when it does not. No credential. - [This document](https://docs.trylath.com/api-reference/platform/this-document.md): The OpenAPI description of every route on this deployment. - [Model Context Protocol endpoint](https://docs.trylath.com/api-reference/platform/model-context-protocol-endpoint.md): The same operations as tools, over MCP. Authenticated with a Lath key like any other route. - [The rate book](https://docs.trylath.com/api-reference/platform/the-rate-book.md): What each metered line costs, read from the same `billing_rates` rows an invoice is drawn from, so the published price and the charge cannot disagree. Public and unauthenticated because prices are the same for everybody and because deciding whether to use Lath should not require an account. `publish… - [Public keys for verifying access tokens](https://docs.trylath.com/api-reference/platform/public-keys-for-verifying-access-tokens.md): The JSON Web Key Set an environment's ES256 access tokens are verified against, so a customer's server verifies locally with no round trip. - [The environment's published theme](https://docs.trylath.com/api-reference/platform/the-environments-published-theme.md): The tokens and copy the hosted pages and drop-in components render with. Public because a browser needs it before anyone has signed in. - [The public subset of sign-in settings](https://docs.trylath.com/api-reference/platform/the-public-subset-of-sign-in-settings.md): Which methods a browser should offer, code length and lifetimes, and whether sign-up is open. Public for the same reason as the theme. - [Console bootstrap](https://docs.trylath.com/api-reference/platform/console-bootstrap.md): What the dashboard needs before anyone has signed in. - [Accounts this person can open](https://docs.trylath.com/api-reference/platform/accounts-this-person-can-open.md): The accounts, projects and environments behind the signed-in console session. - [Webhook events](https://docs.trylath.com/reference/webhook-events.md): Every event a webhook endpoint can subscribe to — 158 across 7 products. - [Error codes](https://docs.trylath.com/reference/error-codes.md): Every refusal the API can make — 142 of them, by HTTP status, each with its fix. ## OpenAPI Specs - [openapi](/api-reference/openapi.json)