Dashboard authentication
Sign in to the Tokeflow Dashboard — merchant and organization login, password reset, token refresh, memberships, and switching the active organization.
These endpoints power signing in to the Dashboard. A user logs in as a merchant or organization user, receives a session, and presents it as a bearer token on every subsequent Dashboard call. They also cover the housekeeping around a session: refreshing an expiring token, changing or resetting a password, listing the memberships a user has, and switching which organization is active.
This is distinct from API-key auth. Machine-to-machine calls to the public API use sk_…/pk_… keys and never touch these endpoints; these exist for the human, browser-based Dashboard. Accepting a Dashboard invitation happens here too — see Invitations for the invite lifecycle.
These endpoints are how a person signs in to the Tokeflow Dashboard. They exchange credentials for a session (JWT bearer) — the token every other Dashboard endpoint expects. They are not part of the public API-key surface; a machine integration authenticates with an sk_… key instead. See Authentication.
The login response
Returned by the list and retrieve endpoints on this page.
| Field | Type | Description |
|---|---|---|
user | object | Authenticated merchant user. |
access_token | string | JWT access token. |
refresh_token | string | Refresh token. |
token_type | string | Token type. |
expires_in | number | Token expiration in seconds. |
Endpoints
POST/api/v1/auth/change-password
Auth: Dashboard session (JWT bearer).
Allows users with temporary passwords to change their password before logging in. Required when must_change_password is true.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User email address. |
current_password | string | Yes | Current/temporary password. |
new_password | string | Yes | New password. Password must be 12-128 characters and include a lowercase letter, an uppercase letter and a number. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/change-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "admin@tokeflow.com",
"current_password": "TempPass@2025Xyz",
"new_password": "NewSecurePass@2025"
}'Example response — 200
{}POST/api/v1/auth/forgot-password
Auth: Dashboard session (JWT bearer).
Always returns the same 202 response whether or not the address is registered, so it cannot be used to discover accounts. The per-email limit is enforced in the service; the throttle here is a per-IP backstop.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address of the account to recover. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/forgot-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "user@organization.com"
}'Example response — 202
{
"message": "If an account exists for that email, a password reset link has been sent."
}POST/api/v1/auth/login
Auth: Dashboard session (JWT bearer).
Authenticate internal platform users (super admin, platform admin, support) with email and password. Returns JWT token for subsequent API requests.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User email address. |
password | string | Yes | User password. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/login \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "superadmin@tokeflow.com",
"password": "SuperAdmin@123"
}'Example response — 200
{}POST/api/v1/auth/logout
Auth: Dashboard session (JWT bearer).
Invalidate the current refresh token. The access token will expire naturally.
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/logout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"Example response — 200
{}POST/api/v1/auth/merchant/accept-invitation
Auth: Dashboard session (JWT bearer).
Set a password and activate the merchant_users row associated with the given invitation token. After acceptance the user can log in via /auth/merchant/login.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Invitation token from the welcome email. |
password | string | Yes | New password. Password must be 12-128 characters and include a lowercase letter, an uppercase letter and a number. |
name | string | No | Optional name override (defaults to value captured at invite). |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/merchant/accept-invitation \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"token": "a1b2c3...e9f0",
"password": "StrongP@ssw0rd!",
"name": "Acme Store"
}'Example response — 200
{
"message": "Operation completed successfully",
"email": "jane@example.com"
}POST/api/v1/auth/merchant/change-password
Auth: Dashboard session (JWT bearer).
Queries merchant_users only. The same address can be an independent identity in more than one table, so use the endpoint matching the dashboard the password belongs to — this one for merchant, organization/change-password for org, change-password for admin. Revokes refresh tokens; access tokens expire within 15 minutes.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User email address. |
current_password | string | Yes | Current/temporary password. |
new_password | string | Yes | New password. Password must be 12-128 characters and include a lowercase letter, an uppercase letter and a number. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/merchant/change-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "contact@organization.com",
"current_password": "TempPass@2025Xyz",
"new_password": "NewSecurePass@2025"
}'Example response — 200
{
"message": "Password changed successfully",
"email": "contact@organization.com",
"can_login": true
}POST/api/v1/auth/merchant/forgot-password
Auth: Dashboard session (JWT bearer).
Always returns the same 202 response whether or not the address is registered, so it cannot be used to discover accounts.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address of the account to recover. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/merchant/forgot-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "user@organization.com"
}'Example response — 202
{
"message": "If an account exists for that email, a password reset link has been sent."
}POST/api/v1/auth/merchant/login
Auth: Dashboard session (JWT bearer).
Authenticate users who have been assigned to merchants. Returns JWT token and list of merchant memberships for merchant picker.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Merchant user email address. |
password | string | Yes | Merchant user password. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/merchant/login \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "user@merchant.com",
"password": "Password@123"
}'Example response — 200
{
"user": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "user@merchant.com",
"name": "John Doe",
"merchants": [
{
"membership_id": "f0f524fe-d28f-485b-bc3c-2c6acc26d12b",
"merchant_id": "mrc_abc123",
"merchant_name": "Store XPTO",
"status": "active",
"role": "owner",
"organization_id": "org_xyz",
"organization_name": "Acme Corp"
}
],
"last_login_at": "2026-04-09T10:00:00.000Z"
},
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 900
}GET/api/v1/auth/merchant/memberships
Auth: Dashboard session (JWT bearer).
Returns all merchant memberships for the authenticated user. Used by the frontend to show a merchant context picker.
Example request
curl https://api.tokeflow.com/api/v1/auth/merchant/memberships \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"Example response — 200
{
"memberships": [
{
"membership_id": "f0f524fe-d28f-485b-bc3c-2c6acc26d12b",
"merchant_id": "mrc_abc123",
"merchant_name": "Store XPTO",
"status": "active",
"role": "owner",
"organization_id": "org_xyz",
"organization_name": "Acme Corp"
}
]
}POST/api/v1/auth/organization/change-password
Auth: Dashboard session (JWT bearer).
Queries organization_users only. Allows an organization user with a temporary password to change it before logging in; required when must_change_password is true. Merchant identities use merchant/change-password — the same address can exist independently in both tables.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User email address. |
current_password | string | Yes | Current/temporary password. |
new_password | string | Yes | New password. Password must be 12-128 characters and include a lowercase letter, an uppercase letter and a number. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/organization/change-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "contact@organization.com",
"current_password": "TempPass@2025Xyz",
"new_password": "NewSecurePass@2025"
}'Example response — 200
{}POST/api/v1/auth/organization/forgot-password
Auth: Dashboard session (JWT bearer).
Always returns the same 202 response whether or not the address is registered, so it cannot be used to discover accounts.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address of the account to recover. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/organization/forgot-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "user@organization.com"
}'Example response — 202
{
"message": "If an account exists for that email, a password reset link has been sent."
}POST/api/v1/auth/organization/login
Auth: Dashboard session (JWT bearer).
Authenticate organization users (primary contacts and organization members) with email and password. Returns JWT token with organization memberships.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Organization user email address. |
password | string | Yes | Organization user password. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/organization/login \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"email": "owner@company.com",
"password": "OrgPass@123"
}'Example response — 200
{}POST/api/v1/auth/organization/logout
Auth: Dashboard session (JWT bearer).
Invalidate the current refresh token for an organization user. The access token will expire naturally.
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/organization/logout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"Example response — 200
{}GET/api/v1/auth/organization/memberships
Auth: Dashboard session (JWT bearer).
Returns every organization the authenticated user belongs to. The login response carries the same list, but clients persist only the active organization, so this is how a picker repopulates after a reload.
Example request
curl https://api.tokeflow.com/api/v1/auth/organization/memberships \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"Example response — 200
{
"memberships": [
{
"membership_id": "f0f524fe-d28f-485b-bc3c-2c6acc26d12b",
"organization_id": "org_abc123",
"organization_name": "Acme Corp",
"role": "owner"
}
]
}POST/api/v1/auth/organization/switch
Auth: Dashboard session (JWT bearer).
Re-mints this session against another organization the caller belongs to, returning a new token pair. Authenticated rather than public: the org this returns is the one every subsequent request is scoped to, so the caller must be a verified subject, not merely the holder of a refresh token. 403 if the caller has no membership in the target.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization to make active for this session. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/organization/switch \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"organization_id": "org_abc123"
}'Example response — 200
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900
}POST/api/v1/auth/password-reset/confirm
Auth: Dashboard session (JWT bearer).
Consumes the token, sets the password, clears any lockout, and revokes refresh tokens so existing sessions end. Access tokens already issued remain valid until they expire (15 minutes).
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The token from the emailed reset link. |
new_password | string | Yes | New password. Password must be 12-128 characters and include a lowercase letter, an uppercase letter and a number. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/password-reset/confirm \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"token": "V-9nQ2h1c2VyLXRva2VuLWV4YW1wbGUtdmFsdWU",
"new_password": "CorrectHorse1Battery"
}'Example response — 200
{
"message": "Password reset successfully",
"email": "user@organization.com",
"can_login": true
}POST/api/v1/auth/refresh
Auth: Dashboard session (JWT bearer).
Exchange a valid refresh token for a new access token and refresh token pair (token rotation).
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token | string | Yes | Refresh token issued during login. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/auth/refresh \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'Example response — 200
{}Errors
Errors use the standard envelope. The most common cases here:
| HTTP | Meaning |
|---|---|
400 | Invalid parameters or a state that does not allow this operation. |
401 | Missing, expired, or invalid Dashboard session token. |
403 | Authenticated, but the signed-in user lacks access to this entity. |
404 | The record does not exist or is not visible to this entity. |