Subscriptions

Subscriptions link a customer to a subscription plan, or to a subscription offer for items bought in a mixed cart, and automate recurring billing. Create one directly when you already have a Flint customer_id and a usable payment method for that customer; for Flint-hosted signup, sell the plan through a checkout session or payment link with subscription_plan_id instead. A subscription can start immediately, at a future time, or by importing an already-paid current period without charging.

A subscription is always in exactly one of six states:

status on subscription
Final values do not change again
  • incomplete
    Created, but the first payment hasn't succeeded yet. Plans without a trial start here. Don't provision yet. Wait for the first subscription.payment_succeeded.
  • trialing
    In the free trial. The card is saved but hasn't been charged. Provision access.
  • active
    Paid and current. Provision access.
  • past_due
    A renewal charge failed and Flint is retrying. Keep or degrade access (your call) and prompt the customer to update their card.
  • paused
    Billing is suspended: by you, by the customer, after retries ran out (if you configure that), or after a delivery hold ran out. Suspend access if your product pauses with billing.
  • canceledFinal
    Either canceled immediately or reached the end of its final paid period. Revoke access.

Non-trial immediate subscriptions start as incomplete while Flint collects the first paid period, then move to active; grant access only once the subscription is active. From there, the lifecycle covers trialing, paused, past_due, and canceled. Pausing preserves remaining prepaid time, cancellation can take effect immediately or at period end, and failed renewals enter dunning, where Flint retries the payment before applying the owner-specific end action. A customer can hold multiple independent subscriptions to the same plan.

A paused subscription reports pause_reason. delivery_action_required means a renewal was held because delivery couldn't be quoted, and then either the hold ran out or someone (the buyer or you) paused during the hold. A pause Flint starts when the hold runs out has no end date and waits for a resume. A pause with a length resumes on its own when the length is up, and starts a new hold if delivery still can't be quoted. Resuming by hand needs a delivery preference Flint can quote (409 SUBSCRIPTION_DELIVERY_UNAVAILABLE otherwise, and the subscription stays paused), starts a new billing period, and charges and ships right away.

billing_schedule_owner is flint when Flint computes renewal dates and external when your integration supplies them. An external subscription with no next_billing_at keeps its lifecycle status and reports awaiting_billing_schedule: true; use the billing-schedule and skip-cycle endpoints to manage its timer. Past-due subscriptions can create idempotent, pollable manual payment retries. Buyers can also start retries through POST /v1/me/subscriptions/{subscription_id}/payment-retries; their limit is 3 retries per billing period, counting retries started by the store too, while merchant requests keep their existing retry behavior.

Note:

See the Subscription billing guide for the full lifecycle and dunning behavior. Use webhooks like subscription.activated and subscription.past_due to drive entitlement changes.

When you send your own subscription email, link the buyer to the subscription with POST /v1/subscriptions/{subscription_id}/access-links. The url it returns opens the subscription in your Flint-hosted customer account without a sign-in for 14 days or 5 opens; pausing or canceling still needs the buyer to sign in. The url is a bearer credential: Flint returns it only in that response and in a retry with the same Idempotency-Key. The route needs commerce.subscriptions.read, and refuses a merchant_hosted customer account. See Link the buyer to their order.

cURL
curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_01J5Z8N3QK4W7Y2RB6TPVXHC9D/access-links \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: subscription-link-sub_01J5Z8N3QK4W7Y2RB6TPVXHC9D"

Delivery#

A subscription to a plan with physical lines carries delivery: where each shipment goes and how. It is required on create for such a plan and rejected for a plan without physical lines.

FieldDescription
typeshipment or local_delivery.
delivery_method_idThe method each renewal is quoted with.
destinationaddress, copied when delivery is written, and customer_address_id when it came from a saved address, for display only. Editing the saved address doesn't change this copy. Unlike the request, the response has no type.
recipientname, phone, and email of the person receiving the shipment.
revisionGoes up by one on every change.
address_verification.stateverified, needs_review, unverified, or unverifiable, from verification when delivery was written. Renewals don't verify again.
delivery_methodThe stored method for display: name, description, type, and price_type (fixed or quoted).
shipping_moneyShipping for one shipment: the method's price when fixed, or the shipping charged on the latest shipment when quoted. Absent until a quoted method has charged once.
updated_atWhen delivery last changed.

