Auth API Live
The user-facing auth endpoints: sign up a workspace, log in, request a password-reset email, complete a reset, and log out. Rate limits and authentication requirements vary by endpoint; see Errors, rate limits, versioning.
For agent invitations from inside a workspace, see the Agents API. For choosing the right credential type, see the Authentication API.
Register
Creates a new workspace and admin agent in one step. Returns a fresh workspace JWT bound to the new agent. The onboarding wizard at app.message.com/register calls this endpoint.
Request body
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Agent email. Becomes the admin contact for the workspace. |
| passwordrequired | string | At least 12 characters with uppercase and lowercase letters, a number and a symbol; at most 72 UTF-8 bytes. Common passwords are rejected. |
| workspaceNamerequired | string | Display name for the workspace. Shown in the dashboard top bar. |
| namerequired | string | Administrator display name, 1–200 characters. |
| slugrequired | string | Unique workspace address: 3–63 lowercase letters, numbers or dashes. Reserved addresses are rejected. |
| websiteoptional | string | Optional public business website. Do not send siteUrl; that is not a recognized field. |
| timezoneoptional | string | Optional IANA timezone. |
{
"email": "[email protected]",
"password": "Example-Only!47Replace",
"name": "Alex Rivera",
"workspaceName": "Acme Support",
"slug": "acme-support",
"website": "https://acme.com"
}{
"token": "eyJhbGci...",
"onboardingRunId": null,
"website": "https://acme.com",
"slug": "acme-support",
"products": [],
"setupPath": "/setup/start",
"agent": {
"id": "uuid",
"email": "[email protected]",
"name": "Alex Rivera",
"role": "admin",
"workspaceId": "uuid",
"status": "offline"
}
}Login
Exchanges email and password for { token, agent } when no additional verification is required. An account with extra security instead returns { mfaRequired: true, challenge, methods }; do not assume every successful HTTP response contains a token. Use Message.com’s sign-in screen to complete the security challenge. An optional workspaceSlug selects a workspace.
{
"email": "[email protected]",
"password": "your-password"
}Code samples
curl -X POST 'https://app.message.com/api/v1/auth/login' \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"your-password"}'const res = await fetch('https://app.message.com/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const { token, agent } = await res.json();import requests
r = requests.post(
"https://app.message.com/api/v1/auth/login",
json={"email": email, "password": password},
)
token = r.json()["token"]require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/auth/login")
res = Net::HTTP.post(uri, { email: email, password: password }.to_json, "Content-Type" => "application/json")
token = JSON.parse(res.body)["token"]<?php
$ctx = stream_context_create([
"http" => [
"method" => "POST",
"header" => "Content-Type: application/json",
"content" => json_encode(["email" => $email, "password" => $password]),
],
]);
$body = file_get_contents("https://app.message.com/api/v1/auth/login", false, $ctx);
$token = json_decode($body, true)["token"];Forgot password
Sends a password-reset email to the address (if it matches a real agent). Returns HTTP 200 with { ok: true } regardless of whether the email exists, so we do not leak account enumeration.
{ "email": "[email protected]" }The email contains a one-time token that expires in 30 minutes. Each new request invalidates the previous token, so the most recent email is always the valid one.
Reset password
Completes a password reset using the token from the email plus the new password. Returns HTTP 200 with { ok: true }. Existing sessions are revoked; sign in again. It does not return a new token.
{
"token": "the-token-from-the-email",
"newPassword": "Different-Example!83Replace"
}Logout
Revokes the bearer token by bumping the agent's tokenVersion. Returns HTTP 200 with { ok: true }. Logout is global: every device signed in as this agent will be force-logged on next request.
Errors
| Code | When |
|---|---|
400 invalid_body | Payload failed validation (password too weak, email malformed). |
401 invalid_credentials | Email + password mismatch. Generic on purpose. |
409 email_taken | Register: that email is already an agent on another workspace. |
400 invalid_or_expired_token | Reset: the token has expired or was superseded. |
429 rate_limited | Per-IP or per-email cap hit. See rate-limit table. |
Per-route caps
| Endpoint | Cap |
|---|---|
POST /auth/register | 5/min per IP |
POST /auth/login | 20/min per IP, plus email and email/IP failed-attempt lockouts |
POST /auth/forgot-password | 3/min per IP |
POST /auth/reset-password | 5/min per IP |
Common pitfalls
- Treating 401 from
/loginas "wrong password". It might be "email does not exist". We deliberately return one generic error for both. - Storing the password in plaintext anywhere. We bcrypt server-side. Your client should never write the password to disk or to a cookie.
- Showing different UI for "email taken" on register. Pair this with the 409 response and you teach attackers which emails are valid. Use a neutral message on both branches.