Skip to content
Products & subscriptionsModification & querying

Modification and querying

Subscription endpoints fall into two groups.

Direct query and modification. These calls do not use a Checkout Session. Use them to display a subscription, its order history and invoice links, and open plan changes, and to cancel a subscription or a pending plan change when the action comes from you. Direct cancellation takes effect immediately.

Requests the consumer confirms. These calls return a Checkout Session. Redirect the consumer to its url. The subscription does not change until they confirm. Use them when the change needs the consumer's action or consent: they asked to cancel, they must approve a plan change, or they must supply a new payment method.

Amount format: Monetary values (such as amount fields) are expressed in the smallest minor unit of each currency. See Supported currencies.

Results are limited to the API key's merchant and test mode.

List subscriptions

GET /v2/subscription returns subscriptions for the authenticated merchant, newest id first.

reference and customerId are exact matches and combine with AND. limit is 1–100 and defaults to 20. Omit cursor for the first page; pass pagination.nextCursor back unchanged as cursor for the next page.

bash
curl --request GET \
  --url 'https://api.tokenz.one/v2/subscription?customerId=customer_123&limit=20' \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "data": [
    {
      "id": "subscription_1p4LS47fB1h_t",
      "object": "subscription",
      "status": "active",
      "test": true,
      "reference": "Pro Plan (Monthly)",
      "customerId": "customer_123",
      "items": [
        {
          "id": "item_1p4LS47fB1i_t",
          "detail": {
            "product": {
              "price": { "amount": 1000, "currency": "USD" },
              "quantity": 1,
              "label": "Pro Plan (Monthly)",
              "images": ["https://example.com/pro-plan.png"]
            }
          }
        }
      ],
      "interval": { "unit": "MONTH", "count": 1 },
      "provideAccess": true,
      "currentBillingPeriodEnd": "2026-08-01T00:00:00Z",
      "createdAt": "2026-07-01T00:00:00Z",
      "updatedAt": "2026-07-01T00:00:00Z"
    }
  ],
  "pagination": {
    "nextCursor": "subscription_1p4LC47fB2a_t"
  }
}

pagination.nextCursor is absent on the last page.

Retrieve a subscription

GET /v2/subscription/{id} returns one subscription. The call fails with 404 when the id is unknown, belongs to another merchant, or does not match the API key's test mode.

bash
curl --request GET \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "id": "subscription_1p4LS47fB1h_t",
  "object": "subscription",
  "status": "active",
  "test": true,
  "reference": "Pro Plan (Monthly)",
  "customerId": "customer_123",
  "items": [
    {
      "id": "item_1p4LS47fB1i_t",
      "detail": {
        "product": {
          "price": { "amount": 1000, "currency": "USD" },
          "quantity": 1,
          "label": "Pro Plan (Monthly)",
          "images": ["https://example.com/pro-plan.png"]
        }
      }
    }
  ],
  "interval": { "unit": "MONTH", "count": 1 },
  "provideAccess": true,
  "currentBillingPeriodEnd": "2026-08-01T00:00:00Z",
  "createdAt": "2026-07-01T00:00:00Z",
  "updatedAt": "2026-07-01T00:00:00Z"
}

Cancel a subscription

POST /v2/subscription/{id}/cancel cancels the subscription immediately. There is no request body. The subscription must be trialing, active, or unpaid to be canceled. Already canceled subscription are unaffected and other statuses result in 422 with code subscription.status-invalid.

Cancellation sets canceledAt, stops future renewal orders, and sends subscription.canceled. It is final. See Lifecycle & billing for what happens to access and in-flight orders.