Flint clears delivery when the subscription becomes canceled. Each renewal order keeps its own delivery_destination. open_renewal_order_id names a renewal order that is paid but hasn't shipped. It keeps the destination it was paid with, even after delivery changes or the subscription is canceled. It is absent when there is no such order, and only renewal orders count, never the signup order.

Replace delivery as a whole with PATCH /v1/subscriptions/{subscription_id} and the subscription's current version as expected_version. Send destination with "type": "customer_address" and a customer_address_id, or "type": "address" and an address. Flint previews delivery before saving and rejects a method the plan doesn't offer or one that can't serve the address. The change applies from the next unpaid renewal, and the buyer is emailed. Use POST /v1/subscription-previews with mode: "delivery_options" to see which methods serve an address before saving.

Delivery holds#

When a renewal can't be quoted for delivery, Flint holds it instead of charging and reports delivery_hold:

FieldDescription
reasonmethod_unavailable (another offered method serves the address), destination_not_served (no offered method does), or rate_unavailable (the method can't be priced right now).
fixable_bybuyer for method_unavailable when the store lets buyers change delivery (can_update_delivery), merchant otherwise.
started_atWhen the hold started.
ends_atWhen the subscription pauses if the hold isn't resolved: 14 days or one billing interval after the billing date, whichever is sooner.

delivery_hold is absent when nothing is held. While it is present, a payment retry fails with 409 SUBSCRIPTION_PAYMENT_RETRY_NOT_ALLOWED, from you or the buyer, and the buyer's retry_payment action is unavailable with not_in_state. See When a renewal can't ship.

upcoming_delivery_hold reports a renewal that will be held: a delivery check before the billing date failed. It has the same reason and fixable_by, plus detected_at and renewal_at, the billing date that will be held. It clears when a later check passes, the cycle is skipped, the subscription is paused or canceled, or the billing date moves, and at the billing date it becomes delivery_hold if delivery still can't be quoted. It is never present together with delivery_hold. Setting or clearing it emits subscription.updated.

inventory_wait reports a renewal waiting on stock under the invoice path of subscription_inventory_block_action: started_at, the blocked order_id, and its invoice_id. It clears when the renewal is paid or replaced, or the cycle is skipped, paused, or canceled. It appears on merchant reads only. Payment retries are refused while it is present, the same as during a delivery hold.

Needs attention#

GET /v1/subscriptions?needs_attention=true matches a subscription that is past_due or incomplete, active with a renewal more than 24 hours overdue, has a delivery_hold, upcoming_delivery_hold, or inventory_wait, or is paused with pause_reason: "delivery_action_required". needs_attention=false matches every other subscription. Both combine with the other filters. See Renewals that need attention.

Quantity, cadence, and items#

quantity multiplies the whole subscription. Each entry in line_items keeps its per-unit quantity, and each renewal order ships the two multiplied together. recurring_amount_money includes the multiplier. billing_interval and billing_interval_count are the cadence the buyer chose.

Change the cadence or quantity with PATCH /v1/subscriptions/{subscription_id}, within the plan's billing_interval_options and quantity_options. Add, change, and remove lines with POST /v1/subscriptions/{subscription_id}/line-items and PATCH or DELETE /v1/subscriptions/{subscription_id}/line-items/{subscription_line_item_id}. Changes apply from the next unpaid renewal. POST /v1/subscriptions/{subscription_id}/renew bills and ships the next shipment now. See Change cadence, quantity, and items and Order now.

A subscription created from an offer in a mixed cart has no subscription_plan_id. Its lines carry subscription_offer_id, and its options come from the offer.

Cycles, version, and filters#

completed_cycles counts the cycles charged so far, including any carried in with billing_start.imported.completed_cycles. Each renewal order's subscription_cycle is that count plus one. version goes up on every change. Send it as expected_version on PATCH, line item, and Order now requests, and on the buyer routes, to reject a change made after you read the subscription.

GET /v1/subscriptions filters by delivery_method_id to find every subscription using a method, and by hold_reason to find held subscriptions.

The Subscription object#

Every field on a subscription, as returned by retrieve and carried by the endpoints below.

Attributes

completed_atstring

RFC3339 timestamp.

created_atstringRequired

RFC3339 timestamp.

failed_countintegerRequired
failure_reason_countsarray of objectRequired
from_delivery_method_idstringRequired
moved_countintegerRequired
pending_countintegerRequired
statusenumRequired
  • pending
  • running
  • completed
subscription_delivery_migration_idstringRequired
subscription_plan_idstring
to_delivery_method_idstringRequired
total_countintegerRequired
updated_atstringRequired

RFC3339 timestamp.

Preview subscription delivery#

POST/v1/me/subscription-previews

Requires CustomerSessionBearer

Lists currently offered delivery methods and rates for a buyer's proposed destination without changing the subscription. Requires a full buyer session. A preview does not reserve a method or shipping rate.

Request body

destinationone ofRequired
modeenumRequired
  • delivery_options
subscription_idstringRequired

Response · 200

dataone ofRequired
metaobject
request_idstring
curl -X POST https://api.withflintpay.com/v1/me/subscription-previews \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": {},
    "mode": "delivery_options",
    "subscription_id": ""
  }'

