Merchant subscriptions

Manage a merchant's subscriptions from the Dashboard — inspect lifecycle and dunning, pause or resume, cancel, and change the billed offer.

A subscription is a recurring agreement between a customer and a merchant, billed against an offer. These endpoints back the Dashboard's subscriptions screen: list and open subscriptions, walk their transition history, pause and resume, cancel, and move one to a different offer.

Every state change is recorded as a transition — the append-only history that answers what changed, when, and why. Dunning is part of that lifecycle: a failed renewal moves the subscription into a retry state rather than ending it outright.

These endpoints power the Tokeflow Dashboard UI. They are session-authenticated (JWT bearer) — the token comes from signing in to the Dashboard, not from an sk_/pk_ API key. Requests also carry the x-merchant-id header identifying the merchant in context, and the signed-in user must be a member with access to it.

The subscription object

Returned by the list and retrieve endpoints on this page.

FieldTypeDescription
idstringSubscription id.
merchant_idstringMerchant id.
customer_idstringCustomer id.
customer_namestring | nullCustomer name (resolved).
customer_emailstring | nullCustomer email (resolved).
current_offer_idstringCurrent offer id.
offer_namestringOffer name (resolved).
product_idstringProduct id of the current offer.
product_namestringProduct name (resolved).
product_family_idstringProduct family id.
billing_cyclestringOne of daily, biweekly, monthly, quarterly, half_yearly, yearly, custom, none.
currencystringISO 4217 currency.
current_amountnumberCurrent charge amount in minor units.
current_period_startstring(ISO 8601 UTC).
current_period_endstring(ISO 8601 UTC).
next_billing_atstring | null(ISO 8601 UTC).
billing_anchor_daynumber | null
trial_startstring | null(ISO 8601 UTC).
trial_endstring | null(ISO 8601 UTC).
dunning_started_atstring | null(ISO 8601 UTC).
dunning_attempt_countnumber
dunning_next_retry_atstring | null(ISO 8601 UTC).
cycles_completednumber
cycle_limitnumber | null
statusstringOne of trialing, active, dunning, paused, cancelled, expired.
cancel_at_period_endboolean
cancelled_atstring | null(ISO 8601 UTC).
cancellation_reasonstring | null
payment_instrument_idstring
preferred_connector_idstring | null
preferred_connector_namestringPreferred connector name (resolved).
initial_network_transaction_idstring | null
preferred_installmentsnumber
created_atstring(ISO 8601 UTC).
updated_atstring(ISO 8601 UTC).

Endpoints

GET/api/v1/merchant/subscriptions

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

List subscriptions for merchant.

Query parameters

FieldTypeRequiredDescription
pagenumberNoPage number (1-indexed). Default 1, min 1.
limitnumberNoNumber of items per page. Default 20, min 1, max 100.
customer_idstringNoFilter by customer ID
statusstringNoFilter by subscription status
current_offer_idstringNoFilter by current offer ID
product_family_idstringNoFilter by product family ID

Example request

curl -G https://api.tokeflow.com/api/v1/merchant/subscriptions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9" \
  --data-urlencode "page=1" \
  --data-urlencode "limit=20" \
  --data-urlencode "customer_id=cust_123" \
  --data-urlencode "status=active"

Example response200

{
  "data": [
    {
      "id": "sub_123",
      "merchant_id": "mrc_123",
      "customer_id": "cust_123",
      "customer_name": "Acme Store",
      "customer_email": "jane@example.com",
      "current_offer_id": "off_123",
      "offer_name": "Acme Store",
      "product_id": "prd_9b1e6c05",
      "product_name": "Acme Store",
      "product_family_id": "pfam_123",
      "billing_cycle": "monthly",
      "currency": "BRL",
      "current_amount": 4990,
      "current_period_start": "2026-05-25T00:00:00Z",
      "current_period_end": "2026-06-25T00:00:00Z",
      "next_billing_at": "2026-06-25T00:00:00Z",
      "billing_anchor_day": 25,
      "trial_start": "2026-05-25T00:00:00Z",
      "trial_end": "2026-06-08T00:00:00Z",
      "dunning_started_at": "2026-01-15T12:30:00.000Z",
      "dunning_attempt_count": 0,
      "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
      "cycles_completed": 3,
      "cycle_limit": 12,
      "status": "active",
      "cancel_at_period_end": false
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "total_pages": 3,
    "has_next": true,
    "has_prev": false
  }
}

GET/api/v1/merchant/subscriptions/:id

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Get subscription by ID.

Path parameters

FieldTypeRequiredDescription
idstringYes

Example request

curl https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9"

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

POST/api/v1/merchant/subscriptions/:id/cancel

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Cancel subscription (admin attribution).

Path parameters

FieldTypeRequiredDescription
idstringYes

Request fields

FieldTypeRequiredDescription
at_period_endbooleanYesWhen true defers cancellation to the next renewal; false cancels immediately.
reasonstringNoOptional human-readable reason persisted on the subscription.

Example request

curl -X POST https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/cancel \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9" \
  -H "Content-Type: application/json" \
  -d '{
    "at_period_end": true,
    "reason": "customer no longer needs the service"
  }'

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