bash
curl --request POST \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t/cancel \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "id": "subscription_1p4LS47fB1h_t",
  "object": "subscription",
  "status": "canceled",
  "test": true,
  "items": [
    {
      "id": "item_1p4LS47fB1i_t",
      "detail": {
        "product": {
          "price": { "amount": 1000, "currency": "USD" },
          "quantity": 1,
          "label": "Pro Plan (Monthly)",
          "images": ["https://example.com/pro-plan.png"]
        }
      }
    }
  ],
  "interval": { "unit": "MONTH", "count": 1 },
  "provideAccess": true,
  "provideAccessUntil": "2026-08-01T00:00:00Z",
  "canceledAt": "2026-07-15T12:00:00Z",
  "createdAt": "2026-07-01T00:00:00Z",
  "updatedAt": "2026-07-15T12:00:00Z"
}

Request consumer cancellation

POST /v2/subscription/{id}/request/cancel does not cancel the subscription itself. It creates a Checkout Session the consumer uses to confirm. Redirect them to the returned url. After they confirm, the subscription is canceled the same way as a direct cancellation, including the subscription.canceled webhook.

Required body fields:

  • successUrl: where the consumer lands after confirming.
  • pendingUrl: where the consumer lands if confirmation is still pending.
  • cancelUrl: where the consumer lands if they abandon the flow.

theme is optional (LIGHT or DARK).

bash
curl --request POST \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t/request/cancel \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \
  --data '{
    "successUrl": "https://example.com/success",
    "pendingUrl": "https://example.com/pending",
    "cancelUrl": "https://example.com/cancel"
  }'

Response

201 returns the Checkout Session. The subscription stays in its current status until the consumer confirms.

json
{
  "id": "checkoutsession_1p4LC47fB2a_t",
  "object": "checkoutsession",
  "url": "https://checkout.tokenz.one/1p4LC47fB2a_t",
  "successUrl": "https://example.com/success",
  "pendingUrl": "https://example.com/pending",
  "cancelUrl": "https://example.com/cancel",
  "test": true,
  "subscription": {
    "id": "subscription_1p4LS47fB1h_t",
    "object": "subscription",
    "status": "active"
  },
  "createdAt": "2026-07-15T12:00:00Z",
  "updatedAt": "2026-07-15T12:00:00Z"
}

Request a payment-method change

POST /v2/subscription/{id}/request/payment-method-change creates a Checkout Session where the consumer supplies a new card. Redirect them to url. Consent for the new card is captured on that hosted page; see Payment methods & consent.

The body is the same three redirect URLs as consumer cancellation (successUrl, pendingUrl, cancelUrl), plus optional theme.

When the subscription is unpaid, the returned session is the checkout for the outstanding order. Paying that order replaces the payment method and reactivates the subscription. On success, Tokenz sends subscription.activated webhook.

For an active or trialing subscription a Checkout Session for payment method update is returned. On success, Tokenz sends subscription.payment_method_updated webhook.

bash
curl --request POST \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t/request/payment-method-change \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \
  --data '{
    "successUrl": "https://example.com/success",
    "pendingUrl": "https://example.com/pending",
    "cancelUrl": "https://example.com/cancel"
  }'

Response

json
{
  "id": "checkoutsession_1p4LP47fB3b_t",
  "object": "checkoutsession",
  "url": "https://checkout.tokenz.one/1p4LP47fB3b_t",
  "successUrl": "https://example.com/success",
  "pendingUrl": "https://example.com/pending",
  "cancelUrl": "https://example.com/cancel",
  "test": true,
  "subscription": {
    "id": "subscription_1p4LS47fB1h_t",
    "object": "subscription",
    "status": "active"
  },
  "createdAt": "2026-07-15T12:00:00Z",
  "updatedAt": "2026-07-15T12:00:00Z"
}

Request a plan change

POST /v2/subscription/{id}/request/plan-change asks the consumer to approve a new item and billing interval. The change is not applied until they approve it on the returned Checkout Session.

The subscription must be active or trialing, other states result in 422 with code subscription.status-invalid. The body must include itemDetails, replacementMode, successUrl, pendingUrl, and cancelUrl. itemDetails replaces the subscription's current item: exactly one non-discounted item with quantity of 1. The item's currency must match the subscription's currency, otherwise error 400 with code currency.inconsistent is returned. interval sets the new billing interval, { "unit": "WEEK" | "MONTH" | "YEAR", "count": <integer ≥ 1> }. successUrl is used after an immediate change is applied, and pendingUrl is used after a deferred change is approved.