Change subscription billing interval#

POST/v1/me/subscriptions/{subscription_id}/billing-intervalIdempotent

Requires CustomerSessionBearer

Changes future renewals to an interval currently offered by the subscription plan or frozen offer. Requires a full buyer session, billing_interval, and billing_interval_count. Send expected_version to reject concurrent changes.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

billing_intervalenumRequired
  • daily
  • weekly
  • monthly
  • yearly
billing_interval_countintegerRequired
expected_versioninteger

Response · 200

dataobjectRequired
metaobject
request_idstring
curl -X POST https://api.withflintpay.com/v1/me/subscriptions/sub_123/billing-interval \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "billing_interval": "daily",
    "billing_interval_count": 0
  }'

Update subscription delivery#

POST/v1/me/subscriptions/{subscription_id}/deliveryIdempotent

Requires CustomerSessionBearer

Saves an offered delivery method and destination for future renewals when buyer delivery changes are enabled. Requires a full buyer session. Send expected_version to reject concurrent changes. A paid shipment already in progress keeps its destination.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

deliveryobjectRequired
expected_versioninteger

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/me/subscriptions/sub_123/delivery \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "delivery": {
      "delivery_method_id": "",
      "destination": {},
      "type": "shipment"
    }
  }'

Swap subscription variant#

PATCH/v1/me/subscriptions/{subscription_id}/line-items/{subscription_line_item_id}Idempotent

Requires CustomerSessionBearer

Swaps a subscription line to an offered variant for future renewals. Requires a full buyer session. Send expected_version to reject concurrent changes. The replacement must remain deliverable to the subscription destination.

Path parameters

subscription_idstringRequired

Subscription ID.

subscription_line_item_idstringRequired

Subscription line item ID.

Request body

expected_versioninteger
variant_idstringRequired

Response · 200

Same response as Change subscription billing interval.

curl -X PATCH https://api.withflintpay.com/v1/me/subscriptions/sub_123/line-items/{subscription_line_item_id} \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "variant_id": ""
  }'

Change subscription quantity#

POST/v1/me/subscriptions/{subscription_id}/quantityIdempotent

Requires CustomerSessionBearer

Changes future renewals to a quantity currently offered by the subscription plan or frozen offer. Requires a full buyer session. Send expected_version to reject concurrent changes. Delivery eligibility is checked for the new quantity.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

expected_versioninteger
quantityintegerRequired

Whole-number quantity; fractional quantities are not supported.

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/me/subscriptions/sub_123/quantity \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "quantity": 0
  }'

Renew subscription now#

POST/v1/me/subscriptions/{subscription_id}/renewIdempotent

Requires CustomerSessionBearer

Charges the next renewal now, ships it when the subscription has delivery, and moves the next billing date forward by one interval. Available while the subscription is active on a Flint-owned billing schedule (billing_schedule_owner is flint), is not set to cancel at the end of its period, is not in a trial, and has no delivery hold or renewal in progress. The subscription's payment method must be active and allow off-session charges. Requires a full buyer session and Idempotency-Key. Send expected_version to reject concurrent changes. Retry with the same key to recover the same attempt.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

