API reference

Subscriptions and bills

  • 7 endpoints

Subscriptions are created by completing a checkout (no create route here): a paid subscription is recorded once the customer's on-chain transaction is confirmed (404 until then), a free trial once the customer signed the trial's message at the checkout (status: "trial"). A subscription's uuid is sub@-prefixed and is the same as its checkout session's uuid, for life. The timeline, the webhooks and when to grant access: Subscriptions.

List subscriptions#

GET /subscriptions

Lists the subscriptions of the request's space (with includeMembers, of the organization and its members; with userUuid, of one member), newest first, cancelled ones included unless filtered out. reference: the one with that merchant reference (0 or 1 item).

Auth
X-API-Key: any key
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl https://api.qbitflow.app/v2/subscriptions \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a page of Subscription ({ items, hasMore, nextCursor? })

Query parameters

  • limitintegerOptional

    Page size: 20 when absent or ≤ 0, at most 100 (a larger one is clamped, not refused)

  • cursorstringOptional

    The previous page's nextCursor, verbatim; omit for the first page

    max=200

  • customerUuidstringOptional

    Only this customer's

  • productUuidstringOptional

    Only this product's

  • createdAfterstringOptional

    Only those created after this instant, excluded (RFC 3339, e.g. 2026-10-04T12:00:00Z, or a date: its midnight UTC)

  • createdBeforestringOptional

    Only those created before this instant, excluded (RFC 3339 or a date, as createdAfter)

  • includeMembersbooleanOptional

    The organization's space only (the team, its keys without On-Behalf-Of): its members' too, each naming its member (userUuid). From a member's space → 400 on includeMembers

  • userUuidstringOptional

    The organization's space only (owners and admins): this member's only, read from the organization's space (a removed member's too). Not with includeMembers (400 on userUuid)

  • statusstringOptional

    Only those in this status: trial, trialExpired, active, pastDue, paused, stopped or cancelled (cancelled ones are listed too unless filtered out)

    max=32

    One of:

    • trialStatusTrial is a free trial: nothing was signed on-chain yet.
    • trialExpiredStatusTrialExpired is a trial that ended without its customer confirming it (actionRequired confirmTrial): cancelled after the grace period unless they subscribe.
    • activeStatusActive is a subscription billed on its due dates. Its customer may have something to do (actionRequired: topUpAllowance, raiseMaximum) while it stays active.
    • pastDueStatusPastDue indicates a subscription whose last bill failed: its retries run.
    • pausedStatusPaused is a subscription its customer paused (a message signed with its wallet): QBitFlow doesn't bill it until they resume it. On-chain it is still active. It keeps the period it paid for (currentPeriodEnd).
    • stoppedStatusStopped is a subscription cancelled during its billing period (by its customer, or its merchant's force cancel with immediate=false): never billed again, it still runs until its paid period ends (nextBillingDate), then it is cancelled.
    • cancelledStatusCancelled indicates a cancelled subscription.
  • referencestringOptional

    Only the one with this reference

    referencemax=100

Response

A page: { "items": Subscription[], "hasMore": …, "nextCursor"?: … }. Pass nextCursor back as cursor for the next page; it is absent when hasMore is false.

30 fields of each Subscription
  • uuidstring

    Its id (sub@…): the checkout session's

    A prefixed id (pay@…, sub@…)

  • referencestringOptional

    The merchant's reference for the subscription (an order or customer id), set when creating its checkout. Only for the merchant: never in the public reads by uuid (GET /hosted/transactions/:txUuid)

    Only for the resource's owner

  • createdAtstring
  • updatedAtstring

    Its last change (a bill, a status, its metadata)

  • fromstring

    The subscriber's wallet: the one it bills. Absent when unknown (a trial not confirmed yet may have none)

  • tostring

    The wallet its bills pay: the merchant's (or, while the organization holds a member's funds, the organization's)

  • productUuidstring

    Its product (GET /products/:uuid). Absent without one

  • subscriptionHashstring

    The hash of the transaction that created the subscription on-chain. Absent until then (a trial, until its customer confirms it)

  • currencyIdinteger

    The currency (token) billed, written as the currency object under currency (GET /currencies/:id)

  • frequencyDuration

    Billing interval in seconds, as on-chain (e.g. 2592000 = 30 days). Written as a types.Duration in responses and webhooks (e.g. {"value": 1, "unit": "months"})

    2 fields of Duration
    • valueinteger

      Number of units; 0 means no duration

    • unitstring

      Required when value > 0. "months" = 30 days, "years" = 365 days

      oneof=seconds minutes hours days weeks months years

  • statusstring

    SubscriptionStatus (status) is where it stands: trial, trialExpired, active, pastDue, paused, stopped or cancelled. Every change sends subscription.statusChanged. Don't grant access from it: grant access while now < accessUntil (docs/api/guides/subscriptions.md § Access)

    One of:

    • trialStatusTrial is a free trial: nothing was signed on-chain yet.
    • trialExpiredStatusTrialExpired is a trial that ended without its customer confirming it (actionRequired confirmTrial): cancelled after the grace period unless they subscribe.
    • activeStatusActive is a subscription billed on its due dates. Its customer may have something to do (actionRequired: topUpAllowance, raiseMaximum) while it stays active.
    • pastDueStatusPastDue indicates a subscription whose last bill failed: its retries run.
    • pausedStatusPaused is a subscription its customer paused (a message signed with its wallet): QBitFlow doesn't bill it until they resume it. On-chain it is still active. It keeps the period it paid for (currentPeriodEnd).
    • stoppedStatusStopped is a subscription cancelled during its billing period (by its customer, or its merchant's force cancel with immediate=false): never billed again, it still runs until its paid period ends (nextBillingDate), then it is cancelled.
    • cancelledStatusCancelled indicates a cancelled subscription.
  • actionRequiredstringOptional

    ActionRequired is what its customer must do, if anything (absent: nothing): topUpAllowance (the allowance covers about one more bill at most), raiseMaximum (a bill waits for a new maximum per period), confirmTrial (the trial ended unconfirmed). Every change (set, changed or cleared) sends subscription.actionRequiredChanged

    One of

    • topUpAllowanceActionTopUpAllowance: what remains of the allowance covers about one more bill at most (or none). The customer adds periods from their management page.
    • raiseMaximumActionRaiseMaximum: a bill is above the maximum per period the customer signed (the token's price moved); it waits up to 7 days for a new maximum, signed from the management page.
    • confirmTrialActionConfirmTrial: the trial ended unconfirmed (trialExpired); the customer subscribes from their management page before the grace period ends.
  • currentPeriodEndstringOptional

    CurrentPeriodEnd is the paid-through date. A trial: its end. active, paused, stopped: the end of the period paid for (the next bill's due date). pastDue: the start of the unpaid period (past). cancelled: when it was cancelled, or the end of its last paid period if that came first. For access, read accessUntil: an active subscription is renewed a few minutes after this date

  • accessUntilstringOptional

    AccessUntil is when access ends: grant it while now < accessUntil, whatever the status. An active subscription: currentPeriodEnd plus 1 hour, since its renewal is billed within minutes of its due date (a subscriber whose bill is on its way keeps access; a failed bill sets pastDue). Every other status: currentPeriodEnd

  • priceUsdstring

    PriceUSD is the price per period the customer subscribed at, in USD (a decimal string, e.g. "9.99"), locked at signup (a free trial's too): every bill charges it and its lines (fees), converted to the token at the bill's price. A later change of the product's price applies to new subscribers only. Never "0"

  • feesarray of FeeLine

    Fees is what its checkout added to the price, line by line, as the customer saw them (a tax, shipping, the processing fee when the customer pays it), locked at signup with the price: every bill charges priceUsd plus these lines. [] without any

    4 fields of each FeeLine
    • typestring

      custom (the merchant's line) or processingFee (QBitFlow's fee, which the merchant has the customer pay)

      One of:

      • customThe merchant's own line: a tax, shipping, a service fee
      • processingFeeQBitFlow's fee, which the merchant has the customer pay (computed by QBitFlow)
    • labelstring

      The line's name, as the checkout shows it ("Processing fee" for the processing fee)

    • descriptionstringOptional

      Optional: more about the line, as the merchant wrote it. Omitted without one

    • amountUsdstring

      The line's amount in USD, a decimal string with at most 2 decimals

  • allowanceAllowanceOptional

    AllowanceStatus (allowance) is what the subscriber's wallet still lets QBitFlow bill, and the most one bill may charge, at today's price. Absent during a free trial (nothing signed yet)

    6 fields of Allowance
    • amountstring

      In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

    • amountMinUnitsstring

      The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

    • amountUsdstringOptional

      Its value in USD, a decimal string; absent when no price was known

    • remainingPeriodsintegerOptional

      RemainingPeriods is how many whole bills the allowance still covers at today's price: the allowance divided by a bill (priceUsd and its fees, converted to the token), rounded down, before the network fee each bill adds. 0 is a value: the customer must top it up (actionRequired topUpAllowance) before the next bill. Absent without a price

    • maxPerPeriodstringOptional

      MaxPerPeriod is the most one bill may charge, as the subscriber signed it, in the token's units (maxPerPeriodMinUnits: its on-chain integer): a bill above it waits for a new maximum (actionRequired raiseMaximum). Absent when the subscription has none recorded

    • maxPerPeriodMinUnitsstringOptional
  • lastBilledAtstringOptional

    When it was last billed. Absent before its first bill (a trial)

  • nextBillingAtstringOptional

    When its next bill is due (a trial: when it ends; stopped: when it is cancelled). Absent once cancelled

  • cancelledAtstringOptional

    When it was cancelled (absent until then, and for subscriptions cancelled before it was recorded)

  • cancellationReasonstringOptional

    Why it stopped or was cancelled: customer, merchant, billingFailed, trialNotConverted, merchantClosed or inactiveOnChain. Absent while it runs (and for subscriptions cancelled before it was recorded)

    One of:

    • customerCancelledByCustomer: its customer cancelled it (it was stopped until its period ended).
    • merchantCancelledByMerchant: its merchant cancelled it (POST /subscriptions/:uuid/cancel).
    • billingFailedCancelledBillingFailed: its bill's last attempt failed.
    • trialNotConvertedCancelledTrialNotConverted: its trial ended and its customer didn't subscribe within the grace period.
    • merchantClosedCancelledMerchantClosed: its merchant's space closed (a member removed, the organization closed).
    • inactiveOnChainCancelledInactiveOnChain: the contract no longer had it active (cancelled outside QBitFlow).
  • cancellableAtstringOptional

    MinimumCancellationDate (cancellableAt) is the earliest its customer may cancel it (the checkout's minPeriods). Absent when they may cancel it any time

  • metadatamapOptional

    Metadata is the merchant's own key-value data: its checkout session's, copied when the subscription was created, then changed with PATCH /subscriptions/:uuid (merged). {} when none. Only for the merchant (API and webhooks)

    Only for the resource's owner

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • customerUuidstringOptional

    The customer, when QBitFlow has one (named by the checkout, found by its customerReference, or recorded from the details the customer gave); omitted otherwise

    Only for the resource's owner

  • customerReferencestringOptional

    The merchant's reference of the customer, as the checkout was given it (customerReference), whether or not QBitFlow has a customer with it; omitted otherwise

    Only for the resource's owner

  • customerSummaryOptional

    The customer, named (merchant only, API reads): who paid, even once deleted. Omitted without one

    Only for the resource's owner

    6 fields of Summary
    • uuidstring

      The customer (GET /customers/:uuid)

    • firstNamestring

      First name

    • lastNamestringOptional

      Last name, when given

    • emailstring

      Email, lowercase

    • referencestringOptional

      The merchant's reference of the customer, when it has one

    • deletedboolean

      The merchant deleted the customer: it still names its rows, but GET /customers/:uuid answers 404

  • dunningDunningStatusOptional

    DunningStatus (dunning) is where its failing bill's retries stand: the failed attempts, the next one, a wait for a new maximum. Omitted while no bill is failing. API reads only: webhooks tell each failure with subscription.billingFailed

    5 fields of DunningStatus
    • failedAttemptsinteger

      The bill's failed attempts so far (0 while it only waits for a new maximum)

    • remainingAttemptsinteger

      Attempts left: after the last one fails, the subscription is cancelled

    • failingSincestringOptional

      The bill's first failed attempt: when the subscription went past due. Omitted without one

    • nextAttemptAtstringOptional

      When the bill is tried again at the latest (sooner once the customer tops up or raises their allowance). Omitted when none is scheduled

    • awaitingMaximumSincestringOptional

      While the bill is above the customer's maximum (actionRequired raiseMaximum): when it started waiting for them to raise it. nextAttemptAt is then when the wait ends. Omitted otherwise

Get subscription#

GET /subscriptions/:uuid

Reads one of the caller's subscriptions (sub@… or its bare uuid), whatever its status (a cancelled one too), with its customer's management page and its allowance at today's price. Another space's, an unknown one or another kind of id → 404.

Auth
X-API-Key: any key
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl "https://api.qbitflow.app/v2/subscriptions/$SUBSCRIPTION_UUID" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a Subscription
// Any status, cancelled included. Before its checkout completes, it is a 404.const subscription = await client.subscriptions.get(subscriptionUuid);console.log(`${subscription.uuid}: ${subscription.status}`);console.log(`paid until ${subscription.currentPeriodEnd ?? '—'}`);
subscription = client.subscriptions.get(subscription_uuid)  # sub@…, cancelled ones tooprint(subscription.status, "paid until", subscription.current_period_end)
sub, err := client.Subscriptions.Get(ctx, subscriptionUUID, nil) // sub@…, cancelled ones tooif err != nil {	log.Fatal(err)}fmt.Println(sub.UUID, sub.Status) // trial, active, pastDue, stopped, cancelled…if sub.CurrentPeriodEnd != nil {	fmt.Println("paid until", sub.CurrentPeriodEnd.Format(time.RFC3339))}
$subscription = $client->subscriptions->get($subscriptionUuid); // sub@…printf("%s: %s, paid until %s\n", $subscription->uuid, $subscription->status, $subscription->currentPeriodEnd?->format('Y-m-d') ?? '-');
Check access to a subscription

has-access.sh

# Grant access while now < accessUntil, whatever the status: a stopped or paused# subscription has paid for its period, an active one keeps an hour while its renewal confirms.curl "https://api.qbitflow.app/v2/subscriptions/$SUBSCRIPTION_UUID" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: { "uuid": "sub@…", "status": "active", "currentPeriodEnd": "2026-10-31T12:00:00Z", "accessUntil": "2026-10-31T13:00:00Z", … }
// Grant access while now < accessUntil, whatever the status: a stopped or paused// subscription has paid for its period, and an active one keeps it while its renewal is billed.const subscription = await client.subscriptions.get(subscriptionUuid);if (hasAccess(subscription)) {	console.log('serve the premium content');} else {	console.log('access ended: show the renewal page');}
subscription = client.subscriptions.get(subscription_uuid)# now is before access_until, whatever the status: the end of the period paid for, plus an# hour for an active subscription while its renewal is billed.if subscription.has_access():    print("grant access")else:    print("no access")
// Access lasts while now < AccessUntil, whatever the status: the end of the period paid// for, plus an hour for an active subscription while its renewal is billed.sub, err := client.Subscriptions.Get(ctx, subscriptionUUID, nil)if err != nil {	log.Fatal(err)}if sub.HasAccess(time.Now()) { // now before AccessUntil	fmt.Println("access granted until", sub.AccessUntil.Format(time.RFC3339))} else {	fmt.Println("no access")}
$subscription = $client->subscriptions->get($subscriptionUuid);// now < accessUntil, whatever the status: the end of the period paid for, plus an hour for an// active subscription while its renewal is billed.if ($subscription->hasAccess()) {	echo "Access granted\n";} else {	echo "No access: the paid period has ended\n";}

Path parameters

  • uuidstringRequired

    Its prefixed uuid (or the bare uuid)

    txuuid

Query parameters

  • includeMembersbooleanOptional

    The organization's space only (the team, its keys without On-Behalf-Of): a member's too, naming its member (userUuid). Read only: acting on it still switches into the member's space or uses On-Behalf-Of. From a member's space → 400 on includeMembers

Response

A Subscription.

30 fields of Subscription
  • uuidstring

    Its id (sub@…): the checkout session's

    A prefixed id (pay@…, sub@…)

  • referencestringOptional

    The merchant's reference for the subscription (an order or customer id), set when creating its checkout. Only for the merchant: never in the public reads by uuid (GET /hosted/transactions/:txUuid)

    Only for the resource's owner

  • createdAtstring
  • updatedAtstring

    Its last change (a bill, a status, its metadata)

  • fromstring

    The subscriber's wallet: the one it bills. Absent when unknown (a trial not confirmed yet may have none)

  • tostring

    The wallet its bills pay: the merchant's (or, while the organization holds a member's funds, the organization's)

  • productUuidstring

    Its product (GET /products/:uuid). Absent without one

  • subscriptionHashstring

    The hash of the transaction that created the subscription on-chain. Absent until then (a trial, until its customer confirms it)

  • currencyIdinteger

    The currency (token) billed, written as the currency object under currency (GET /currencies/:id)

  • frequencyDuration

    Billing interval in seconds, as on-chain (e.g. 2592000 = 30 days). Written as a types.Duration in responses and webhooks (e.g. {"value": 1, "unit": "months"})

    2 fields of Duration
    • valueinteger

      Number of units; 0 means no duration

    • unitstring

      Required when value > 0. "months" = 30 days, "years" = 365 days

      oneof=seconds minutes hours days weeks months years

  • statusstring

    SubscriptionStatus (status) is where it stands: trial, trialExpired, active, pastDue, paused, stopped or cancelled. Every change sends subscription.statusChanged. Don't grant access from it: grant access while now < accessUntil (docs/api/guides/subscriptions.md § Access)

    One of:

    • trialStatusTrial is a free trial: nothing was signed on-chain yet.
    • trialExpiredStatusTrialExpired is a trial that ended without its customer confirming it (actionRequired confirmTrial): cancelled after the grace period unless they subscribe.
    • activeStatusActive is a subscription billed on its due dates. Its customer may have something to do (actionRequired: topUpAllowance, raiseMaximum) while it stays active.
    • pastDueStatusPastDue indicates a subscription whose last bill failed: its retries run.
    • pausedStatusPaused is a subscription its customer paused (a message signed with its wallet): QBitFlow doesn't bill it until they resume it. On-chain it is still active. It keeps the period it paid for (currentPeriodEnd).
    • stoppedStatusStopped is a subscription cancelled during its billing period (by its customer, or its merchant's force cancel with immediate=false): never billed again, it still runs until its paid period ends (nextBillingDate), then it is cancelled.
    • cancelledStatusCancelled indicates a cancelled subscription.
  • actionRequiredstringOptional

    ActionRequired is what its customer must do, if anything (absent: nothing): topUpAllowance (the allowance covers about one more bill at most), raiseMaximum (a bill waits for a new maximum per period), confirmTrial (the trial ended unconfirmed). Every change (set, changed or cleared) sends subscription.actionRequiredChanged

    One of

    • topUpAllowanceActionTopUpAllowance: what remains of the allowance covers about one more bill at most (or none). The customer adds periods from their management page.
    • raiseMaximumActionRaiseMaximum: a bill is above the maximum per period the customer signed (the token's price moved); it waits up to 7 days for a new maximum, signed from the management page.
    • confirmTrialActionConfirmTrial: the trial ended unconfirmed (trialExpired); the customer subscribes from their management page before the grace period ends.
  • currentPeriodEndstringOptional

    CurrentPeriodEnd is the paid-through date. A trial: its end. active, paused, stopped: the end of the period paid for (the next bill's due date). pastDue: the start of the unpaid period (past). cancelled: when it was cancelled, or the end of its last paid period if that came first. For access, read accessUntil: an active subscription is renewed a few minutes after this date

  • accessUntilstringOptional

    AccessUntil is when access ends: grant it while now < accessUntil, whatever the status. An active subscription: currentPeriodEnd plus 1 hour, since its renewal is billed within minutes of its due date (a subscriber whose bill is on its way keeps access; a failed bill sets pastDue). Every other status: currentPeriodEnd

  • priceUsdstring

    PriceUSD is the price per period the customer subscribed at, in USD (a decimal string, e.g. "9.99"), locked at signup (a free trial's too): every bill charges it and its lines (fees), converted to the token at the bill's price. A later change of the product's price applies to new subscribers only. Never "0"

  • feesarray of FeeLine

    Fees is what its checkout added to the price, line by line, as the customer saw them (a tax, shipping, the processing fee when the customer pays it), locked at signup with the price: every bill charges priceUsd plus these lines. [] without any

    4 fields of each FeeLine
    • typestring

      custom (the merchant's line) or processingFee (QBitFlow's fee, which the merchant has the customer pay)

      One of:

      • customThe merchant's own line: a tax, shipping, a service fee
      • processingFeeQBitFlow's fee, which the merchant has the customer pay (computed by QBitFlow)
    • labelstring

      The line's name, as the checkout shows it ("Processing fee" for the processing fee)

    • descriptionstringOptional

      Optional: more about the line, as the merchant wrote it. Omitted without one

    • amountUsdstring

      The line's amount in USD, a decimal string with at most 2 decimals

  • allowanceAllowanceOptional

    AllowanceStatus (allowance) is what the subscriber's wallet still lets QBitFlow bill, and the most one bill may charge, at today's price. Absent during a free trial (nothing signed yet)

    6 fields of Allowance
    • amountstring

      In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

    • amountMinUnitsstring

      The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

    • amountUsdstringOptional

      Its value in USD, a decimal string; absent when no price was known

    • remainingPeriodsintegerOptional

      RemainingPeriods is how many whole bills the allowance still covers at today's price: the allowance divided by a bill (priceUsd and its fees, converted to the token), rounded down, before the network fee each bill adds. 0 is a value: the customer must top it up (actionRequired topUpAllowance) before the next bill. Absent without a price

    • maxPerPeriodstringOptional

      MaxPerPeriod is the most one bill may charge, as the subscriber signed it, in the token's units (maxPerPeriodMinUnits: its on-chain integer): a bill above it waits for a new maximum (actionRequired raiseMaximum). Absent when the subscription has none recorded

    • maxPerPeriodMinUnitsstringOptional
  • lastBilledAtstringOptional

    When it was last billed. Absent before its first bill (a trial)

  • nextBillingAtstringOptional

    When its next bill is due (a trial: when it ends; stopped: when it is cancelled). Absent once cancelled

  • cancelledAtstringOptional

    When it was cancelled (absent until then, and for subscriptions cancelled before it was recorded)

  • cancellationReasonstringOptional

    Why it stopped or was cancelled: customer, merchant, billingFailed, trialNotConverted, merchantClosed or inactiveOnChain. Absent while it runs (and for subscriptions cancelled before it was recorded)

    One of:

    • customerCancelledByCustomer: its customer cancelled it (it was stopped until its period ended).
    • merchantCancelledByMerchant: its merchant cancelled it (POST /subscriptions/:uuid/cancel).
    • billingFailedCancelledBillingFailed: its bill's last attempt failed.
    • trialNotConvertedCancelledTrialNotConverted: its trial ended and its customer didn't subscribe within the grace period.
    • merchantClosedCancelledMerchantClosed: its merchant's space closed (a member removed, the organization closed).
    • inactiveOnChainCancelledInactiveOnChain: the contract no longer had it active (cancelled outside QBitFlow).
  • cancellableAtstringOptional

    MinimumCancellationDate (cancellableAt) is the earliest its customer may cancel it (the checkout's minPeriods). Absent when they may cancel it any time

  • metadatamapOptional

    Metadata is the merchant's own key-value data: its checkout session's, copied when the subscription was created, then changed with PATCH /subscriptions/:uuid (merged). {} when none. Only for the merchant (API and webhooks)

    Only for the resource's owner

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • customerUuidstringOptional

    The customer, when QBitFlow has one (named by the checkout, found by its customerReference, or recorded from the details the customer gave); omitted otherwise

    Only for the resource's owner

  • customerReferencestringOptional

    The merchant's reference of the customer, as the checkout was given it (customerReference), whether or not QBitFlow has a customer with it; omitted otherwise

    Only for the resource's owner

  • customerSummaryOptional

    The customer, named (merchant only, API reads): who paid, even once deleted. Omitted without one

    Only for the resource's owner

    6 fields of Summary
    • uuidstring

      The customer (GET /customers/:uuid)

    • firstNamestring

      First name

    • lastNamestringOptional

      Last name, when given

    • emailstring

      Email, lowercase

    • referencestringOptional

      The merchant's reference of the customer, when it has one

    • deletedboolean

      The merchant deleted the customer: it still names its rows, but GET /customers/:uuid answers 404

  • dunningDunningStatusOptional

    DunningStatus (dunning) is where its failing bill's retries stand: the failed attempts, the next one, a wait for a new maximum. Omitted while no bill is failing. API reads only: webhooks tell each failure with subscription.billingFailed

    5 fields of DunningStatus
    • failedAttemptsinteger

      The bill's failed attempts so far (0 while it only waits for a new maximum)

    • remainingAttemptsinteger

      Attempts left: after the last one fails, the subscription is cancelled

    • failingSincestringOptional

      The bill's first failed attempt: when the subscription went past due. Omitted without one

    • nextAttemptAtstringOptional

      When the bill is tried again at the latest (sooner once the customer tops up or raises their allowance). Omitted when none is scheduled

    • awaitingMaximumSincestringOptional

      While the bill is above the customer's maximum (actionRequired raiseMaximum): when it started waiting for them to raise it. nextAttemptAt is then when the wait ends. Omitted otherwise

Update subscription#

PATCH /subscriptions/:uuid

Changes a subscription's metadata (merged: a key with "" is deleted, keys not named are kept; at most 50 keys once merged), cancelled ones too, and answers the subscription. Its price, terms and status don't change here. Another space's → 404.

Auth
X-API-Key: any keyA member's key needs the members.subscriptions policy
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl -X PATCH "https://api.qbitflow.app/v2/subscriptions/$SUBSCRIPTION_UUID" \  -H "X-API-Key: $QBITFLOW_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "metadata": {      "plan": "pro"    }  }'# 200: a Subscription
// Metadata is merged into the subscription's: '' deletes a key, keys not named are kept. It// is the only thing a merchant edits on a subscription; webhooks carry it.const updated = await client.subscriptions.update(subscriptionUuid, {	metadata: { plan: 'pro', coupon: '' },});console.log(updated.metadata.plan);
# Metadata is merged into the subscription's: "" deletes a key, keys not named are kept.# It is the only thing a merchant edits on a subscription; webhooks carry it.updated = client.subscriptions.update(subscription_uuid, metadata={"plan": "pro", "coupon": ""})print(updated.metadata.get("plan"))
// Metadata is merged into the subscription's: "" deletes a key, keys not named are kept.// It is the only thing a merchant edits on a subscription; webhooks carry it.updated, err := client.Subscriptions.Update(ctx, subscriptionUUID, &qbitflow.UpdateSubscriptionParams{	Metadata: map[string]string{"plan": "pro", "coupon": ""},})if err != nil {	log.Fatal(err)}fmt.Println(updated.Metadata["plan"])
// Metadata is merged into the subscription's: '' deletes a key, keys not named are kept. It is the// only thing a merchant edits on a subscription; webhooks carry it.$updated = $client->subscriptions->update($subscriptionUuid, new \QBitFlow\Params\UpdateSubscriptionParams(	metadata: ['plan' => 'pro', 'coupon' => ''],));echo ($updated->metadata['plan'] ?? '-') . "\n";

Path parameters

  • uuidstringRequired

    The subscription: sub@… or its bare uuid

    txuuid

Body

  • metadatamapOptional

    Metadata is merged into the subscription's (absent: unchanged): a key with a value sets it, a key with "" deletes it, keys not named are kept. At most 50 keys once merged

    metadata

Response

A Subscription.

30 fields of Subscription
  • uuidstring

    Its id (sub@…): the checkout session's

    A prefixed id (pay@…, sub@…)

  • referencestringOptional

    The merchant's reference for the subscription (an order or customer id), set when creating its checkout. Only for the merchant: never in the public reads by uuid (GET /hosted/transactions/:txUuid)

    Only for the resource's owner

  • createdAtstring
  • updatedAtstring

    Its last change (a bill, a status, its metadata)

  • fromstring

    The subscriber's wallet: the one it bills. Absent when unknown (a trial not confirmed yet may have none)

  • tostring

    The wallet its bills pay: the merchant's (or, while the organization holds a member's funds, the organization's)

  • productUuidstring

    Its product (GET /products/:uuid). Absent without one

  • subscriptionHashstring

    The hash of the transaction that created the subscription on-chain. Absent until then (a trial, until its customer confirms it)

  • currencyIdinteger

    The currency (token) billed, written as the currency object under currency (GET /currencies/:id)

  • frequencyDuration

    Billing interval in seconds, as on-chain (e.g. 2592000 = 30 days). Written as a types.Duration in responses and webhooks (e.g. {"value": 1, "unit": "months"})

    2 fields of Duration
    • valueinteger

      Number of units; 0 means no duration

    • unitstring

      Required when value > 0. "months" = 30 days, "years" = 365 days

      oneof=seconds minutes hours days weeks months years

  • statusstring

    SubscriptionStatus (status) is where it stands: trial, trialExpired, active, pastDue, paused, stopped or cancelled. Every change sends subscription.statusChanged. Don't grant access from it: grant access while now < accessUntil (docs/api/guides/subscriptions.md § Access)

    One of:

    • trialStatusTrial is a free trial: nothing was signed on-chain yet.
    • trialExpiredStatusTrialExpired is a trial that ended without its customer confirming it (actionRequired confirmTrial): cancelled after the grace period unless they subscribe.
    • activeStatusActive is a subscription billed on its due dates. Its customer may have something to do (actionRequired: topUpAllowance, raiseMaximum) while it stays active.
    • pastDueStatusPastDue indicates a subscription whose last bill failed: its retries run.
    • pausedStatusPaused is a subscription its customer paused (a message signed with its wallet): QBitFlow doesn't bill it until they resume it. On-chain it is still active. It keeps the period it paid for (currentPeriodEnd).
    • stoppedStatusStopped is a subscription cancelled during its billing period (by its customer, or its merchant's force cancel with immediate=false): never billed again, it still runs until its paid period ends (nextBillingDate), then it is cancelled.
    • cancelledStatusCancelled indicates a cancelled subscription.
  • actionRequiredstringOptional

    ActionRequired is what its customer must do, if anything (absent: nothing): topUpAllowance (the allowance covers about one more bill at most), raiseMaximum (a bill waits for a new maximum per period), confirmTrial (the trial ended unconfirmed). Every change (set, changed or cleared) sends subscription.actionRequiredChanged

    One of

    • topUpAllowanceActionTopUpAllowance: what remains of the allowance covers about one more bill at most (or none). The customer adds periods from their management page.
    • raiseMaximumActionRaiseMaximum: a bill is above the maximum per period the customer signed (the token's price moved); it waits up to 7 days for a new maximum, signed from the management page.
    • confirmTrialActionConfirmTrial: the trial ended unconfirmed (trialExpired); the customer subscribes from their management page before the grace period ends.
  • currentPeriodEndstringOptional

    CurrentPeriodEnd is the paid-through date. A trial: its end. active, paused, stopped: the end of the period paid for (the next bill's due date). pastDue: the start of the unpaid period (past). cancelled: when it was cancelled, or the end of its last paid period if that came first. For access, read accessUntil: an active subscription is renewed a few minutes after this date

  • accessUntilstringOptional

    AccessUntil is when access ends: grant it while now < accessUntil, whatever the status. An active subscription: currentPeriodEnd plus 1 hour, since its renewal is billed within minutes of its due date (a subscriber whose bill is on its way keeps access; a failed bill sets pastDue). Every other status: currentPeriodEnd

  • priceUsdstring

    PriceUSD is the price per period the customer subscribed at, in USD (a decimal string, e.g. "9.99"), locked at signup (a free trial's too): every bill charges it and its lines (fees), converted to the token at the bill's price. A later change of the product's price applies to new subscribers only. Never "0"

  • feesarray of FeeLine

    Fees is what its checkout added to the price, line by line, as the customer saw them (a tax, shipping, the processing fee when the customer pays it), locked at signup with the price: every bill charges priceUsd plus these lines. [] without any

    4 fields of each FeeLine
    • typestring

      custom (the merchant's line) or processingFee (QBitFlow's fee, which the merchant has the customer pay)

      One of:

      • customThe merchant's own line: a tax, shipping, a service fee
      • processingFeeQBitFlow's fee, which the merchant has the customer pay (computed by QBitFlow)
    • labelstring

      The line's name, as the checkout shows it ("Processing fee" for the processing fee)

    • descriptionstringOptional

      Optional: more about the line, as the merchant wrote it. Omitted without one

    • amountUsdstring

      The line's amount in USD, a decimal string with at most 2 decimals

  • allowanceAllowanceOptional

    AllowanceStatus (allowance) is what the subscriber's wallet still lets QBitFlow bill, and the most one bill may charge, at today's price. Absent during a free trial (nothing signed yet)

    6 fields of Allowance
    • amountstring

      In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

    • amountMinUnitsstring

      The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

    • amountUsdstringOptional

      Its value in USD, a decimal string; absent when no price was known

    • remainingPeriodsintegerOptional

      RemainingPeriods is how many whole bills the allowance still covers at today's price: the allowance divided by a bill (priceUsd and its fees, converted to the token), rounded down, before the network fee each bill adds. 0 is a value: the customer must top it up (actionRequired topUpAllowance) before the next bill. Absent without a price

    • maxPerPeriodstringOptional

      MaxPerPeriod is the most one bill may charge, as the subscriber signed it, in the token's units (maxPerPeriodMinUnits: its on-chain integer): a bill above it waits for a new maximum (actionRequired raiseMaximum). Absent when the subscription has none recorded

    • maxPerPeriodMinUnitsstringOptional
  • lastBilledAtstringOptional

    When it was last billed. Absent before its first bill (a trial)

  • nextBillingAtstringOptional

    When its next bill is due (a trial: when it ends; stopped: when it is cancelled). Absent once cancelled

  • cancelledAtstringOptional

    When it was cancelled (absent until then, and for subscriptions cancelled before it was recorded)

  • cancellationReasonstringOptional

    Why it stopped or was cancelled: customer, merchant, billingFailed, trialNotConverted, merchantClosed or inactiveOnChain. Absent while it runs (and for subscriptions cancelled before it was recorded)

    One of:

    • customerCancelledByCustomer: its customer cancelled it (it was stopped until its period ended).
    • merchantCancelledByMerchant: its merchant cancelled it (POST /subscriptions/:uuid/cancel).
    • billingFailedCancelledBillingFailed: its bill's last attempt failed.
    • trialNotConvertedCancelledTrialNotConverted: its trial ended and its customer didn't subscribe within the grace period.
    • merchantClosedCancelledMerchantClosed: its merchant's space closed (a member removed, the organization closed).
    • inactiveOnChainCancelledInactiveOnChain: the contract no longer had it active (cancelled outside QBitFlow).
  • cancellableAtstringOptional

    MinimumCancellationDate (cancellableAt) is the earliest its customer may cancel it (the checkout's minPeriods). Absent when they may cancel it any time

  • metadatamapOptional

    Metadata is the merchant's own key-value data: its checkout session's, copied when the subscription was created, then changed with PATCH /subscriptions/:uuid (merged). {} when none. Only for the merchant (API and webhooks)

    Only for the resource's owner

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • customerUuidstringOptional

    The customer, when QBitFlow has one (named by the checkout, found by its customerReference, or recorded from the details the customer gave); omitted otherwise

    Only for the resource's owner

  • customerReferencestringOptional

    The merchant's reference of the customer, as the checkout was given it (customerReference), whether or not QBitFlow has a customer with it; omitted otherwise

    Only for the resource's owner

  • customerSummaryOptional

    The customer, named (merchant only, API reads): who paid, even once deleted. Omitted without one

    Only for the resource's owner

    6 fields of Summary
    • uuidstring

      The customer (GET /customers/:uuid)

    • firstNamestring

      First name

    • lastNamestringOptional

      Last name, when given

    • emailstring

      Email, lowercase

    • referencestringOptional

      The merchant's reference of the customer, when it has one

    • deletedboolean

      The merchant deleted the customer: it still names its rows, but GET /customers/:uuid answers 404

  • dunningDunningStatusOptional

    DunningStatus (dunning) is where its failing bill's retries stand: the failed attempts, the next one, a wait for a new maximum. Omitted while no bill is failing. API reads only: webhooks tell each failure with subscription.billingFailed

    5 fields of DunningStatus
    • failedAttemptsinteger

      The bill's failed attempts so far (0 while it only waits for a new maximum)

    • remainingAttemptsinteger

      Attempts left: after the last one fails, the subscription is cancelled

    • failingSincestringOptional

      The bill's first failed attempt: when the subscription went past due. Omitted without one

    • nextAttemptAtstringOptional

      When the bill is tried again at the latest (sooner once the customer tops up or raises their allowance). Omitted when none is scheduled

    • awaitingMaximumSincestringOptional

      While the bill is above the customer's maximum (actionRequired raiseMaximum): when it started waiting for them to raise it. nextAttemptAt is then when the wait ends. Omitted otherwise

Errors

  • 403policy_disabled

    a member doing what their organization's policy doesn't allow them, reads of what the policy governs included

List subscription bills#

GET /subscriptions/:uuid/bills

Lists a subscription's bills, newest first: every one, page by page (the hosted page shows the 10 most recent). The subscription is the caller's (sub@… or its bare uuid; cancelled ones too): another space's, an unknown one or another kind of id → 404.

Auth
X-API-Key: any key
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl "https://api.qbitflow.app/v2/subscriptions/$SUBSCRIPTION_UUID/bills" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a page of Bill ({ items, hasMore, nextCursor? })

Path parameters

  • uuidstringRequired

    The subscription: sub@… or its bare uuid

    txuuid

Query parameters

  • limitintegerOptional

    Page size: 20 when absent or ≤ 0, at most 100 (a larger one is clamped, not refused)

  • cursorstringOptional

    The previous page's nextCursor, verbatim; omit for the first page

    max=200

Response

A page: { "items": Bill[], "hasMore": …, "nextCursor"?: … }. Pass nextCursor back as cursor for the next page; it is absent when hasMore is false.

30 fields of each Bill
  • uuidstring

    allow read and create, (generated on creation of the payment link)

    A prefixed id (pay@…, sub@…)

  • createdAtstring
  • fromstring
  • tostring
  • amountstring

    The amount in the currency's units, exact, a decimal string ("10" for 10 USDC): amountMinUnits / 10^decimals

  • amountMinUnitsstring

    The amount in the currency's smallest unit, a string of digits ("10000000" for 10 USDC, 6 decimals)

  • amountUsdstring

    What the customer paid, in USD, a decimal string: the price (and, on a one-time payment, the fees its checkout added: fees), which the contracts split between QBitFlow's fee (the referrer's share included), the organization's fee and the merchant (settlement.split). The network fee a customer pays on top (settlement.split.networkFee) is not in it

  • currencyIdinteger

    The currency paid in, written as the currency object under currency (GET /currencies/:id)

  • txHashstring

    Hash of the transaction in the blockchain

  • chainstringOptional

    The chain it was paid on: ETH (Ethereum), BASE (Base) or SOL (Solana), the testnet's for a test-mode transfer (currency.test)

  • explorerUrlstringOptional

    Its transaction on the chain's block explorer (the testnet's in test mode). Omitted without a txHash

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • productNamestring

    What was paid for: the subscription's product name when the bill was paid (the first bill: as it was when the checkout was created). Later product edits don't change it

  • productDescriptionstring

    Same, for the product's description. Absent without one

  • productUuidstringOptional

    The subscription's product

  • subscriptionUuidstring

    The subscription it bills (sub@…)

  • customerUuidstringOptional

    The customer, when QBitFlow has one (named by the checkout, found by its customerReference, or recorded from the details the customer gave); omitted otherwise

    Only for the resource's owner

  • customerReferencestringOptional

    The merchant's reference of the customer, as the checkout was given it (customerReference), whether or not QBitFlow has a customer with it; omitted otherwise

    Only for the resource's owner

  • customerSummaryOptional

    The customer, named (merchant only, API reads): who paid, even once deleted. Omitted without one

    Only for the resource's owner

    6 fields of Summary
    • uuidstring

      The customer (GET /customers/:uuid)

    • firstNamestring

      First name

    • lastNamestringOptional

      Last name, when given

    • emailstring

      Email, lowercase

    • referencestringOptional

      The merchant's reference of the customer, when it has one

    • deletedboolean

      The merchant deleted the customer: it still names its rows, but GET /customers/:uuid answers 404

  • settlementSettlementOptional

    How it settled: its fees, its split and its transaction (only for the merchant)

    Only for the resource's owner

    5 fields of Settlement
    • feePercentnumber

      QBitFlow's fee on this payment, in bps (1 % = 100 bps), deducted from the amount paid. Written as feePercent, a percent string

    • organizationFeeOrganizationFeeOptional

      The organization's fee on its member's payment (a marketplace's commission), paid to the organization's wallet. It is taken from what remains after QBitFlow's fee (contracts SPEC §4.1): organization = (amount - QBitFlow's fee) × its rate, and the member receives the rest. While the organization holds the member's funds, it is withheld from what the organization owes them instead of paid on-chain. Absent: none

      2 fields of OrganizationFee
      • addressstringOptional

        The organization's wallet that receives the fee (only for the merchant)

        Only for the resource's owner

      • feePercentnumber

        The organization's fee, in bps, taken from what remains after the platform fee. Written as feePercent, a percent string

    • referralFeeReferralFeeOptional

      The referrer's share of QBitFlow's fee. Absent: none

      2 fields of ReferralFee
      • addressstringOptional

        The referrer's wallet that receives the fee (only for the merchant)

        Only for the resource's owner

      • feePercentnumber

        The referrer's share of the platform fee, in bps (2000 = 20 % of it). Written as feePercent, a percent string

    • splitSplitOptional

      How the contracts split what the payer paid. For a payment the organization held for its member, the organization's fee was withheld from the member's share (not paid on-chain): the split is the one a direct payment would have had. Absent on records made before the split was recorded

      5 fields of Split
      • platformTokenAmount

        QBitFlow's fee (the referrer's share not included)

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • organizationTokenAmountOptional

        The organization's fee; absent without one

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • referralTokenAmountOptional

        The referrer's share of QBitFlow's fee; absent without one

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • merchantTokenAmount

        What the merchant received (the member, for a member's payment), net of every fee

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • networkFeeTokenAmountOptional

        NetworkFee is the network fee the payer paid on top of the amount, in the payment's currency: the gas refund the contracts took in the token (their GasRefundProcessed event), or, for a payment in a chain's native coin, the fee of the transaction the payer's wallet paid (its gas and, on Base, its L1 data fee), bounded by what QBitFlow prepared. Not the transaction's own cost to its sender (transaction.fee). Absent on records made before it was recorded ("0" once recorded as none)

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

    • transactionSettlementTransactionOptional

      The transaction that paid it. Absent before its confirmation

      6 fields of SettlementTransaction
      • blockNumberstring

        The block (Ethereum, Base) or slot (Solana) it landed in, a string of digits

      • blockTimestringOptional

        When its block was produced (UTC); when it was recorded if the chain's node didn't give it. Absent only on records made before it was recorded

      • gasUsedintegerOptional

        The gas it consumed (Ethereum, Base). Absent on Solana

      • feeTokenAmount

        What the transaction cost its sender, in the chain's native coin (ETH, SOL; its currency is the payment currency's chain): its gas and, on Base, its L1 data fee. amountUsd at nativePriceUsd

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • l1FeeTokenAmountOptional

        The part of fee that paid Base's L1 data fee, in the native coin. Absent off Base, and on transactions recorded before it was

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • nativePriceUsdstringOptional

        NativePriceUSD is the USD price of the chain's native coin when the transaction was recorded (what its fee cost in USD). Absent when the price wasn't available then

  • periodStartstringOptional

    The start of the period the bill paid: its due date (the subscription's start for its first bill). Omitted on bills recorded before it was

  • periodEndstringOptional

    The end of the period the bill paid: the subscription's next bill. Paid until then. Omitted on bills recorded before it was

  • confirmedAtstringOptional

    When the chain confirmed it: its block's time (settlement.transaction.blockTime). Absent only on records made before it was recorded

  • paidstringOptional

    Everything the customer's wallet sent, in the currency's units (a decimal string): the amount plus the network fee paid on top (settlement.split). A refund's base (refundPercent of it). Only for the merchant; absent when the split wasn't recorded

    Only for the resource's owner

  • paidMinUnitsstringOptional

    The same in the currency's smallest unit, a string of digits. Only for the merchant, like paid

    Only for the resource's owner

  • paidUsdstringOptional

    The same in USD, at the payment's time, a decimal string. Only for the merchant, like paid

    Only for the resource's owner

  • refundRefundSummaryOptional

    Its refund (one per transaction); omitted without one. The merchant's own refund appears once its transfer confirmed (approved)

    Only for the resource's owner

    9 fields of RefundSummary
    • uuidstring

      The refund (refund@…)

    • statusstring

      pending, approved or rejected

      One ofpendingapprovedrejected

      • failedDeclared, never set: an approval that fails leaves the refund pending, to approve again
    • initiatedBystring

      customer (a request) or merchant

    • refundPercentnumber

      The share of what the customer paid it sends back, a percent string ("100": all of it). Written as refundPercent

    • amountstringOptional

      What it sends back, in the currency's units (a decimal string). Absent when its currency isn't known (a refund requested before refunds named it)

    • amountMinUnitsstring

      The same in the currency's smallest unit (a string of digits)

    • amountUsdstringOptional

      The same in USD, at the payment's time (a decimal string). Absent when unknown (a refund requested before it was recorded)

    • createdAtstring

      When it was requested or started

    • respondedAtstringOptional

      When it was approved (confirmed) or rejected; absent while pending

  • refundablebooleanOptional

    Whether it can be refunded now

    Only for the resource's owner

  • notRefundableReasonstringOptional

    Why not: refundExists or heldFundsReleased. Omitted when refundable

    Only for the resource's owner

Get bill#

GET /bills/:uuid

Reads one of the caller's subscription bills (sub-hist@… or its bare uuid): another space's, an unknown one or another kind of id → 404.

Auth
X-API-Key: any key
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl "https://api.qbitflow.app/v2/bills/$BILL_UUID" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a Bill

Path parameters

  • uuidstringRequired

    Its prefixed uuid (or the bare uuid)

    txuuid

Query parameters

  • includeMembersbooleanOptional

    The organization's space only (the team, its keys without On-Behalf-Of): a member's too, naming its member (userUuid). Read only: acting on it still switches into the member's space or uses On-Behalf-Of. From a member's space → 400 on includeMembers

Response

A Bill.

30 fields of Bill
  • uuidstring

    allow read and create, (generated on creation of the payment link)

    A prefixed id (pay@…, sub@…)

  • createdAtstring
  • fromstring
  • tostring
  • amountstring

    The amount in the currency's units, exact, a decimal string ("10" for 10 USDC): amountMinUnits / 10^decimals

  • amountMinUnitsstring

    The amount in the currency's smallest unit, a string of digits ("10000000" for 10 USDC, 6 decimals)

  • amountUsdstring

    What the customer paid, in USD, a decimal string: the price (and, on a one-time payment, the fees its checkout added: fees), which the contracts split between QBitFlow's fee (the referrer's share included), the organization's fee and the merchant (settlement.split). The network fee a customer pays on top (settlement.split.networkFee) is not in it

  • currencyIdinteger

    The currency paid in, written as the currency object under currency (GET /currencies/:id)

  • txHashstring

    Hash of the transaction in the blockchain

  • chainstringOptional

    The chain it was paid on: ETH (Ethereum), BASE (Base) or SOL (Solana), the testnet's for a test-mode transfer (currency.test)

  • explorerUrlstringOptional

    Its transaction on the chain's block explorer (the testnet's in test mode). Omitted without a txHash

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • productNamestring

    What was paid for: the subscription's product name when the bill was paid (the first bill: as it was when the checkout was created). Later product edits don't change it

  • productDescriptionstring

    Same, for the product's description. Absent without one

  • productUuidstringOptional

    The subscription's product

  • subscriptionUuidstring

    The subscription it bills (sub@…)

  • customerUuidstringOptional

    The customer, when QBitFlow has one (named by the checkout, found by its customerReference, or recorded from the details the customer gave); omitted otherwise

    Only for the resource's owner

  • customerReferencestringOptional

    The merchant's reference of the customer, as the checkout was given it (customerReference), whether or not QBitFlow has a customer with it; omitted otherwise

    Only for the resource's owner

  • customerSummaryOptional

    The customer, named (merchant only, API reads): who paid, even once deleted. Omitted without one

    Only for the resource's owner

    6 fields of Summary
    • uuidstring

      The customer (GET /customers/:uuid)

    • firstNamestring

      First name

    • lastNamestringOptional

      Last name, when given

    • emailstring

      Email, lowercase

    • referencestringOptional

      The merchant's reference of the customer, when it has one

    • deletedboolean

      The merchant deleted the customer: it still names its rows, but GET /customers/:uuid answers 404

  • settlementSettlementOptional

    How it settled: its fees, its split and its transaction (only for the merchant)

    Only for the resource's owner

    5 fields of Settlement
    • feePercentnumber

      QBitFlow's fee on this payment, in bps (1 % = 100 bps), deducted from the amount paid. Written as feePercent, a percent string

    • organizationFeeOrganizationFeeOptional

      The organization's fee on its member's payment (a marketplace's commission), paid to the organization's wallet. It is taken from what remains after QBitFlow's fee (contracts SPEC §4.1): organization = (amount - QBitFlow's fee) × its rate, and the member receives the rest. While the organization holds the member's funds, it is withheld from what the organization owes them instead of paid on-chain. Absent: none

      2 fields of OrganizationFee
      • addressstringOptional

        The organization's wallet that receives the fee (only for the merchant)

        Only for the resource's owner

      • feePercentnumber

        The organization's fee, in bps, taken from what remains after the platform fee. Written as feePercent, a percent string

    • referralFeeReferralFeeOptional

      The referrer's share of QBitFlow's fee. Absent: none

      2 fields of ReferralFee
      • addressstringOptional

        The referrer's wallet that receives the fee (only for the merchant)

        Only for the resource's owner

      • feePercentnumber

        The referrer's share of the platform fee, in bps (2000 = 20 % of it). Written as feePercent, a percent string

    • splitSplitOptional

      How the contracts split what the payer paid. For a payment the organization held for its member, the organization's fee was withheld from the member's share (not paid on-chain): the split is the one a direct payment would have had. Absent on records made before the split was recorded

      5 fields of Split
      • platformTokenAmount

        QBitFlow's fee (the referrer's share not included)

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • organizationTokenAmountOptional

        The organization's fee; absent without one

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • referralTokenAmountOptional

        The referrer's share of QBitFlow's fee; absent without one

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • merchantTokenAmount

        What the merchant received (the member, for a member's payment), net of every fee

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • networkFeeTokenAmountOptional

        NetworkFee is the network fee the payer paid on top of the amount, in the payment's currency: the gas refund the contracts took in the token (their GasRefundProcessed event), or, for a payment in a chain's native coin, the fee of the transaction the payer's wallet paid (its gas and, on Base, its L1 data fee), bounded by what QBitFlow prepared. Not the transaction's own cost to its sender (transaction.fee). Absent on records made before it was recorded ("0" once recorded as none)

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

    • transactionSettlementTransactionOptional

      The transaction that paid it. Absent before its confirmation

      6 fields of SettlementTransaction
      • blockNumberstring

        The block (Ethereum, Base) or slot (Solana) it landed in, a string of digits

      • blockTimestringOptional

        When its block was produced (UTC); when it was recorded if the chain's node didn't give it. Absent only on records made before it was recorded

      • gasUsedintegerOptional

        The gas it consumed (Ethereum, Base). Absent on Solana

      • feeTokenAmount

        What the transaction cost its sender, in the chain's native coin (ETH, SOL; its currency is the payment currency's chain): its gas and, on Base, its L1 data fee. amountUsd at nativePriceUsd

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • l1FeeTokenAmountOptional

        The part of fee that paid Base's L1 data fee, in the native coin. Absent off Base, and on transactions recorded before it was

        3 fields of TokenAmount
        • amountstring

          In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

        • amountMinUnitsstring

          The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

        • amountUsdstringOptional

          Its value in USD, a decimal string; absent when no price was known

      • nativePriceUsdstringOptional

        NativePriceUSD is the USD price of the chain's native coin when the transaction was recorded (what its fee cost in USD). Absent when the price wasn't available then

  • periodStartstringOptional

    The start of the period the bill paid: its due date (the subscription's start for its first bill). Omitted on bills recorded before it was

  • periodEndstringOptional

    The end of the period the bill paid: the subscription's next bill. Paid until then. Omitted on bills recorded before it was

  • confirmedAtstringOptional

    When the chain confirmed it: its block's time (settlement.transaction.blockTime). Absent only on records made before it was recorded

  • paidstringOptional

    Everything the customer's wallet sent, in the currency's units (a decimal string): the amount plus the network fee paid on top (settlement.split). A refund's base (refundPercent of it). Only for the merchant; absent when the split wasn't recorded

    Only for the resource's owner

  • paidMinUnitsstringOptional

    The same in the currency's smallest unit, a string of digits. Only for the merchant, like paid

    Only for the resource's owner

  • paidUsdstringOptional

    The same in USD, at the payment's time, a decimal string. Only for the merchant, like paid

    Only for the resource's owner

  • refundRefundSummaryOptional

    Its refund (one per transaction); omitted without one. The merchant's own refund appears once its transfer confirmed (approved)

    Only for the resource's owner

    9 fields of RefundSummary
    • uuidstring

      The refund (refund@…)

    • statusstring

      pending, approved or rejected

      One ofpendingapprovedrejected

      • failedDeclared, never set: an approval that fails leaves the refund pending, to approve again
    • initiatedBystring

      customer (a request) or merchant

    • refundPercentnumber

      The share of what the customer paid it sends back, a percent string ("100": all of it). Written as refundPercent

    • amountstringOptional

      What it sends back, in the currency's units (a decimal string). Absent when its currency isn't known (a refund requested before refunds named it)

    • amountMinUnitsstring

      The same in the currency's smallest unit (a string of digits)

    • amountUsdstringOptional

      The same in USD, at the payment's time (a decimal string). Absent when unknown (a refund requested before it was recorded)

    • createdAtstring

      When it was requested or started

    • respondedAtstringOptional

      When it was approved (confirmed) or rejected; absent while pending

  • refundablebooleanOptional

    Whether it can be refunded now

    Only for the resource's owner

  • notRefundableReasonstringOptional

    Why not: refundExists or heldFundsReleased. Omitted when refundable

    Only for the resource's owner

Cancel subscription#

POST /subscriptions/:uuid/cancel

Cancels one of the merchant's subscriptions without its subscriber signing (?immediate=true|false), as a bill's last failure does: on-chain (QBitFlow signs the force cancel, so nothing can bill it anymore), else off-chain (a trial, never on-chain; a stopped subscription, cancelled on-chain already; or the force cancel failed). immediate=true (default): cancelled now. immediate=false: stopped now, cancelled at the end of its paid period by its bill. subscription.statusChanged tells each change. It answers the subscription as it is then: 200 once done, 202 while it still confirms on-chain. Another space's subscription (another organization's, another mode's) is not found, whatever its state; a cancelled one: 409 subscription_already_stopped_or_inactive, and so is one stopped already with immediate=false; a trial with immediate=false: 400; a cancellation running: 409 tx_already_sent. A member needs the members.subscriptions policy (403 policy_disabled, checked before the subscription is looked up, so before any 404).

Auth
X-API-Key: any keyA member's key needs the members.subscriptions policy
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200 (done), 202 (still confirming on-chain)
Request

request.sh

curl -X POST "https://api.qbitflow.app/v2/subscriptions/$SUBSCRIPTION_UUID/cancel?immediate=false" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a Cancelled (202 while the cancellation is still confirming on-chain)
// immediate: false stops it now (never billed again) and cancels it at the end of the period// paid for. A ConflictError when it is already stopped or inactive.const { subscription, pending } = await client.subscriptions.cancel(subscriptionUuid, {	immediate: false,});if (pending) {	// HTTP 202: the on-chain cancellation is still confirming. It goes on regardless:	// subscription.statusChanged tells the end.	console.log('cancellation confirming');} else {	console.log(`now ${subscription.status}`); // stopped}
result = client.subscriptions.cancel(subscription_uuid, immediate=False)  # at period endif result.pending:    # HTTP 202: still confirming on-chain; subscription.statusChanged tells the end.    print("cancellation confirming")else:    print("now", result.subscription.status)  # stopped, cancelled at the period's end
// Immediate false: never billed again, cancelled when the paid period ends.res, err := client.Subscriptions.Cancel(ctx, subscriptionUUID, &qbitflow.CancelSubscriptionParams{	Immediate: new(false),})if err != nil {	log.Fatal(err) // 409 subscription_already_stopped_or_inactive}if res.Pending {	// HTTP 202: the on-chain cancellation is still confirming; subscription.statusChanged	// tells the end.	fmt.Println("cancellation confirming")} else {	fmt.Println("now", res.Subscription.Status) // stopped}
$result = $client->subscriptions->cancel($subscriptionUuid, new \QBitFlow\Params\CancelSubscriptionParams(immediate: false));if ($result->pending) {	// HTTP 202: the on-chain cancellation is still confirming; subscription.statusChanged tells the end.	echo "Cancellation confirming\n";} else {	echo "Now {$result->subscription->status}\n"; // stopped: cancelled at the end of the paid period}

Path parameters

  • uuidstringRequired

    The subscription: sub@… or its bare uuid

    txuuid

Query parameters

  • immediatebooleanOptional

    Immediate: true (the default) cancels it now (cancelled); false stops it now (never billed again, its status stopped) and cancels it when its paid period ends (nextBillingAt). A trial is cancelled immediately only (no paid period to finish: false → 400)

Response

A Cancelled.

30 fields of Cancelled
  • uuidstring

    Its id (sub@…): the checkout session's

    A prefixed id (pay@…, sub@…)

  • referencestringOptional

    The merchant's reference for the subscription (an order or customer id), set when creating its checkout. Only for the merchant: never in the public reads by uuid (GET /hosted/transactions/:txUuid)

    Only for the resource's owner

  • createdAtstring
  • updatedAtstring

    Its last change (a bill, a status, its metadata)

  • fromstring

    The subscriber's wallet: the one it bills. Absent when unknown (a trial not confirmed yet may have none)

  • tostring

    The wallet its bills pay: the merchant's (or, while the organization holds a member's funds, the organization's)

  • productUuidstring

    Its product (GET /products/:uuid). Absent without one

  • subscriptionHashstring

    The hash of the transaction that created the subscription on-chain. Absent until then (a trial, until its customer confirms it)

  • currencyIdinteger

    The currency (token) billed, written as the currency object under currency (GET /currencies/:id)

  • frequencyDuration

    Billing interval in seconds, as on-chain (e.g. 2592000 = 30 days). Written as a types.Duration in responses and webhooks (e.g. {"value": 1, "unit": "months"})

    2 fields of Duration
    • valueinteger

      Number of units; 0 means no duration

    • unitstring

      Required when value > 0. "months" = 30 days, "years" = 365 days

      oneof=seconds minutes hours days weeks months years

  • statusstring

    SubscriptionStatus (status) is where it stands: trial, trialExpired, active, pastDue, paused, stopped or cancelled. Every change sends subscription.statusChanged. Don't grant access from it: grant access while now < accessUntil (docs/api/guides/subscriptions.md § Access)

    One of:

    • trialStatusTrial is a free trial: nothing was signed on-chain yet.
    • trialExpiredStatusTrialExpired is a trial that ended without its customer confirming it (actionRequired confirmTrial): cancelled after the grace period unless they subscribe.
    • activeStatusActive is a subscription billed on its due dates. Its customer may have something to do (actionRequired: topUpAllowance, raiseMaximum) while it stays active.
    • pastDueStatusPastDue indicates a subscription whose last bill failed: its retries run.
    • pausedStatusPaused is a subscription its customer paused (a message signed with its wallet): QBitFlow doesn't bill it until they resume it. On-chain it is still active. It keeps the period it paid for (currentPeriodEnd).
    • stoppedStatusStopped is a subscription cancelled during its billing period (by its customer, or its merchant's force cancel with immediate=false): never billed again, it still runs until its paid period ends (nextBillingDate), then it is cancelled.
    • cancelledStatusCancelled indicates a cancelled subscription.
  • actionRequiredstringOptional

    ActionRequired is what its customer must do, if anything (absent: nothing): topUpAllowance (the allowance covers about one more bill at most), raiseMaximum (a bill waits for a new maximum per period), confirmTrial (the trial ended unconfirmed). Every change (set, changed or cleared) sends subscription.actionRequiredChanged

    One of

    • topUpAllowanceActionTopUpAllowance: what remains of the allowance covers about one more bill at most (or none). The customer adds periods from their management page.
    • raiseMaximumActionRaiseMaximum: a bill is above the maximum per period the customer signed (the token's price moved); it waits up to 7 days for a new maximum, signed from the management page.
    • confirmTrialActionConfirmTrial: the trial ended unconfirmed (trialExpired); the customer subscribes from their management page before the grace period ends.
  • currentPeriodEndstringOptional

    CurrentPeriodEnd is the paid-through date. A trial: its end. active, paused, stopped: the end of the period paid for (the next bill's due date). pastDue: the start of the unpaid period (past). cancelled: when it was cancelled, or the end of its last paid period if that came first. For access, read accessUntil: an active subscription is renewed a few minutes after this date

  • accessUntilstringOptional

    AccessUntil is when access ends: grant it while now < accessUntil, whatever the status. An active subscription: currentPeriodEnd plus 1 hour, since its renewal is billed within minutes of its due date (a subscriber whose bill is on its way keeps access; a failed bill sets pastDue). Every other status: currentPeriodEnd

  • priceUsdstring

    PriceUSD is the price per period the customer subscribed at, in USD (a decimal string, e.g. "9.99"), locked at signup (a free trial's too): every bill charges it and its lines (fees), converted to the token at the bill's price. A later change of the product's price applies to new subscribers only. Never "0"

  • feesarray of FeeLine

    Fees is what its checkout added to the price, line by line, as the customer saw them (a tax, shipping, the processing fee when the customer pays it), locked at signup with the price: every bill charges priceUsd plus these lines. [] without any

    4 fields of each FeeLine
    • typestring

      custom (the merchant's line) or processingFee (QBitFlow's fee, which the merchant has the customer pay)

      One of:

      • customThe merchant's own line: a tax, shipping, a service fee
      • processingFeeQBitFlow's fee, which the merchant has the customer pay (computed by QBitFlow)
    • labelstring

      The line's name, as the checkout shows it ("Processing fee" for the processing fee)

    • descriptionstringOptional

      Optional: more about the line, as the merchant wrote it. Omitted without one

    • amountUsdstring

      The line's amount in USD, a decimal string with at most 2 decimals

  • allowanceAllowanceOptional

    AllowanceStatus (allowance) is what the subscriber's wallet still lets QBitFlow bill, and the most one bill may charge, at today's price. Absent during a free trial (nothing signed yet)

    6 fields of Allowance
    • amountstring

      In the token's units, exact: amountMinUnits / 10^decimals, a decimal string ("12.5")

    • amountMinUnitsstring

      The on-chain integer, in the token's smallest unit, a string of digits ("12500000")

    • amountUsdstringOptional

      Its value in USD, a decimal string; absent when no price was known

    • remainingPeriodsintegerOptional

      RemainingPeriods is how many whole bills the allowance still covers at today's price: the allowance divided by a bill (priceUsd and its fees, converted to the token), rounded down, before the network fee each bill adds. 0 is a value: the customer must top it up (actionRequired topUpAllowance) before the next bill. Absent without a price

    • maxPerPeriodstringOptional

      MaxPerPeriod is the most one bill may charge, as the subscriber signed it, in the token's units (maxPerPeriodMinUnits: its on-chain integer): a bill above it waits for a new maximum (actionRequired raiseMaximum). Absent when the subscription has none recorded

    • maxPerPeriodMinUnitsstringOptional
  • lastBilledAtstringOptional

    When it was last billed. Absent before its first bill (a trial)

  • nextBillingAtstringOptional

    When its next bill is due (a trial: when it ends; stopped: when it is cancelled). Absent once cancelled

  • cancelledAtstringOptional

    When it was cancelled (absent until then, and for subscriptions cancelled before it was recorded)

  • cancellationReasonstringOptional

    Why it stopped or was cancelled: customer, merchant, billingFailed, trialNotConverted, merchantClosed or inactiveOnChain. Absent while it runs (and for subscriptions cancelled before it was recorded)

    One of:

    • customerCancelledByCustomer: its customer cancelled it (it was stopped until its period ended).
    • merchantCancelledByMerchant: its merchant cancelled it (POST /subscriptions/:uuid/cancel).
    • billingFailedCancelledBillingFailed: its bill's last attempt failed.
    • trialNotConvertedCancelledTrialNotConverted: its trial ended and its customer didn't subscribe within the grace period.
    • merchantClosedCancelledMerchantClosed: its merchant's space closed (a member removed, the organization closed).
    • inactiveOnChainCancelledInactiveOnChain: the contract no longer had it active (cancelled outside QBitFlow).
  • cancellableAtstringOptional

    MinimumCancellationDate (cancellableAt) is the earliest its customer may cancel it (the checkout's minPeriods). Absent when they may cancel it any time

  • metadatamapOptional

    Metadata is the merchant's own key-value data: its checkout session's, copied when the subscription was created, then changed with PATCH /subscriptions/:uuid (merged). {} when none. Only for the merchant (API and webhooks)

    Only for the resource's owner

  • managementPageLinkstringOptional

    ManagementPageLink is the subscription's page for its customer: where they top up its allowance, raise its maximum, pause, resume or cancel it, and confirm a trial. Share it with them (an email, the merchant's account page)

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • customerUuidstringOptional

    The customer, when QBitFlow has one (named by the checkout, found by its customerReference, or recorded from the details the customer gave); omitted otherwise

    Only for the resource's owner

  • customerReferencestringOptional

    The merchant's reference of the customer, as the checkout was given it (customerReference), whether or not QBitFlow has a customer with it; omitted otherwise

    Only for the resource's owner

  • customerSummaryOptional

    The customer, named (merchant only, API reads): who paid, even once deleted. Omitted without one

    Only for the resource's owner

    6 fields of Summary
    • uuidstring

      The customer (GET /customers/:uuid)

    • firstNamestring

      First name

    • lastNamestringOptional

      Last name, when given

    • emailstring

      Email, lowercase

    • referencestringOptional

      The merchant's reference of the customer, when it has one

    • deletedboolean

      The merchant deleted the customer: it still names its rows, but GET /customers/:uuid answers 404

  • dunningDunningStatusOptional

    DunningStatus (dunning) is where its failing bill's retries stand: the failed attempts, the next one, a wait for a new maximum. Omitted while no bill is failing. API reads only: webhooks tell each failure with subscription.billingFailed

    5 fields of DunningStatus
    • failedAttemptsinteger

      The bill's failed attempts so far (0 while it only waits for a new maximum)

    • remainingAttemptsinteger

      Attempts left: after the last one fails, the subscription is cancelled

    • failingSincestringOptional

      The bill's first failed attempt: when the subscription went past due. Omitted without one

    • nextAttemptAtstringOptional

      When the bill is tried again at the latest (sooner once the customer tops up or raises their allowance). Omitted when none is scheduled

    • awaitingMaximumSincestringOptional

      While the bill is above the customer's maximum (actionRequired raiseMaximum): when it started waiting for them to raise it. nextAttemptAt is then when the wait ends. Omitted otherwise

Errors

  • 403policy_disabled

    a member doing what their organization's policy doesn't allow them, reads of what the policy governs included

  • 409tx_already_sent

    a transaction sent already: running, or completed (Payments and transactions § Sending a signed transaction)

  • 409subscription_already_stopped_or_inactive

    cancelling a subscription, raising its allowance or its maximum, once it is stopped (it ends with its paid period; customer-side routes), a merchant's POST /subscriptions/:uuid/cancel?immediate=false of a stopped one, or a merchant's POST /subscriptions/:uuid/cancel or /test-bill of a cancelled one

Run test bill#

POST /subscriptions/:uuid/test-bill

Bills a test subscription now ("the test bill"): live subscriptions are billed on their due date only (a live one → 400 test_mode_only). It runs the same bill as live, so statuses and webhooks are exactly live's: the bill of its due date, or, on a bill waiting in dunning (or for a new maximum), its next attempt now. It answers once the attempt settled (at most 2 minutes: then where it stands). A paused subscription isn't billed (its bill ends: outcome paused); one not due yet → 409 payment_not_due; a cancelled one → 409 subscription_already_stopped_or_inactive. A member needs the members.subscriptions policy (403 policy_disabled, checked before the subscription is looked up, so before any 404). Another space's → 404.

Auth
X-API-Key: any keyA member's key needs the members.subscriptions policy
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl -X POST "https://api.qbitflow.app/v2/subscriptions/$SUBSCRIPTION_UUID/test-bill" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a TestBill
// Test mode only: runs the next billing now, with live's statuses and webhooks. A ConflictError// payment_not_due before nextBillingAt; a BadRequestError test_mode_only for a live one.const bill = await client.subscriptions.testBill(subscriptionUuid);// billUuid is sub-hist@…: the id its subscription.billed carries once paid.console.log(bill.billUuid, bill.stage, bill.outcome ?? 'running', bill.failureCode ?? '');
# Test mode only: run the next bill now instead of on its due date.bill = client.subscriptions.test_bill(subscription_uuid)print(bill.bill_uuid, bill.stage, bill.outcome, bill.failure_code)  # sub-hist@…
// Test mode only: runs the next billing now, with live's statuses and webhooks.bill, err := client.Subscriptions.TestBill(ctx, subscriptionUUID)if err != nil {	log.Fatal(err) // 409 payment_not_due before NextBillingAt; 400 test_mode_only for a live one}fmt.Println(bill.BillUUID, bill.Stage, bill.Outcome, bill.FailureCode) // sub-hist@…
// Test mode only: runs the next billing now instead of on its due date.$bill = $client->subscriptions->testBill($subscriptionUuid);echo "Bill {$bill->billUuid}: {$bill->stage} " . ($bill->outcome ?? '-') . ' ' . ($bill->failureCode ?? '') . "\n"; // sub-hist@…

Path parameters

  • uuidstringRequired

    The subscription: sub@… or its bare uuid

    txuuid

Response

A TestBill.

  • billUuidstring

    The bill (sub-hist@…): the uuid its subscription.billed and GET /bills/:uuid carry once it is paid

  • stagestring

    running (being charged), waiting (for its next attempt, its due date or a trial's grace period), pending (over the customer's maximum: waiting for a new one) or done

    One ofdone

    • runningBeing planned, charged or recorded
    • waitingWaiting for its next attempt (dunning, or QBitFlow's own failure), its due date, or the end of a trial's grace period
    • pendingOver the customer's maximum: waiting for their new one
  • outcomestringOptional

    Once done: paid, notDue (nothing to bill), skipped (below the minimum amount), cancelled or paused. Absent before

    One ofpaid

    • notDueNothing to bill: paid already, cancelled, or gone
    • skippedBelow the minimum amount: the period moved on without a charge
    • cancelledThe subscription was cancelled: stopped by its subscriber, its trial over, its merchant closed, inactive on-chain, or its last attempt failed
    • pausedIts customer paused the subscription: not charged (resumed, it is billed by the bill of its new date)
  • attemptsinteger

    Its failed attempts so far

  • nextAttemptAtstringOptional

    While waiting or pending: when it is tried again at the latest. Absent otherwise

  • txHashstringOptional

    Paid: its charge's transaction. Absent otherwise

  • failureCodestringOptional

    Its last failure's code (errors), e.g. insufficient_allowance. Absent without one

Errors

  • 403policy_disabled

    a member doing what their organization's policy doesn't allow them, reads of what the policy governs included

  • 400test_mode_only

    something only test mode does asked in live mode (a test bill, a faucet, a test payment)

  • 409subscription_already_stopped_or_inactive

    cancelling a subscription, raising its allowance or its maximum, once it is stopped (it ends with its paid period; customer-side routes), a merchant's POST /subscriptions/:uuid/cancel?immediate=false of a stopped one, or a merchant's POST /subscriptions/:uuid/cancel or /test-bill of a cancelled one

  • 409payment_not_due

    asked for what the subscription's state refuses

Edge cases

The contract's rules for these routes: Authentication & roles · Ids · Spaces · Reads & shape · PATCH /subscriptions/:uuid · Cancel (POST /subscriptions/:uuid/cancel) · Test bill (POST /subscriptions/:uuid/test-bill) · Billing · The list · Bills.

Read all 10

Authentication & roles

  • POST /subscriptions/:uuid/cancel and POST /subscriptions/:uuid/test-bill are under the members.subscriptions policy: a member (session or own key) while it is off → 403 policy_disabled, details.policy: "members.subscriptions", subscriptions created earlier included (the organization keeps managing them); the team passes, acting in the member's space too. The policy is checked before the subscription is looked up: 403 first, whatever the uuid (another space's or unknown included); the 404 ladder applies once the policy passes.
  • PATCH follows the organization's members.subscriptions policy, as creating a subscription checkout does: a member's credential while it is off → 403 policy_disabled.
  • The two actions change state, so they are POST; a GET on them → 405 method_not_allowed (Allow: POST).
  • The public bill history a customer's page shows is GET /hosted/subscriptions/:uuid/bills (Hosted subscriptions).

Ids

  • :uuid is the subscription's id, sub@…, or its bare uuid (the same subscription; answers always name it sub@…). A bill's is sub-hist@… or its bare uuid. Another kind of id (pay@… on a subscription route, sub@… on /bills) names nothing → 404; a malformed id → 400 validation_failed on uuid.

Spaces

  • Every subscription belongs to one space (spaces): the organization's or a member's, in one mode. Every route works in the request's space: the team (and organization keys) sees the organization's subscriptions, a member (and their keys) their own, and an organization key with On-Behalf-Of: <userUuid> (or the dashboard switched into the member's space) the member's.
  • A subscription of another space, of another organization or of the other mode is never listed, and answers 404 on every route (the reads, PATCH, the actions): existence is never revealed, never 403 nor 409.
  • The reads return the caller's subscription whatever its status, a cancelled one too (status: "cancelled"). The actions (cancel, test-bill) answer 409 subscription_already_stopped_or_inactive for a cancelled one of the caller's space (nothing left to do on it); PATCH edits a cancelled one's metadata too.
  • A subscription doesn't exist while it is a checkout. It exists once its checkout completed (paid on-chain; a free trial: its message signed). Before that, its checkout session's uuid (sub@…) answers 404 on every subscription route, and no list has it: read the checkout session you created instead (Checkout sessions: created (with lastAttempt after a failed try), waitingConfirmation, then completed or expired).
  • Organization-wide reads (?includeMembers=true on GET /subscriptions, GET /subscriptions/:uuid and GET /bills/:uuid): the organization's space (the team, the organization's keys without On-Behalf-Of) reads its members' subscriptions too, in its mode only, each with its userUuid: removed members' too, and the personal space an admin kept from before their promotion (as Payments and transactions). From a member's space → 400 validation_failed on includeMembers. Read only: PATCH, the actions and GET /subscriptions/:uuid/bills stay in the request's space (a member's subscription: On-Behalf-Of that member).
  • One member's subscriptions (?userUuid=<member> on GET /subscriptions): that member's only, read from the organization's space by owners and admins, with the rules of Payments and transactions § Spaces (One member's rows).

Reads & shape

  • GET /subscriptions/:uuid and every item of the list are a Subscription, as every subscription.* webhook carries it (Webhook events).
  • userUuid is present for a member's subscription and omitted for the organization's own. No organization is named.
  • status is one of trial, trialExpired, active, pastDue, paused, stopped, cancelled. actionRequired says what its customer must do (topUpAllowance, raiseMaximum; confirmTrial on a trialExpired one), absent when nothing. stopped is a subscription cancelled during its paid period (by its customer, or by its merchant with immediate=false): never billed again, it keeps running until nextBillingAt, then becomes cancelled. paused: its customer paused it; it isn't billed until they resume it. Every status change sends subscription.statusChanged, every change of actionRequired subscription.actionRequiredChanged.
  • Access: grant it while now < accessUntil, whatever the status: Subscriptions § Access. accessUntil is the paid-through date (currentPeriodEnd), plus 1 hour for an active subscription, whose renewal is billed within minutes of its due date (§ Billing): a subscriber whose bill is on its way keeps access, a failed bill makes it pastDue (accessUntil = currentPeriodEnd, past). Both are present whenever the subscription has a paid-through date.
  • The instants: lastBilledAt (absent before its first bill: a trial), nextBillingAt (a trial: when it ends; stopped: when it is cancelled; absent once cancelled), cancellableAt (the earliest its customer may cancel it, the checkout's minPeriods; absent when any time), cancelledAt. RFC 3339, UTC.
  • cancellationReason (on stopped and cancelled subscriptions): customer, merchant, billingFailed, trialNotConverted, merchantClosed or inactiveOnChain; a stopped subscription keeps the reason it stopped for once cancelled. Absent while it runs.
  • priceUsd is the price the customer subscribed at, never "0": locked at signup, a free trial's too (subscriptions recorded before every path locked it took their product's price, what their next bill would have charged). fees: its checkout's lines, locked with it ([] without any). currency: the token billed, the currency object of naming.
  • subscriptionHash (the on-chain creation's transaction) is absent until it is on-chain (a trial); from (the subscriber's wallet) and productUuid are absent when unknown.
  • allowance (absent during a free trial: nothing signed yet) is what the subscriber's wallet still lets QBitFlow bill, in the subscription's token:
    • amount / amountMinUnits: what remains of the allowance on-chain; amountUsd: its value at today's price;
    • remainingPeriods: how many whole bills it still covers at today's price (priceUsd and its fees converted to the token, before each bill's network fee), rounded down. The checkout's "N payments" kept room for the network fees, so this count is usually higher: the checkout's figure is an estimate, the least the customer is covered for. 0 is a value: the customer must top it up before the next bill (actionRequired: "topUpAllowance" comes with a bill that leaves at most about one);
    • maxPerPeriod / maxPerPeriodMinUnits: the most one bill may charge, as the customer signed it; a bill above it waits for a new maximum (raiseMaximum). Absent when none was recorded.
    • Without a price QBitFlow can trust right now (errors network_unavailable), amountUsd and remainingPeriods are absent; the read never fails for it.
  • managementPageLink: the subscription's page for its customer, where they top up its allowance, raise its maximum, pause, resume or cancel it, and confirm a trial. On every read and in every subscription.* webhook. Share it with them (an email, the merchant's account page).
  • metadata: the merchant's own key-value data (naming): its checkout session's, copied when the subscription was created (a trial's too, kept when it is confirmed), then edited with PATCH. {} when none. Only for the merchant (API reads and webhooks); bills don't carry it.
  • digestData and the subscription's stored allowance and maximum in min units are never shown; the product, organization and user relations are absent.

PATCH /subscriptions/:uuid

  • The only thing a merchant edits on a subscription: its metadata. Its price, terms and status are locked (a price change: cancel with immediate=false and send a new checkout; § Cancel). Other body fields are ignored.
  • Merge: metadata absent → unchanged; a key with a value sets it; a key with "" deletes it; keys not named are kept. There is no "replace everything": send each key with "" to clear them. The limits are checked on the merged result: at most 50 keys, keys of 1–40 characters of A–Z a–z 0–9 _ - . :, values of at most 500 characters without control characters (validators.md metadata); otherwise 400 validation_failed on metadata or metadata.<key>, and nothing changes.
  • Two updates at once never lose each other's keys (each reads the stored metadata, its row locked).
  • Answers 200 with the Subscription as written. The next subscription.* webhooks carry the new metadata (no event is sent for the edit itself).

Cancel (POST /subscriptions/:uuid/cancel)

  • ?immediate=true|false lets a merchant cancel a subscription without its customer signing. QBitFlow's operator cancels it on-chain now in both cases, so nothing can bill it anymore:
    • immediate=true (the default): cancelled at once (status: "cancelled", cancellationReason: "merchant").
    • immediate=false: stopped now (status: "stopped", never billed again, the customer keeps what they paid for), then cancelled at the end of its paid period (nextBillingAt) by its bill: the normal cancellation process, as when the customer cancels.
    • immediate is a boolean (true/false, 1/0); another value → 400 validation_failed on immediate.
  • Its answer is the subscription, as the cancellation left it (the Subscription above), with:
    • 200 once the cancellation is done: cancelled, or stopped with immediate=false. A trial, or a subscription stopped already, ends at once (nothing to send on-chain);
    • 202 while the on-chain force cancel still confirms (QBitFlow waits up to 15 seconds): the status is unchanged yet, and subscription.statusChanged tells the end. The cancellation goes on whatever happens to the request.
  • The subscription is looked up in the caller's space first: another space's → 404 whatever its state, never 409. A cancelled one of the caller's space → 409 subscription_already_stopped_or_inactive (cancelled already: nothing to cancel).
  • A subscription stopped already: immediate=false → 409 subscription_already_stopped_or_inactive; immediate=true cancels it at once (off-chain: it was cancelled on-chain when it stopped), keeping the reason it stopped for.
  • A free trial (trial, trialExpired: nothing on-chain, no paid period) is cancelled off-chain at once, without a transaction; immediate=false on a trial → 400 validation_failed on immediate.
  • If the on-chain force cancel fails, the subscription is cancelled (or stopped) off-chain all the same: it is never billed again either way. Unless the contract has it inactive already, QBitFlow then sends the on-chain force cancel again (every hour) until it lands; its status doesn't change again (no new event).
  • immediate=false on a subscription whose bill is due already (pastDue, or waiting for a new maximum) stops it, and its waiting bill cancels it at once.
  • Each change is announced once: subscription.statusChanged to cancelled (its allowance amount "0", cancelledAt, cancellationReason, no nextBillingAt), or to stopped then, at the period's end, to cancelled. A charge already on its way that lands after the cancellation is recorded (subscription.billed, its subscription.status cancelled); the subscription stays cancelled.
  • A cancellation already running for the subscription → 409 tx_already_sent. Once it is done, it can be asked again: immediate=false, then immediate=true, cancels it at once.
  • Changing a subscriber's price isn't possible on an existing subscription (its price is locked at signup and the customer signed its maximum): cancel it with immediate=false (they keep the period they paid for), and send them a new checkout at the new price.

Test bill (POST /subscriptions/:uuid/test-bill)

  • The test bill: live subscriptions are billed on their due date; test subscriptions are billed only from here, so integrators bill at their own pace. It runs the same bill as live billing (§ Billing), so statuses and webhooks are exactly live's. A live subscription → 400 test_mode_only (every server).
  • Not due yet (nextBillingAt in the future) → 409 payment_not_due, and nothing runs.
  • When due, it starts the bill of the subscription's nextBillingAt. If that bill is waiting already (in dunning after a failed attempt, or waiting for a new maximum), it runs the next attempt now instead of waiting (it spends an attempt). The retry schedule still counts from the first failure, and the attempt after it comes at least a day later (§ Billing).
  • It answers 200 with a TestBill once the attempt settled (at most about 2 minutes; later, stage is still running):
    • billUuid: the bill, sub-hist@…: a paid bill has this id (GET /bills/:uuid, subscription.billed).
    • stage: done, waiting (for its next attempt, or for the end of a trial's grace period), pending (for the customer's new maximum) or running.
    • outcome (once done; absent before): paid, cancelled (stopped by its subscriber, its trial over, its merchant closed, inactive on-chain, or its last attempt failed), skipped (below the minimum amount: the period moved on without a charge), paused or notDue.
    • attempts: the bill's failed attempts. nextAttemptAt: while waiting or pending, when it tries again at the latest. txHash: the paid charge's transaction. failureCode: the last failure's code (errors), e.g. insufficient_allowance. Each absent without a value.
  • A bill that is done answers its end again. A cancelled subscription → 409 subscription_already_stopped_or_inactive (nothing left to bill); another space's → 404.

Billing

QBitFlow bills each subscription from its subscriber's wallet on its nextBillingAt. No funds are held in advance. Each period's bill is charged once: it has its own uuid, and the paid bill has that uuid (sub-hist@<billUuid>).

  • When. A live subscription is billed within about 10 minutes of its nextBillingAt (a sweep every 10 minutes, then the chain confirms the charge), never before it (the contracts refuse an early bill). Its subscriber keeps access meanwhile (accessUntil). A test subscription is billed only when its merchant asks (§ Test bill), with the same statuses and webhooks.
  • How much. Every bill charges priceUsd plus the subscription's fees lines: the price the customer subscribed at (the checkout's, or the upgrade's for a trial confirmed later) and what its checkout added to it (a tax, shipping, the processing fee: Checkout sessions § Fees), both locked at signup, converted to the token at the bill's day price. The bill's amountUsd is that sum, its amount the token amount charged. Changing the product's price applies to new subscribers only (Products). The amount a bill charges never exceeds the maximum per period the subscriber signed (allowance.maxPerPeriod): the contract refuses it, and the bill waits for a new maximum (below).
  • Paid. The bill is recorded with its fees, nextBillingAt moves to the next period, and subscription.billed is sent: { "bill": Bill, "subscription": Subscription }, the bill with the period paid (periodStart → periodEnd), the subscription as the bill leaves it. The status goes back to active; when the remaining allowance is under 1.05 periods, actionRequired is topUpAllowance. A stopped subscription stays stopped.
  • The customer's wallet can't pay (balance, allowance or approval too low): the subscription becomes pastDue, and subscription.billingFailed is sent with attempt and remainingAttempts. The bill is retried 1, 3, 5 and 7 days after its first failed attempt (5 attempts in all), and never less than a day after the previous attempt. The customer raising their allowance (or their maximum) retries it at once; that extra try spends no attempt and sends nothing if it still fails. The subscription stays pastDue until the bill is paid. When remainingAttempts is 0 the subscription is still pastDue in that event, and its cancellation follows (subscription.statusChanged to cancelled).
  • Above the customer's maximum (the token's price moved): the subscription keeps its status, actionRequired becomes raiseMaximum (subscription.actionRequiredChanged), and subscription.billingFailed is sent once with reason: maxAmountExceeded. The bill waits up to 7 days for the customer to approve a new maximum, without spending an attempt. Approving a new maximum retries it at once. After 7 days, the retries above start.
  • Where a failing bill stands, on a read (dunning, every subscription read; absent while no bill is failing and once the subscription is cancelled):
    • failedAttempts and remainingAttempts (after the last one fails, the subscription is cancelled); failingSince: its first failed attempt;
    • nextAttemptAt: when it is tried again at the latest (sooner if the customer tops up or raises their maximum);
    • while it waits for a new maximum: awaitingMaximumSince, and nextAttemptAt is when the wait ends (failedAttempts is 0 if no attempt failed before). Webhooks don't carry it (subscription.billingFailed tells each failure).
  • No longer active on-chain (subscription_not_active): the subscription is cancelled.
  • QBitFlow's own failures (a network or a price unavailable, a chain whose clock is behind, a refusal of QBitFlow's own signature or key): retried every 30 minutes. No attempt is spent, no event or email is sent, the status doesn't change, the subscription is never cancelled for them.
  • Stopped (by its subscriber, or its merchant with immediate=false): cancelled when its last paid period ends, keeping its cancellationReason. Free trial: trialExpired when the trial ends, cancelled 7 days later unless the customer confirmed it (trialNotConverted). The customer is emailed when it ends, with the link to confirm it (setting emails.customerTrialEnded). Confirmed, the trial is the paid subscription: the same uuid, reference, metadata and createdAt, now active and billed (subscription.statusChanged, then subscription.billed; Hosted subscriptions). Merchant closed (the member removed, the organization closed): its subscriptions are cancelled, never charged again. Below the minimum amount: no charge, the next period starts.
  • Customer emails: each failed attempt emails the customer (why, when it is retried or that the subscription is cancelled, and the management page link); setting emails.customerBillingFailed. Each paid bill emails the customer its receipt (setting emails.customerReceipts). Test mode never emails; both are sent in the merchant's name.

The list

  • GET /subscriptions is paginated (pagination: limit 20 by default, at most 100, clamped; the opaque cursor of the previous page's nextCursor): the space's subscriptions, cancelled ones included, newest first by createdAt then uuid. A cursor that isn't a nextCursor → 400 validation_failed on cursor.
  • Filters (each optional, combined with AND): status (any status value; another value → 400 on status, which lists the values), reference (the merchant's reference: 0 or 1 item; reference rules, at most 100), customerUuid, productUuid, createdAfter, createdBefore (RFC 3339 instants or dates, both excluded), includeMembers, userUuid (above). A malformed value → 400 validation_failed on its name. The former GET …/reference/:type/:reference route is gone: filter the list.
  • Items are Subscriptions, as GET /subscriptions/:uuid returns them.

Bills

  • GET /subscriptions/:uuid/bills lists every bill of one of the caller's subscriptions (a cancelled one's too), paginated (pagination), newest first by createdAt then uuid. A subscription not billed yet → {"items": [], "hasMore": false}.
  • GET /bills/:uuid reads one bill of the caller's space (§ Ids); ?includeMembers=true from the organization's space reads a member's (read only).
  • A Bill is what its customer paid for one period: amount / amountMinUnits (the token charged) and amountUsd, currency, productName / productDescription (as they were when it was paid), subscriptionUuid (sub@…), txHash and where to check it, its settlement (the fees and split, merchant only), paid* and confirmedAt, its customer and its refund state (Payments and transactions § Who paid, § Refund state, § When). Bills carry no merchant metadata: read the subscription's.
  • A bill keeps the period it paid: periodStart (its due date; the subscription's start for its first bill) → periodEnd (its next bill: paid until then), as subscription.billed says. Absent on bills recorded before (their period can't be recovered).

The codes named here

  • 400validation_failed

    path/query/body failed binding or validation, or a business rule about one input (a field named in errors)

  • 403policy_disabled

    a member doing what their organization's policy doesn't allow them, reads of what the policy governs included

  • 409tx_already_sent

    a transaction sent already: running, or completed (Payments and transactions § Sending a signed transaction)

  • 405method_not_allowed

    the path exists, not with this method; the Allow header lists its methods. Answered before any credential is read, like the 404 of a path no route has

  • 400test_mode_only

    something only test mode does asked in live mode (a test bill, a faucet, a test payment)

  • 409subscription_already_stopped_or_inactive

    cancelling a subscription, raising its allowance or its maximum, once it is stopped (it ends with its paid period; customer-side routes), a merchant's POST /subscriptions/:uuid/cancel?immediate=false of a stopped one, or a merchant's POST /subscriptions/:uuid/cancel or /test-bill of a cancelled one

  • 422insufficient_allowance

    granted QBitFlow less than this amount: increase the allowance

  • 409subscription_not_active

    asked for what the subscription's state refuses

  • 409payment_not_due

    asked for what the subscription's state refuses

  • 503network_unavailable

    can't act: QBitFlow can't send on the network for now, or has no fresh USD price for the currency (missing, older than 5 minutes, or a stablecoin off its peg by more than 5 %), retry later