replacementMode:

  • IMMEDIATE_PRORATION: for a time-based subscription (for example a premium plan), apply the change as soon as the consumer authorizes the order. When subscription is active the consumer is credited the remaining prorated value of the current billing period and the billing anchor is set to the date of the authorization. When subscription is trialing the trial ends immediately with no additional credit and the subscription starts with the new plan. If the calculated credit exceeds the new item's price, error 422 with code subscription.plan-replacement-invalid is returned. Do not use this mode for an item-based subscription (for example a monthly currency purchase). Contact Tokenz if you want upgrade options for an item-based subscription.
  • DEFERRED: apply the change after the current billing period ends. Approval sends subscription.plan_change_scheduled; the plan itself changes when the order for next billing period is paid.

When the plan is applied (immediately or at the next period), Tokenz sends subscription.plan_changed webhook.

bash
curl --request POST \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t/request/plan-change \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \
  --data '{
    "itemDetails": [{
      "product": {
        "price": { "amount": 2000, "currency": "USD" },
        "quantity": 1,
        "label": "Pro Plan (Yearly)",
        "images": ["https://example.com/pro-plan.png"],
        "taxCategory": "SAAS"
      }
    }],
    "interval": { "unit": "YEAR", "count": 1 },
    "replacementMode": "DEFERRED",
    "successUrl": "https://example.com/success",
    "pendingUrl": "https://example.com/pending",
    "cancelUrl": "https://example.com/cancel"
  }'

Use "replacementMode": "IMMEDIATE_PRORATION" to apply the same plan as soon as the consumer approves it. Use this mode for a time-based subscription, not an item-based one.

Response

201 returns the Checkout Session and the pending change.

json
{
  "id": "checkoutsession_1p4LR47fB4c_t",
  "object": "checkoutsession",
  "url": "https://checkout.tokenz.one/1p4LR47fB4c_t",
  "successUrl": "https://example.com/success",
  "pendingUrl": "https://example.com/pending",
  "cancelUrl": "https://example.com/cancel",
  "test": true,
  "subscriptionChange": {
    "id": "subscriptionchange_1p4LC9aB2cD_t",
    "object": "subscriptionchange",
    "status": "pending",
    "replacementMode": "DEFERRED",
    "interval": { "unit": "YEAR", "count": 1 },
    "items": [
      {
        "id": "item_1p4LS47fB1j_t",
        "detail": {
          "product": {
            "price": { "amount": 2000, "currency": "USD" },
            "quantity": 1,
            "label": "Pro Plan (Yearly)",
            "images": ["https://example.com/pro-plan.png"]
          }
        }
      }
    ]
  },
  "createdAt": "2026-07-15T12:00:00Z",
  "updatedAt": "2026-07-15T12:00:00Z"
}

Redirect the consumer to url. Store subscriptionChange.id if you need to list or cancel the change later.

List plan changes

GET /v2/subscription/{id}/plan-change returns the subscription's open changes: those in pending or approved status. canceled and applied changes are not included.

A change moves through pending (waiting for the consumer), approved (accepted, and for a deferred change not yet applied), applied, or canceled.

bash
curl --request GET \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t/plan-change \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "data": [
    {
      "id": "subscriptionchange_1p4LC9aB2cD_t",
      "object": "subscriptionchange",
      "status": "approved",
      "replacementMode": "DEFERRED",
      "interval": { "unit": "YEAR", "count": 1 },
      "items": [
        {
          "id": "item_1p4LS47fB1j_t",
          "detail": {
            "product": {
              "price": { "amount": 2000, "currency": "USD" },
              "quantity": 1,
              "label": "Pro Plan (Yearly)",
              "images": ["https://example.com/pro-plan.png"]
            }
          }
        }
      ]
    }
  ]
}

Cancel a plan change