expected_versioninteger

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/me/subscriptions/sub_123/renew \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "expected_version": 0
  }'

Skip subscription cycle#

POST/v1/me/subscriptions/{subscription_id}/skip-cycleIdempotent

Requires CustomerSessionBearer

Skips the next renewal: nothing is charged or shipped for it, and the next billing date moves forward by one of the subscription's billing intervals. Available when buyer skipping is enabled and the subscription is active on a Flint-owned billing schedule (billing_schedule_owner is flint), is not set to cancel at the end of its period, and is under the store's consecutive skip limit. Requires a full buyer session. Send expected_version to reject concurrent changes.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

expected_versioninteger

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/me/subscriptions/sub_123/skip-cycle \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "expected_version": 0
  }'

List subscription delivery migrations#

GET/v1/subscription-delivery-migrations

Requires scope commerce.subscriptions.read or commerce.subscriptions.write

Each subscription is previewed before its delivery method changes. Progress and per-subscription failures remain available after completion.

Query parameters

page_sizeinteger
page_tokenstring
from_delivery_method_idstring
statusenum
  • pending
  • running
  • completed

Response · 200

dataarray of objectRequired
metaobject
next_page_tokenstring
request_idstring
curl https://api.withflintpay.com/v1/subscription-delivery-migrations \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Move subscribers to another delivery method#

POST/v1/subscription-delivery-migrationsIdempotent

Requires scope commerce.subscriptions.write

Each subscription is previewed before its delivery method changes. Progress and per-subscription failures remain available after completion.

Request body

from_delivery_method_idstringRequired
subscription_plan_idstring

Limit the migration to this plan's live subscriptions.

to_delivery_method_idstringRequired

Response · 202

dataobjectRequired
metaobject
request_idstring
curl -X POST https://api.withflintpay.com/v1/subscription-delivery-migrations \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "from_delivery_method_id": "",
    "to_delivery_method_id": ""
  }'
curl https://api.withflintpay.com/v1/subscription-delivery-migrations/{subscription_delivery_migration_id} \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

List subscriptions that could not be moved#

GET/v1/subscription-delivery-migrations/{subscription_delivery_migration_id}/failures

Requires scope commerce.subscriptions.read or commerce.subscriptions.write

Each subscription is previewed before its delivery method changes. Progress and per-subscription failures remain available after completion.

Path parameters

subscription_delivery_migration_idstringRequired

Subscription delivery migration ID.

Query parameters

page_sizeinteger
page_tokenstring
reasonenum
  • method_not_offered
  • destination_not_served
  • rate_unavailable
  • method_unavailable
  • no_longer_applicable
  • not_movable

Response · 200

dataarray of objectRequired
metaobject
next_page_tokenstring
request_idstring
curl https://api.withflintpay.com/v1/subscription-delivery-migrations/{subscription_delivery_migration_id}/failures \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Preview subscription#

POST/v1/subscription-previews

Requires scope commerce.subscriptions.write

Evaluates a proposed subscription, delivery destination, or delivery method update without saving changes. Malformed JSON, unknown fields and request-level problems (a missing or unsupported mode, fields that belong to another mode) return 400. In create mode, every problem with the proposed subscription is returned in errors with is_valid false, not only the first. A preview does not reserve inventory or guarantee a future shipping rate.

Request body

Send exactly one of these

destinationone ofRequired
modeenumRequired
  • delivery_options
subscription_idstringRequired

Response · 200

Same response as Preview subscription delivery.

curl -X POST https://api.withflintpay.com/v1/subscription-previews \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

List subscriptions#

GET/v1/subscriptions

Requires scope commerce.subscriptions.read or commerce.subscriptions.write

Returns a paginated list of subscriptions for the authenticated merchant.

Query parameters

page_sizeinteger

Page size, default 20, max 100.

page_tokenstring

Cursor returned by the previous list response.

statusarray of enum

Filter by subscription status. Repeat the parameter or pass comma-separated values to match multiple statuses.

  • trialing
  • active
  • paused
  • past_due
  • canceled
  • incomplete
