Skip to content

Me API

/api/v1/me/* is what a signed-in user calls about themselves. Profile reads and edits, session list and revocation, MFA factor management, password change. Scoped to me:read (reads) and me:write (mutations).

The React SDK wraps these as getProfile(), updateProfile(), listSessions(), etc. — typically you don't call them directly.

GET /api/v1/me/profile
Authorization: Bearer <access-token>
Required scope: me:read
{
"data": {
"id": "usr_01HZX...",
"email": "user@cymmetri.com",
"email_verified": true,
"name": "User Name",
"given_name": "User",
"family_name": "Name",
"picture": "https://...",
"locale": "en-GB",
"attributes": { "department": "finance" },
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-05-17T08:00:00Z"
}
}
PATCH /api/v1/me/profile
Authorization: Bearer <access-token>
Content-Type: application/json
Required scope: me:write
{
"name": "Anita Singh",
"given_name": "Anita",
"family_name": "Singh",
"locale": "en-IN",
"attributes": { "department": "engineering" }
}

Returns the updated profile. Fields not in the body are left alone.

email cannot be patched here — email changes go through a verification flow (see "Change email" below). id and created_at are immutable.

POST /api/v1/me/password
Authorization: Bearer <access-token>
Content-Type: application/json
Required scope: me:write
{
"current": "...",
"next": "..."
}

Returns 204 No Content. The current password is required as a step-up check. If the user is signed in via SSO and has no password, this endpoint returns 400 password_not_set.

POST /api/v1/me/email/change
Authorization: Bearer <access-token>
Content-Type: application/json
Required scope: me:write (+ step-up to AAL 2)
{
"new_email": "anita.singh@cymmetri.com"
}

Sends a verification email to the new address. Returns:

{ "data": { "pending_change_id": "pec_01HZX...", "verified": false } }

The user clicks the link in the email; the platform completes the change. Until they click, the user's email field is unchanged.

POST /api/v1/me/email/resend-verification
Authorization: Bearer <access-token>

For the initial address (the one the user signed up with) — re-sends the verification email. Rate-limited.

GET /api/v1/me/sessions
Authorization: Bearer <access-token>
Required scope: me:read

Each item:

{
"id": "ses_01HZX...",
"current": true,
"created_at": "2026-05-17T08:00:00Z",
"last_active_at": "2026-05-17T08:30:00Z",
"ip": "203.0.113.45",
"ip_geo": { "city": "Bengaluru", "country": "IN" },
"user_agent": "Chrome 132 on macOS",
"device": { "kind": "desktop", "fingerprint": "vis_abc123" }
}

current flags the session the caller is using. Use this to label the "this device" row in a sessions UI.

DELETE /api/v1/me/sessions/{session_id}
Authorization: Bearer <access-token>
Required scope: me:write

Returns 204. Cannot revoke the current session via this endpoint — use /auth/logout for that.

DELETE /api/v1/me/sessions?except=current
Authorization: Bearer <access-token>

Kills every session except the caller's. Used when a user sees an unfamiliar device on their session list and wants a panic button.

GET /api/v1/me/mfa/factors
Authorization: Bearer <access-token>
{
"data": [
{ "id": "factor_01HZX...", "kind": "webauthn", "label": "MacBook Pro", "created_at": "..." },
{ "id": "factor_01HZY...", "kind": "totp", "label": "1Password", "created_at": "..." }
]
}
POST /api/v1/me/mfa/factors/{kind}/begin
Authorization: Bearer <access-token>
Content-Type: application/json

kind is one of webauthn, totp, sms. The response is factor-specific — see the MFA topics.

POST /api/v1/me/mfa/factors/{kind}/complete
Authorization: Bearer <access-token>
Content-Type: application/json

Body shape depends on the factor.

DELETE /api/v1/me/mfa/factors/{factor_id}
Authorization: Bearer <access-token>
Required scope: me:write (+ step-up to AAL 2)

Returns 204. Refusing this endpoint without step-up is the platform's defence against an attacker who got an access token but does not hold the second factor.

POST /api/v1/me/mfa/backup-codes
Authorization: Bearer <access-token>
Required scope: me:write (+ step-up to AAL 2)

Returns ten one-shot codes. The previous set (if any) is invalidated.

{ "data": { "codes": ["a4f2-bk93-...", "h8h2-9p1l-...", ...] } }

Show these to the user exactly once. The platform does not store them in retrievable form.