POST /v2/subscription/{id}/plan-change/{changeId}/cancel cancels a pending or approved change before it is applied. There is no request body. Canceling an applied, expired or canceled change returns 422 with subscription.change-status-invalid. Deferred changes become non-cancelable when an order for next billing period is created even if their status is still approved, attempt to cancel such a change returns 422 with subscription.change-status-invalid.

A deferred change that was already approved sends subscription.plan_change_canceled.

bash
curl --request POST \
  --url https://api.tokenz.one/v2/subscription/subscription_1p4LS47fB1h_t/plan-change/subscriptionchange_1p4LC9aB2cD_t/cancel \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "id": "subscriptionchange_1p4LC9aB2cD_t",
  "object": "subscriptionchange",
  "status": "canceled",
  "replacementMode": "DEFERRED",
  "interval": { "unit": "YEAR", "count": 1 },
  "items": [
    {
      "id": "item_1p4LS47fB1j_t",
      "detail": {
        "product": {
          "price": { "amount": 2000, "currency": "USD" },
          "quantity": 1,
          "label": "Pro Plan (Yearly)",
          "images": ["https://example.com/pro-plan.png"]
        }
      }
    }
  ]
}

List orders of a subscription

GET /v2/order on the Order service lists the orders created for one subscription. subscriptionId is required. limit (1–100, default 20) and cursor page the same way as List subscriptions: pass pagination.nextCursor back unchanged as cursor. Orders are newest id first, and only those matching the API key's test mode are returned.

Each order includes subscriptionId. Items may include billedPeriodStart (inclusive) and billedPeriodEnd (exclusive) for the period that order covers.

bash
curl --request GET \
  --url 'https://api.tokenz.one/v2/order?subscriptionId=subscription_1p4LS47fB1h_t&limit=20' \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "data": [
    {
      "id": "order_1D5xA9BnKfv_t",
      "object": "order",
      "status": "succeeded",
      "test": true,
      "subscriptionId": "subscription_1p4LS47fB1h_t",
      "amount": { "amount": 1000, "currency": "USD" },
      "items": [
        {
          "id": "item_1p4LO47fB1k_t",
          "billedPeriodStart": "2026-07-01T00:00:00Z",
          "billedPeriodEnd": "2026-08-01T00:00:00Z",
          "detail": {
            "product": {
              "price": { "amount": 1000, "currency": "USD" },
              "quantity": 1,
              "label": "Pro Plan (Monthly)",
              "images": ["https://example.com/pro-plan.png"]
            }
          }
        }
      ],
      "createdAt": "2026-07-01T00:00:00Z",
      "updatedAt": "2026-07-01T00:00:05Z"
    }
  ],
  "pagination": {
    "nextCursor": "order_1p4LC47fB2a_t"
  }
}

GET /v2/order/{id}/invoice returns the buyer's hosted invoice links for an order, including a subscription renewal. displayUrl is the hosted invoice page. downloadUrl is the PDF and is present only after the PDF has been generated. Redirect the customer to the full URL including the fragment part with Tokenz generated signature.

bash
curl --request GET \
  --url https://api.tokenz.one/v2/order/order_1D5xA9BnKfv_t/invoice \
  --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'

Response

json
{
  "displayUrl": "https://invoice.tokenz.one/i/1D5xA9BnKfv_t#generated-invoice-signature",
  "downloadUrl": "https://invoice.tokenz.one/i/1D5xA9BnKfv_t/download#generated-invoice-signature"
}

Until the PDF exists, the response contains displayUrl only.

Webhooks

Keep your own records in sync from webhooks rather than polling these endpoints. The events for the operations on this page:

  • subscription.canceled — direct cancellation, or a consumer-confirmed cancellation, completed.
  • subscription.payment_method_updated — the consumer confirmed a new card.
  • subscription.plan_change_scheduled — the consumer approved a deferred plan change.
  • subscription.plan_change_canceled — a scheduled deferred plan change was canceled before it was applied.
  • subscription.plan_changed — an immediate or deferred plan change was applied. items and interval in the payload are the new plan.

Payload shapes are in Webhooks.