billing_schedule_ownerenum

Filter by the system that supplies billing dates.

  • flint
  • external
awaiting_billing_scheduleboolean

Filter external schedules by whether they need another billing date.

cancel_at_period_endboolean

When true, returns subscriptions scheduled to cancel at the end of the current period that are not yet canceled. When false, returns every other subscription.

customer_idstring

Filter by Flint customer ID.

delivery_method_idstring

Filter by the subscription's selected delivery method.

hold_reasonenum

Filter by the reason of the current delivery_hold. Does not match upcoming delivery issues.

  • method_unavailable
  • destination_not_served
  • rate_unavailable
subscription_offer_idstring

Filter by Flint subscription offer ID.

subscription_plan_idstring

Filter by Flint subscription plan ID.

external_reference_idstring

Exact-match filter on the caller-owned external reference ID.

querystring

Search across subscription ID, external reference ID, customer, and plan. Text fields match any part of the value, and %, _ and \ are ordinary characters, not wildcards. IDs match from the start and need the type prefix, such as ord_01.

sort_byenum

Sort field.

  • created_at
  • updated_at
  • next_billing_at
sort_directionenum

Sort direction.

  • asc
  • desc
created_afterstring

RFC3339 lower bound for created_at.

created_beforestring

RFC3339 upper bound for created_at.

updated_afterstring

RFC3339 lower bound for updated_at.

updated_beforestring

RFC3339 upper bound for updated_at.

next_billing_at_afterstring

RFC3339 lower bound for next_billing_at.

next_billing_at_beforestring

RFC3339 upper bound for next_billing_at.

needs_attentionboolean

True matches subscriptions with a delivery hold, an upcoming delivery hold, an inventory wait, or a delivery-action-required pause, plus past_due, incomplete, or active subscriptions with next_billing_at more than 24 hours ago. False is the exact complement. Other filters still apply.

expandarray of enum

Supported expansions: customer, subscription_plan. Each expansion resolves with one batched lookup per page. Expansion requires commerce.subscriptions.read plus the read scope for each expanded resource. Limits: at most 10 unique expand paths per request; path depth at most 2. Repeat expand, for example expand=customer&expand=subscription_plan, or pass one comma-separated value.

  • customer
  • subscription_plan

Response · 200

dataarray of objectRequired
metaobject
next_page_tokenstring
request_idstring
curl https://api.withflintpay.com/v1/subscriptions \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "data": [
    {
      "billing_anchor_day": 15,
      "billing_interval": "monthly",
      "billing_interval_count": 1,
      "billing_schedule_owner": "flint",
      "buyer_actions": [],
      "cancel_at_period_end": false,
      "completed_cycles": 0,
      "created_at": "2026-03-17T14:30:00Z",
      "current_period_end": "2026-04-17T14:30:00Z",
      "current_period_start": "2026-03-17T14:30:00Z",
      "customer_id": "cus_123",
      "merchant_id": "mer_123",
      "metadata": {
        "source": "api"
      },
      "next_billing_at": "2026-04-17T14:30:00Z",
      "next_retry_at": null,
      "payment_method_id": "pm_123",
      "quantity": 0,
      "recurring_amount_money": {
        "amount": 4500,
        "currency": "USD"
      },
      "status": "active",
      "subscription_id": "sub_123",
      "subscription_plan_id": "plan_123",
      "updated_at": "2026-03-17T14:30:00Z",
      "version": 0
    }
  ],
  "next_page_token": "example",
  "request_id": "bce56cba-0827-44aa-bb56-4f200ba15ee6"
}

Create subscription#

POST/v1/subscriptionsIdempotent

Requires scope commerce.subscriptions.write

Creates a subscription for the authenticated merchant.

Request body

Send exactly one of these

Flint owns the renewal date. billing_anchor_day is allowed only in this branch.

billing_anchor_dayinteger
billing_intervalenum
  • daily
  • weekly
  • monthly
  • yearly
billing_interval_countinteger
billing_scheduleobjectRequired
billing_startone ofRequired

How billing begins. Send exactly one closed tagged-union branch.

customer_idstringRequired
deliveryobject
external_reference_idstring

Caller-owned identifier for this resource in an external system.

