Skip to content

Auth — /v1/auth

All auth endpoints live at /v1/auth/. None require an Authorization header unless marked requires session.


Create a new user account and organization.

Request

{
"org_name": "Acme AI",
"email": "you@acme.com",
"password": "min-8-chars"
}

Response 201

{
"user": {
"user_id": "usr_abc123",
"email": "you@acme.com",
"email_verified": false,
"org_id": "org_xyz789"
}
}

Errors

StatusErrorReason
400validation_errorMissing or invalid fields
409Email already registered

A verification email is sent automatically.


Exchange email + password for a signed JWT (valid 24h).

Request

{
"email": "you@acme.com",
"password": "your-password"
}

Response 200

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"user_id": "usr_abc123",
"email": "you@acme.com",
"email_verified": true,
"org_id": "org_xyz789"
}
}

Errors

StatusReason
400Validation error
401Invalid credentials

Requires session. Signals logout — JWT is stateless so the client must discard the token.

Response 200

{ "success": true }

Requires session. Returns the current user and their organization.

Response 200

{
"user": {
"user_id": "usr_abc123",
"email": "you@acme.com",
"email_verified": true,
"org_id": "org_xyz789",
"created_at": "2026-05-01T12:00:00Z"
},
"org": {
"org_id": "org_xyz789",
"name": "Acme AI",
"plan": "starter"
}
}

Confirm an email address using the token from the verification email.

Request

{ "token": "<verification-token>" }

Response 200

{ "success": true }

Errors

StatusReason
400Token missing or malformed
400Token expired or already used

Re-send the email verification link.

Request

{ "email": "you@acme.com" }

Response 200

{ "success": true }

Always returns 200 to prevent email enumeration.


Send a password reset link to the given email address.

Request

{ "email": "you@acme.com" }

Response 200

{ "success": true }

Always returns 200 even if the email doesn’t exist (prevents enumeration). Reset links expire after 1 hour.


Set a new password using a valid reset token.

Request

{
"token": "<reset-token-from-email>",
"password": "new-password-min-8"
}

Response 200

{ "success": true }

Errors

StatusReason
400Validation error
400Token expired or already used

The JWT payload contains:

{
"user_id": "usr_abc123",
"email": "you@acme.com",
"org_id": "org_xyz789",
"iat": 1748390400,
"exp": 1748476800
}

Algorithm: HS256. Expiry: 24 hours.

Pass the token as a Bearer header on session-protected endpoints:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

The same Authorization: Bearer header also accepts ctv_key_… API keys on all non-auth routes — the backend distinguishes by prefix.