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.

FieldTypeDescription
userobjectAuthenticated merchant user.
access_tokenstringJWT access token.
refresh_tokenstringRefresh token.
token_typestringToken type.
expires_innumberToken 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

FieldTypeRequiredDescription
emailstringYesUser email address.
current_passwordstringYesCurrent/temporary password.
new_passwordstringYesNew 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 response200

{}

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

FieldTypeRequiredDescription
emailstringYesEmail 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 response202

{
  "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

FieldTypeRequiredDescription
emailstringYesUser email address.
passwordstringYesUser 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 response200

{}

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 response200

{}

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

FieldTypeRequiredDescription
tokenstringYesInvitation token from the welcome email.
passwordstringYesNew password. Password must be 12-128 characters and include a lowercase letter, an uppercase letter and a number.
namestringNoOptional 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 response200

{
  "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

FieldTypeRequiredDescription
emailstringYesUser email address.
current_passwordstringYesCurrent/temporary password.
new_passwordstringYesNew 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 response200

{
  "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

FieldTypeRequiredDescription
emailstringYesEmail 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 response202

{
  "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

FieldTypeRequiredDescription
emailstringYesMerchant user email address.
passwordstringYesMerchant 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 response200

{
  "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 response200

{
  "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

FieldTypeRequiredDescription
emailstringYesUser email address.
current_passwordstringYesCurrent/temporary password.
new_passwordstringYesNew 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 response200

{}

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

FieldTypeRequiredDescription
emailstringYesEmail 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 response202

{
  "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

FieldTypeRequiredDescription
emailstringYesOrganization user email address.
passwordstringYesOrganization 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 response200

{}

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 response200

{}

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 response200

{
  "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

FieldTypeRequiredDescription
organization_idstringYesThe 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 response200

{
  "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

FieldTypeRequiredDescription
tokenstringYesThe token from the emailed reset link.
new_passwordstringYesNew 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 response200

{
  "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

FieldTypeRequiredDescription
refresh_tokenstringYesRefresh 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 response200

{}

Errors

Errors use the standard envelope. The most common cases here:

HTTPMeaning
400Invalid parameters or a state that does not allow this operation.
401Missing, expired, or invalid Dashboard session token.
403Authenticated, but the signed-in user lacks access to this entity.
404The record does not exist or is not visible to this entity.

On this page