metadatamap of string
payment_method_idstring
quantityinteger

Whole-number quantity; fractional quantities are not supported.

service_locationone of
subscription_plan_idstringRequired

Response · 201

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "billing_anchor_day": 15,
    "billing_schedule": {
      "owner": "flint"
    },
    "billing_start": {
      "type": "immediate"
    },
    "customer_id": "cus_123",
    "metadata": {
      "source": "api"
    },
    "payment_method_id": "pm_123",
    "subscription_plan_id": "plan_123"
  }'

Get subscription#

GET/v1/subscriptions/{subscription_id}

Requires scope commerce.subscriptions.read or commerce.subscriptions.write

Returns a single subscription by ID. A paid checkout session's credential can retrieve only the subscription created by its source order. Checkout credentials cannot expand related resources.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Query parameters

expandarray of enum

Supported expansions: customer, payment_method, subscription_plan. Expansion requires commerce.subscriptions.read plus the read scope for each expanded resource. Limits: at most 10 unique expand paths per request; path depth at most 2. Repeat expand, for example expand=customer&expand=payment_method, or pass one comma-separated value.

  • customer
  • payment_method
  • subscription_plan

Response · 200

Same response as Change subscription billing interval.

curl https://api.withflintpay.com/v1/subscriptions/sub_123 \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "data": {
    "billing_anchor_day": 15,
    "billing_interval": "monthly",
    "billing_interval_count": 1,
    "billing_schedule_owner": "flint",
    "buyer_actions": [],
    "cancel_at_period_end": false,
    "completed_cycles": 0,
    "created_at": "2026-03-17T14:30:00Z",
    "current_period_end": "2026-04-17T14:30:00Z",
    "current_period_start": "2026-03-17T14:30:00Z",
    "customer_id": "cus_123",
    "merchant_id": "mer_123",
    "metadata": {
      "source": "api"
    },
    "next_billing_at": "2026-04-17T14:30:00Z",
    "next_retry_at": null,
    "payment_method_id": "pm_123",
    "quantity": 0,
    "recurring_amount_money": {
      "amount": 4500,
      "currency": "USD"
    },
    "status": "active",
    "subscription_id": "sub_123",
    "subscription_plan_id": "plan_123",
    "updated_at": "2026-03-17T14:30:00Z",
    "version": 0
  },
  "request_id": "bce56cba-0827-44aa-bb56-4f200ba15ee6"
}

Update subscription#

PATCH/v1/subscriptions/{subscription_id}Idempotent

Requires scope commerce.subscriptions.write

Updates metadata, external_reference_id, delivery, billing interval and quantity. A delivery change is checked with a delivery preview before it is saved. Send billing_interval and billing_interval_count together. The billing interval and quantity must be offered by the subscription plan or frozen offer, and apply from the next renewal. Send expected_version to reject concurrent changes. Change the payment method with the payment-method route and undo a scheduled cancellation with the reactivate route.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Request body

billing_intervalenum
  • daily
  • weekly
  • monthly
  • yearly
billing_interval_countinteger
deliveryobject
expected_versioninteger
external_reference_idstring

Caller-owned identifier for this resource in an external system.

metadatamap of string or null

Caller-owned metadata. Omit this field to leave metadata unchanged. Send an object to merge by key, set a key to null to remove it, or set metadata to null to clear all metadata. An empty object makes no change. Empty strings are stored. Keys starting with flint_ are reserved and cannot be written through the public API.

quantityinteger

Whole-number quantity; fractional quantities are not supported.

Response · 200

Same response as Change subscription billing interval.

curl -X PATCH https://api.withflintpay.com/v1/subscriptions/sub_123 \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "metadata": {
      "source": "customer_portal"
    }
  }'

Update subscription billing schedule#

PATCH/v1/subscriptions/{subscription_id}/billing-scheduleIdempotent

Requires scope commerce.subscriptions.write

Sets the next billing date, clears an external schedule while it awaits a date, or transfers schedule ownership. The response carries the updated subscription.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Request body

Send exactly one of these

billing_anchor_dayinteger
initiated_byenumRequired

