Customer Portal sessions and config
How a customer signs in to the portal — the magic-link flow, the current session, bootstrap data, and portal configuration.
The Customer Portal lets a customer manage their own subscriptions and payment methods without contacting support. A session begins with a magic link: the customer requests a link by email, then the verify step exchanges the emailed token for a session cookie. These endpoints cover that handshake, the current session, the bootstrap payload the UI loads first, and the portal's configuration.
Everything else in the portal — subscriptions, payment methods, account — runs on the cookie established here. The portal is white-label, so its branding and allowed actions come from the merchant's portal config.
These endpoints power the Customer Portal — the self-service surface your end customers use, under your brand. They are authenticated by a portal session cookie, established through the magic-link flow (request a link, then verify the token), not by an API key. See Sessions & config.
The portal session
Returned by the list and retrieve endpoints on this page.
| Field | Type | Description |
|---|---|---|
id | string | Portal account id. |
organization_id | string | — |
merchant_id | string | Merchant the session is scoped to. |
email | string | — |
expires_in | number | Session lifetime in seconds. |
Endpoints
GET/api/v1/merchants/:merchant_id/portal-config
Auth: Customer Portal session (cookie set by the magic-link flow).
Branding and behaviour of the self-service portal your customers use to manage their subscriptions. Returns defaults when nothing has been configured yet.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_id | string | Yes | — |
Example request
curl https://api.tokeflow.com/api/v1/merchants/mrc_8a3f12d9/portal-config \
-H "Cookie: tf_portal_session=…"Example response — 200
{
"merchant_id": "mrc_123",
"allow_cancellation": true,
"allow_plan_change": true,
"allow_payment_method_change": true,
"cancellation_survey": true,
"custom_cancellation_message": "Operation completed successfully"
}PUT/api/v1/merchants/:merchant_id/portal-config
Auth: Customer Portal session (cookie set by the magic-link flow).
Upserts the configuration — the first call creates it, later calls replace the fields you send.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_id | string | Yes | — |
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
allow_cancellation | boolean | No | Allow customers to cancel via the portal. |
allow_plan_change | boolean | No | Allow customers to change plan via the portal. |
allow_payment_method_change | boolean | No | Allow customers to add a card during dunning. |
cancellation_survey | boolean | No | Show a cancellation survey. |
custom_cancellation_message | string | No | Markdown shown on the cancellation screen. |
Example request
curl -X PUT https://api.tokeflow.com/api/v1/merchants/mrc_8a3f12d9/portal-config \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"allow_cancellation": true,
"allow_plan_change": true,
"allow_payment_method_change": true,
"cancellation_survey": true,
"custom_cancellation_message": "Operation completed successfully"
}'Example response — 200
{
"merchant_id": "mrc_123",
"allow_cancellation": true,
"allow_plan_change": true,
"allow_payment_method_change": true,
"cancellation_survey": true,
"custom_cancellation_message": "Operation completed successfully"
}POST/api/v1/portal/auth/email-change/confirm
Auth: Customer Portal session (cookie set by the magic-link flow).
Confirm an email change via the emailed token.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Token from the confirmation email. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/auth/email-change/confirm \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"token": "string"
}'POST/api/v1/portal/auth/logout
Auth: Customer Portal session (cookie set by the magic-link flow).
Clear the portal session cookie.
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/auth/logout \
-H "Cookie: tf_portal_session=…"GET/api/v1/portal/auth/me
Auth: Customer Portal session (cookie set by the magic-link flow).
Get the current portal session account.
Example request
curl https://api.tokeflow.com/api/v1/portal/auth/me \
-H "Cookie: tf_portal_session=…"Example response — 200
{
"id": "cpa_123",
"organization_id": "org_123",
"merchant_id": "mrc_123",
"email": "customer@example.com",
"expires_in": 1800
}POST/api/v1/portal/auth/request-link
Auth: Customer Portal session (cookie set by the magic-link flow).
Request a portal magic-link email.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | Organization the portal belongs to. |
merchant_id | string | Yes | Merchant the portal session is scoped to (from the bootstrap response). Required — the portal is single-merchant, and a session with no merchant cannot be scoped to anything. |
email | string | Yes | Customer email. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/auth/request-link \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"organization_id": "org_123",
"merchant_id": "mrc_123",
"email": "customer@example.com"
}'POST/api/v1/portal/auth/verify
Auth: Customer Portal session (cookie set by the magic-link flow).
Verify a magic-link token; sets the session cookie.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Raw token from the emailed magic link. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/auth/verify \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"token": "string"
}'Example response — 200
{
"id": "cpa_123",
"organization_id": "org_123",
"merchant_id": "mrc_123",
"email": "customer@example.com",
"expires_in": 1800
}GET/api/v1/portal/bootstrap
Auth: Customer Portal session (cookie set by the magic-link flow).
Resolve merchant branding + flags for the portal.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
merchant_id | string | No | — |
organization_id | string | No | — |
merchant | string | No | — |
Example request
curl -G https://api.tokeflow.com/api/v1/portal/bootstrap \
-H "Cookie: tf_portal_session=…" \
--data-urlencode "merchant_id=mrc_123" \
--data-urlencode "organization_id=org_123" \
--data-urlencode "merchant=acme-store"Example response — 200
{
"organization_id": "org_123",
"merchant_id": "mrc_123",
"merchant_slug": "acme-store",
"merchant_name": "Acme Store",
"branding": {
"site_title": "Acme Store",
"favicon": "string",
"logo_light_mode": "string",
"logo_dark_mode": "string",
"theme_primary_color": "#1A73E8",
"theme_secondary_color": "#0B5394",
"custom_url": "https://acme.example.com",
"show_name_with_logo": false
},
"config": {
"allow_cancellation": true,
"allow_plan_change": true,
"allow_payment_method_change": true,
"cancellation_survey": false,
"custom_cancellation_message": "Operation completed successfully"
}
}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. |