POST/api/v1/merchant/subscriptions/:id/change-offer

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Change subscription offer.

Path parameters

FieldTypeRequiredDescription
idstringYes

Request fields

FieldTypeRequiredDescription
to_offer_idstringYesTarget offer id. Must belong to the same product family as the current offer.

Example request

curl -X POST https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/change-offer \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9" \
  -H "Content-Type: application/json" \
  -d '{
    "to_offer_id": "off_premium_monthly"
  }'

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

POST/api/v1/merchant/subscriptions/:id/change-payment-instrument

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Change subscription payment instrument.

Path parameters

FieldTypeRequiredDescription
idstringYes

Request fields

FieldTypeRequiredDescription
payment_instrument_idstringYesId of the payment instrument to bill going forward.

Example request

curl -X POST https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/change-payment-instrument \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_instrument_id": "pi_123"
  }'

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

POST/api/v1/merchant/subscriptions/:id/pause

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Pause subscription.

Path parameters

FieldTypeRequiredDescription
idstringYes

Request fields

FieldTypeRequiredDescription
reasonstringNoOptional human-readable reason persisted on the transition.

Example request

curl -X POST https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/pause \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "customer travelling for 6 weeks"
  }'

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

POST/api/v1/merchant/subscriptions/:id/resume

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Resume subscription.

Path parameters

FieldTypeRequiredDescription
idstringYes

Example request

curl -X POST https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/resume \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9"

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

POST/api/v1/merchant/subscriptions/:id/reactivate

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

Call off a scheduled cancellation and keep the subscription on its current plan. Reactivation sets cancel_at_period_end back to false and records a reactivation transition; it does not change the offer, the amount, or the billing dates. Available for a live subscription (active, trialing, or dunning); a paused subscription must be resumed instead, and a terminal one is rejected (409).

Path parameters

FieldTypeRequiredDescription
idstringYes

Example request

curl -X POST https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/reactivate \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9"

Example response200

{
  "id": "sub_123",
  "merchant_id": "mrc_123",
  "customer_id": "cust_123",
  "customer_name": "Acme Store",
  "customer_email": "jane@example.com",
  "current_offer_id": "off_123",
  "offer_name": "Acme Store",
  "product_id": "prd_9b1e6c05",
  "product_name": "Acme Store",
  "product_family_id": "pfam_123",
  "billing_cycle": "monthly",
  "currency": "BRL",
  "current_amount": 4990,
  "current_period_start": "2026-05-25T00:00:00Z",
  "current_period_end": "2026-06-25T00:00:00Z",
  "next_billing_at": "2026-06-25T00:00:00Z",
  "billing_anchor_day": 25,
  "trial_start": "2026-05-25T00:00:00Z",
  "trial_end": "2026-06-08T00:00:00Z",
  "dunning_started_at": "2026-01-15T12:30:00.000Z",
  "dunning_attempt_count": 0,
  "dunning_next_retry_at": "2026-01-15T12:30:00.000Z",
  "cycles_completed": 3,
  "cycle_limit": 12,
  "status": "active",
  "cancel_at_period_end": false
}

GET/api/v1/merchant/subscriptions/:id/transitions

Merchant

Auth: Dashboard session (JWT bearer). Merchant membership required.

List subscription transition history.

Path parameters

FieldTypeRequiredDescription
idstringYes

Example request

curl https://api.tokeflow.com/api/v1/merchant/subscriptions/obj_1a2b3c4d/transitions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
  -H "x-merchant-id: mrc_8a3f12d9"

Example response200

{
  "data": [
    {
      "id": "sbt_123",
      "subscription_id": "sub_123",
      "transition_type": "creation",
      "from_offer_id": "off_basic_monthly",
      "to_offer_id": "off_premium_monthly",
      "from_status": "trialing",
      "to_status": "trialing",
      "triggered_by": "customer",
      "order_id": "ord_123",
      "reason": "requested_by_customer",
      "metadata": {},
      "created_at": "2026-01-15T12:30:00.000Z"
    }
  ]
}

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