Who asked for the schedule change: integration when your billing system sets the schedule, merchant for a change your team makes, or buyer for a change made at the buyer's request. The subscription.updated webhook reports this value as initiated_by.

  • buyer
  • merchant
  • integration
next_billing_atstringRequired

Future date at which Flint attempts the next charge.

ownerenumRequired
  • flint

Response · 200

Same response as Change subscription billing interval.

curl -X PATCH https://api.withflintpay.com/v1/subscriptions/sub_123/billing-schedule \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "initiated_by": "integration",
    "next_billing_at": "2026-05-17T14:30:00Z",
    "owner": "external"
  }'

Cancel subscription#

POST/v1/subscriptions/{subscription_id}/cancelIdempotent

Requires scope commerce.subscriptions.write

Cancels a subscription immediately or at period end, and records who asked, why, and when in cancellation_details. A buyer's cancellation follows the store's customer_account.buyer_capabilities.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Request body

cancel_immediatelyboolean

When true, ends the subscription now instead of at the end of the billing period. A buyer, in Flint's buyer account or with a customer session, may send it only when the store's customer_account.buyer_capabilities.cancellation_timing is buyer_chooses; otherwise the request returns CANCEL_IMMEDIATELY_NOT_ALLOWED. A trialing, paused, or incomplete subscription, or one whose first paid period never started, ends now either way.

cancellation_commentstring

Free text about the cancellation, up to 500 characters after surrounding spaces are trimmed. Recorded in cancellation_details.comment, which only merchant credentials read.

cancellation_reason_codeenum

Optional. Why the subscription is being canceled. When the store lists customer_account.buyer_capabilities.cancellation_reasons, a reason a buyer sends must be one of them; merchant credentials may send any code. Recorded in cancellation_details.reason_code.

  • too_expensive
  • missing_features
  • switched_service
  • unused
  • customer_service
  • too_complex
  • low_quality
  • other

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/cancel \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "cancel_immediately": false,
    "cancellation_reason_code": "too_expensive"
  }'

Add subscription line item#

POST/v1/subscriptions/{subscription_id}/line-itemsIdempotent

Requires scope commerce.subscriptions.write

Adds a catalog variant or bundle to future subscription renewals. Current prices and delivery eligibility are checked before the line is saved. Already-created orders keep their lines.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

Send exactly one of these

expected_versioninteger
quantityintegerRequired

Whole-number quantity; fractional quantities are not supported.

variant_idstringRequired

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/line-items \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "quantity": 0
  }'

Update subscription line item#

PATCH/v1/subscriptions/{subscription_id}/line-items/{subscription_line_item_id}Idempotent

Requires scope commerce.subscriptions.write

Updates a subscription line for future renewals. Send expected_version to reject a concurrent change. Already-created orders keep their lines.

Path parameters

subscription_idstringRequired

Subscription ID.

subscription_line_item_idstringRequired

Subscription line item ID.

Request body

expected_versioninteger
quantityinteger

Whole-number quantity; fractional quantities are not supported.

variant_idstring

Response · 200

Same response as Change subscription billing interval.

curl -X PATCH https://api.withflintpay.com/v1/subscriptions/sub_123/line-items/{subscription_line_item_id} \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "expected_version": 0,
    "quantity": 0,
    "variant_id": ""
  }'

Remove subscription line item#

DELETE/v1/subscriptions/{subscription_id}/line-items/{subscription_line_item_id}Idempotent

Requires scope commerce.subscriptions.write

Removes a line from future subscription renewals. The final line cannot be removed. Send expected_version as a query parameter to reject a concurrent change.

Path parameters

subscription_idstringRequired

Subscription ID.

subscription_line_item_idstringRequired

Subscription line item ID.

Query parameters

expected_versioninteger

Response · 200

Same response as Change subscription billing interval.

curl -X DELETE https://api.withflintpay.com/v1/subscriptions/sub_123/line-items/{subscription_line_item_id} \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Pause subscription#

POST/v1/subscriptions/{subscription_id}/pauseIdempotent

Requires scope commerce.subscriptions.write

Pauses a subscription immediately, optionally for a fixed number of billing cycles. A buyer's pause follows the store's customer_account.buyer_capabilities.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Request body

pause_duration_cyclesinteger

