---
title: "Login"
method: POST
path: "/v1/auth/login"
tags: ["auth"]
---

# Login

`POST /v1/auth/login`

## Request

- Base URL: `https://api.patricia.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.patricia.app/v1/auth/login`
- Auth: none declared

Authenticate with email and password and receive a token pair scoped to one tenant.

## Request body

- LoginRequest: Login payload. ``tenant_id`` optionally selects among the user's tenants.
  - `email` string, email, required
  - `password` string, password, required
  - `tenant_id` string, uuid, nullable: Select which membership tenant to scope the session to. Defaults to the primary tenant.
  - `captcha_token` string

## Response `200`

Access and refresh tokens.

- TokenResponse: Access + refresh token pair. ``expires_in`` is the access-token lifetime (seconds).
  - `access_token` string, required
  - `refresh_token` string, required
  - `token_type` string
  - `expires_in` integer, required
  - `landing_hint` 'pending_invitation' | 'diverted_unknown_workspace': A non-authorization hint explaining WHY a session landed where it did. The dashboard reads it to show the right next step instead of a bare landing. It never grants access: the token's tenant claim (or its absence) is the sole authority. Two values, and they differ in whether the session has a workspace at all: ``PENDING_INVITATION`` lands TENANT-LESS — a returning user with at least one pending invitation and no active available home. It is NOT "only pending memberships": the branch is chosen on ``has_pending`` before the deactivated/unavailable fallback, so a user holding a pending invite alongside deactivated or unavailable ones lands here too. The SSO guard declines to mint an empty duplicate tenant, and the hint points them at accepting the invite / signing in from the connected workspace. ``DIVERTED_UNKNOWN_WORKSPACE`` lands WITH an active workspace — a returning user who signed in from a chat workspace Patricia does not know. The guard diverts them to their existing primary workspace rather than minting a second one, and the hint is what lets the dashboard say so and offer a deliberate way to create a separate workspace instead of failing silently.
  - `decision_key` string, nullable

## Other responses

- `400`: Captcha required or rejected — see ``code`` (``CAPTCHA_REQUIRED`` / ``CAPTCHA_REJECTED``)
- `401`: Invalid credentials or token
- `403`: Not a member of the requested tenant
- `422`: Validation Error
- `429`: Too many attempts against this address (``TOO_MANY_REQUESTS``), or too many requests from this client (``RATE_LIMITED``)
- `502`: Captcha verification unavailable (``CAPTCHA_ERROR``)

---

[API](https://skmtc.dev/patricia/apis/patricia-api.md) · [All operations](https://skmtc.dev/patricia/apis/patricia-api/llms.txt) · [OpenAPI document](https://skmtc.dev/patricia/apis/patricia-api/revisions/0dfb44495ea1?raw)
