Auth

Create auth session

Create a new passwordless auth session (login). Returns a deep link and QR code for the selected channel. Rate limited: 15 requests per minute per IP.

The email channel additionally honours the account-bootstrap decline cooldown: if the owner of the address used the "this wasn't me" link on a recent message from us, this endpoint answers 429 identity_declined for an hour. That covers sign-in mail as well, so a client should offer the other channels (Telegram, WhatsApp, SMS) rather than retrying.

No credential is required. A client that DOES present an API key (Authorization: Bearer pk_…) — an MCP connection signing in from inside — has it checked: a key the API no longer accepts (unknown, revoked, expired) is refused with 401 invalid_api_key before anything is stored or sent, so a connection whose key was revoked cannot sign back in to the account. A live presented key is recorded on the session, and the user session issued when the sign-in completes is BOUND to it: revoking that key by any path ends the session, and it cannot be refreshed once the key is revoked or expired. If the key is revoked before the person completes the sign-in, no session is issued at all.

ON THE EMAIL CHANNEL A 201 MEANS THE MAIL WAS ACCEPTED FOR DELIVERY. The code and the magic link travel in that message and are returned by nothing, so a session created after a failed send could never be completed — if delivery fails, this endpoint answers 503 challenge_delivery_failed and the session is discarded rather than returning a session to poll. Do not look for an email_sent: false to decide whether to tell someone to check their inbox: on this route a 201 already carries that answer. A field of that name DOES mean something elsewhere — POST /api/v1/accounts (AccountSessionResponse) and POST /api/v1/accounts/{id}/send (its own response shape) split creating a session from mailing it, and report a withheld or failed send that way — but those are different endpoints. This one still carries email_sent on an email-channel 201, where it is ALWAYS true (a failed send never reaches a 201), and it never returns email_error at all. Note that email_sent is NOT part of the declared 201 schema below: AuthSessionResponse is shared with the session-poll and submit operations, which return no such field, so it is documented here rather than declared there — a generated client type for this response will not carry it.

post/api/v1/auth/sessions

Request

  • Base URL: https://api.proof.holdings
  • URL: https://api.proof.holdings/api/v1/auth/sessions
  • Auth: none declared

Request body

channel'telegram' | 'whatsapp' | 'sms' | 'email' required

Authentication channel

phone_numberstring

Required for SMS channel (to determine DID routing)

emailstring email

Required for email channel

return_tostring

Same-origin path on the web app (starting with a single /) that the emailed magic link returns to once it signs the person in; GET /auth/complete/{sessionId} honours it too. A messenger sign-in returns through the starting tab, which polls, so its "Open Dashboard" button still opens the dashboard. A value that is not such a path (an absolute or protocol-relative URL, a backslash, a scheme, over 2048 characters) is ignored rather than refused, and the sign-in then returns to the dashboard.

Example request

{
  "channel": "telegram",
  "phone_number": "+37069199199",
  "email": "user@example.com",
  "return_to": "/oauth/consent?request=mcpr_abc"
}

Response

Auth session created

idstring required
type'login' required
channel'telegram' | 'whatsapp' | 'sms' | 'email' required

Authentication channel

status'pending' | 'verified' | 'expired' required

Status of an auth session

deep_linkstring
qr_codestring

Base64-encoded QR code image

qr_textstring

UTF-8 text representation of the QR code for terminal/agent display

expires_atstring date-time required
instructionsstring
verified_atstring date-time
user_idstring

Example response

{
  "id": "auth_abc123",
  "channel": "telegram",
  "status": "pending",
  "deep_link": "https://t.me/bot?start=auth_abc123",
  "expires_at": "2026-02-13T12:10:00Z",
  "instructions": "Open Telegram and tap the link to log in"
}

Changes

No recorded changes to this operation across all 1 revision of this API.