Billing cycles to pause for. Omit it to pause until the subscription is resumed. When the store's customer_account.buyer_capabilities.pause.max_cycles is set, a buyer must send a value from 1 to that limit.

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/pause \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "pause_duration_cycles": 2
  }'
curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/payment-method \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "payment_method_id": "pm_123"
  }'

List subscription payment retries#

GET/v1/subscriptions/{subscription_id}/payment-retries

Requires scope commerce.subscriptions.read or commerce.subscriptions.write

Returns a subscription's manual payment retries, newest first.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Query parameters

page_sizeinteger

Page size, default 20, max 100.

page_tokenstring

Cursor returned by the previous list response.

idempotency_keystring

Filter by the original Idempotency-Key.

Response · 200

dataarray of objectRequired
metaobject
next_page_tokenstring
request_idstring
curl https://api.withflintpay.com/v1/subscriptions/sub_123/payment-retries \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "data": [
    {
      "created_at": "2026-04-17T14:31:00Z",
      "idempotency_key": "retry-2026-04-17",
      "status": "pending",
      "subscription_id": "sub_123",
      "subscription_payment_retry_id": "spr_123",
      "updated_at": "2026-04-17T14:31:00Z"
    }
  ],
  "next_page_token": "example",
  "request_id": "bce56cba-0827-44aa-bb56-4f200ba15ee6"
}

Retry subscription payment#

POST/v1/subscriptions/{subscription_id}/payment-retriesIdempotent

Requires scope commerce.subscriptions.write

Starts one manual collection attempt on a past-due subscription. Send no body, or an empty object. Poll the returned retry for the outcome.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Response · 201

dataobjectRequired
metaobject
request_idstring
curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/payment-retries \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{}'
curl https://api.withflintpay.com/v1/subscriptions/sub_123/payment-retries/spr_123 \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "data": {
    "created_at": "2026-04-17T14:31:00Z",
    "idempotency_key": "retry-2026-04-17",
    "status": "pending",
    "subscription_id": "sub_123",
    "subscription_payment_retry_id": "spr_123",
    "updated_at": "2026-04-17T14:31:00Z"
  },
  "request_id": "bce56cba-0827-44aa-bb56-4f200ba15ee6"
}
curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/reactivate \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Renew subscription now#

POST/v1/subscriptions/{subscription_id}/renewIdempotent

Requires scope commerce.subscriptions.write

Charges the next renewal now, ships it when the subscription has delivery, and moves the next billing date forward by one interval. Available while the subscription is active on a Flint-owned billing schedule (billing_schedule_owner is flint), is not set to cancel at the end of its period, is not in a trial, and has no delivery hold or renewal in progress. The subscription's payment method must be active and allow off-session charges. Requires Idempotency-Key; retry with the same key to recover the same attempt. Returns the resulting subscription after collection.

Path parameters

subscription_idstringRequired

Subscription ID.

Request body

expected_versioninteger

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/renew \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "expected_version": 0
  }'

Resume subscription#

POST/v1/subscriptions/{subscription_id}/resumeIdempotent

Requires scope commerce.subscriptions.write

Requests resumption of a paused subscription. Processing is asynchronous, so the response can still show paused. Retrieve the subscription to follow its status. Paid access resumes only when the subscription is active; overdue payment must be collected first.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/resume \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Skip subscription cycle#

POST/v1/subscriptions/{subscription_id}/skip-cycleIdempotent

Requires scope commerce.subscriptions.write

Skips the next renewal: nothing is charged or shipped for it, and the next billing date moves forward by one of the subscription's billing intervals. Available while the subscription is active, is not set to cancel at the end of its period, and has a next billing date.

Path parameters

subscription_idstringRequired

Flint subscription ID.

Request body

expected_versioninteger
initiated_byenum

Who asked for the skip. Defaults to merchant. Send buyer when you skip at the buyer's request. The subscription.cycle_skipped webhook reports this value as initiated_by.

  • buyer
  • merchant
  • integration

Response · 200

Same response as Change subscription billing interval.

curl -X POST https://api.withflintpay.com/v1/subscriptions/sub_123/skip-cycle \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "initiated_by": "merchant"
  }'

Was this helpful?