Customer Portal subscriptions
Let a customer view and manage their own subscriptions in the portal — see plans, switch plans, add a card during dunning, and cancel.
These endpoints let a signed-in customer manage their own subscriptions: list them, open one, see which plans it can switch to, add a card while a renewal is failing (dunning), and cancel.
Actions here are constrained by the merchant's portal config — a merchant chooses whether customers may switch plans or cancel on their own. Everything is scoped to the customer that owns the session; a customer can never see another's subscriptions.
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 subscription object
Returned by the list and retrieve endpoints on this page.
| Field | Type | Description |
|---|---|---|
id | string | — |
status | string | One of trialing, active, dunning, paused, cancelled, expired. |
current_offer_id | string | — |
billing_cycle | string | One of daily, biweekly, monthly, quarterly, half_yearly, yearly, custom, none. |
currency | string | — |
current_amount | number | Current amount in minor units. |
current_period_start | string | null | (ISO 8601 UTC). |
current_period_end | string | null | (ISO 8601 UTC). |
next_billing_at | string | null | (ISO 8601 UTC). |
cancel_at_period_end | boolean | — |
cancelled_at | string | null | (ISO 8601 UTC). |
cycles_completed | number | Number of completed billing cycles. |
cycle_limit | number | null | Max charges; null = ongoing. |
trial_start | string | null | (ISO 8601 UTC). |
trial_end | string | null | (ISO 8601 UTC). |
preferred_installments | number | — |
dunning_next_retry_at | string | null | Next dunning retry (if dunning). (ISO 8601 UTC). |
offer_name | string | null | — |
product_name | string | null | — |
card_brand | string | null | — |
card_last4 | string | null | — |
card_exp_month | number | null | — |
card_exp_year | number | null | — |
Endpoints
GET/api/v1/portal/subscriptions
Auth: Customer Portal session (cookie set by the magic-link flow).
List the customer's subscriptions.
Example request
curl https://api.tokeflow.com/api/v1/portal/subscriptions \
-H "Cookie: tf_portal_session=…"GET/api/v1/portal/subscriptions/:id
Auth: Customer Portal session (cookie set by the magic-link flow).
Get one subscription.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Example request
curl https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d \
-H "Cookie: tf_portal_session=…"Example response — 200
{
"id": "sub_123",
"status": "trialing",
"current_offer_id": "off_123",
"billing_cycle": "daily",
"currency": "BRL",
"current_amount": 15000,
"current_period_start": "2026-01-15T12:30:00.000Z",
"current_period_end": "2026-01-15T12:30:00.000Z",
"next_billing_at": "2026-01-15T12:30:00.000Z",
"cancel_at_period_end": true,
"cancelled_at": "2026-01-15T12:30:00.000Z",
"cycles_completed": 1,
"cycle_limit": 1,
"trial_start": "2026-01-15T12:30:00.000Z",
"trial_end": "2026-01-15T12:30:00.000Z",
"preferred_installments": 1,
"dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
"offer_name": "Premium Monthly",
"product_name": "Streaming Plans",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2027
}POST/api/v1/portal/subscriptions/:id/add-card
Auth: Customer Portal session (cookie set by the magic-link flow).
Add a card during dunning.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
card_ciphertext_id | string | Yes | The single-use encrypted card reference (tok_…) for the new card, from the Bridge SDK. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d/add-card \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"card_ciphertext_id": "tok_8f3c2a1b9d4e"
}'Example response — 200
{
"id": "sub_123",
"status": "trialing",
"current_offer_id": "off_123",
"billing_cycle": "daily",
"currency": "BRL",
"current_amount": 15000,
"current_period_start": "2026-01-15T12:30:00.000Z",
"current_period_end": "2026-01-15T12:30:00.000Z",
"next_billing_at": "2026-01-15T12:30:00.000Z",
"cancel_at_period_end": true,
"cancelled_at": "2026-01-15T12:30:00.000Z",
"cycles_completed": 1,
"cycle_limit": 1,
"trial_start": "2026-01-15T12:30:00.000Z",
"trial_end": "2026-01-15T12:30:00.000Z",
"preferred_installments": 1,
"dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
"offer_name": "Premium Monthly",
"product_name": "Streaming Plans",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2027
}GET/api/v1/portal/subscriptions/:id/available-plans
Auth: Customer Portal session (cookie set by the magic-link flow).
Plans this subscription can switch to.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Example request
curl https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d/available-plans \
-H "Cookie: tf_portal_session=…"Example response — 200
{
"current_offer_id": "off_123",
"current_amount": 4990,
"currency": "BRL",
"data": [
{
"offer_id": "off_456",
"offer_name": "Premium Monthly",
"description": "Human-readable description",
"billing_cycle": "monthly",
"currency": "BRL",
"amount": 4990,
"change_kind": "upgrade",
"change_charge_behavior": "next_renew"
}
]
}POST/api/v1/portal/subscriptions/:id/cancel
Auth: Customer Portal session (cookie set by the magic-link flow).
Cancel a subscription.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
at_period_end | boolean | No | Cancel at the end of the paid period (default true, most favorable). false cancels immediately. |
reason | string | No | Optional cancellation reason. |
survey_response | string | No | Optional cancellation survey response. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d/cancel \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"at_period_end": true,
"reason": "requested_by_customer",
"survey_response": "string"
}'Example response — 200
{
"id": "sub_123",
"status": "trialing",
"current_offer_id": "off_123",
"billing_cycle": "daily",
"currency": "BRL",
"current_amount": 15000,
"current_period_start": "2026-01-15T12:30:00.000Z",
"current_period_end": "2026-01-15T12:30:00.000Z",
"next_billing_at": "2026-01-15T12:30:00.000Z",
"cancel_at_period_end": true,
"cancelled_at": "2026-01-15T12:30:00.000Z",
"cycles_completed": 1,
"cycle_limit": 1,
"trial_start": "2026-01-15T12:30:00.000Z",
"trial_end": "2026-01-15T12:30:00.000Z",
"preferred_installments": 1,
"dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
"offer_name": "Premium Monthly",
"product_name": "Streaming Plans",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2027
}POST/api/v1/portal/subscriptions/:id/change-plan
Auth: Customer Portal session (cookie set by the magic-link flow).
Change plan (upgrade/downgrade).
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
to_offer_id | string | Yes | Target offer to switch to. |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d/change-plan \
-H "Cookie: tf_portal_session=…" \
-H "Content-Type: application/json" \
-d '{
"to_offer_id": "off_123"
}'Example response — 200
{
"id": "sub_123",
"status": "trialing",
"current_offer_id": "off_123",
"billing_cycle": "daily",
"currency": "BRL",
"current_amount": 15000,
"current_period_start": "2026-01-15T12:30:00.000Z",
"current_period_end": "2026-01-15T12:30:00.000Z",
"next_billing_at": "2026-01-15T12:30:00.000Z",
"cancel_at_period_end": true,
"cancelled_at": "2026-01-15T12:30:00.000Z",
"cycles_completed": 1,
"cycle_limit": 1,
"trial_start": "2026-01-15T12:30:00.000Z",
"trial_end": "2026-01-15T12:30:00.000Z",
"preferred_installments": 1,
"dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
"offer_name": "Premium Monthly",
"product_name": "Streaming Plans",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2027
}POST/api/v1/portal/subscriptions/:id/reactivate
Auth: Customer Portal session (cookie set by the magic-link flow).
Reactivate a pending-cancellation or paused plan.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Example request
curl -X POST https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d/reactivate \
-H "Cookie: tf_portal_session=…"Example response — 200
{
"id": "sub_123",
"status": "trialing",
"current_offer_id": "off_123",
"billing_cycle": "daily",
"currency": "BRL",
"current_amount": 15000,
"current_period_start": "2026-01-15T12:30:00.000Z",
"current_period_end": "2026-01-15T12:30:00.000Z",
"next_billing_at": "2026-01-15T12:30:00.000Z",
"cancel_at_period_end": true,
"cancelled_at": "2026-01-15T12:30:00.000Z",
"cycles_completed": 1,
"cycle_limit": 1,
"trial_start": "2026-01-15T12:30:00.000Z",
"trial_end": "2026-01-15T12:30:00.000Z",
"preferred_installments": 1,
"dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
"offer_name": "Premium Monthly",
"product_name": "Streaming Plans",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2027
}GET/api/v1/portal/subscriptions/:id/transitions
Auth: Customer Portal session (cookie set by the magic-link flow).
A subscription's state-change history.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | — |
Example request
curl https://api.tokeflow.com/api/v1/portal/subscriptions/obj_1a2b3c4d/transitions \
-H "Cookie: tf_portal_session=…"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. |