Tax behavior: inclusive vs exclusive pricing
Payment, subscription, and checkout-session creation now accept an optional
taxBehavior (exclusive | inclusive) controlling how MoR VAT relates to
the price:exclusive(default) — the price is HT; VAT is added on top, so the buyer is chargedprice + VAT.inclusive— the price already includes VAT; the buyer is charged the listed price and the VAT is extracted from it.
POST /v3/payments, POST /v3/subscriptions (applies to every cycle;
the subscription body also gains billingAddress + businessData), and
POST /v3/checkout/sessions (signed into the session so the hosted page’s TTC
matches the charge). Every payment response gains taxInclusive (boolean).Analytics: inactive-subscription count
GET /v3/analytics now returns subscription.inactiveSubscriptions —
the point-in-time count of subscriptions no longer active (canceled / expired /
unpaid), the complement of activeSubscriptions.Per-product payment-method whitelist
Products now carry an optional
paymentMethods field on
POST /v3/products and PATCH /v3/products/{id}, echoed on every product
response.null/[]/ omitted — the product accepts every method enabled on your account (unchanged default).- A non-empty list — checkout is restricted to those categories (e.g.
["CARD", "STABLECOIN"]). The list is always intersected with your account’s enabled methods, so listing a method you haven’t enabled is a harmless no-op, and clearing it (sendnull) restores the default.
PaymentMethodOverride schema for the
full category enum.Breaking: crypto and card options are now grouped
Breaking change. Method-specific request options are now grouped into a
Migrating: move the fields as per the table. Unknown fields are ignored
rather than rejected, so a body left flat does not fail on the stray keys —
it fails on the now-missing group, with a
crypto and a card object instead of sitting flat on the body. This affects
POST /v3/payments, POST /v3/subscriptions, and the hosted-checkout pay
endpoint. Responses are unchanged.On the hosted checkout, the flat
customerEmail / customerFirstName /
customerLastName collapse into the customerData object already used by
POST /v3/payments — { "customerData": { "email": "…" } }.422 naming what it wants (e.g.
method=CRYPTO requires crypto.mode). There is no deprecation window: the flat
fields have no effect as of this release.Removed the crypto urgency field
The
urgency request field is removed from POST /v3/payments (it was
documented as a BTC/SOL fee-policy override). Every crypto payment now uses
the fast policy:- Bitcoin — deposits are accepted at zero confirmations as soon as a
non-RBF transaction is seen in the mempool, so
payment.succeededfires immediately. A deposit that signals RBF still waits for 1 confirmation. - Solana / EVM — the create-time fee snapshot always bids the fast tier (p90 priority fee on Solana, 2× base fee on EVM).
urgency: "slow"
or "normal" no longer has any effect. Drop it from your request bodies.Merchant-initiated refunds
New endpoint
POST /v3/payments/{id}/refund — refund a captured card/APM
payment. Omit amount for a full refund of the remaining amount; a lower
amount refunds partially. An optional reason is accepted.- Crypto payments are not refundable (funds settle on-chain) →
422PAYMENT_NOT_REFUNDABLE. - The refund is triggered at the payment processor; the
REFUNDED/PARTIALLY_REFUNDEDtransition and the balance debit arrive asynchronously via thepayment.refundedwebhook, so the returned payment may still readCOMPLETED.
Payment-processor identity removed from responses
Response payloads no longer expose which payment processor handled a charge —
the API is processor-agnostic by contract. Removed fields:
Payment.paymentProvider(GET /v3/payments,GET /v3/payments/{id}).Subscription.paymentProviderandSubscription.providerSubscriptionId(GET /v3/subscriptions,GET /v3/subscriptions/{id}).
status, method, currency) instead.Analytics totals are FX-normalized to USD
GET /v3/analytics now converts EUR-denominated revenue to a USD base
before summing, instead of adding EUR and USD cents as if 1 € = 1 $. Every
money field (overview, series, subscription, oneTime, productMix,
methodBreakdown) is expressed in the response currency (now “USD” whenever
conversion ran). A new rates object carries eurToUsdScaled1e8 (USD per
1 EUR, scaled 1e8) so you can render totals in whichever currency you prefer.
When the rate is temporarily unavailable, rates.eurToUsdScaled1e8 is null
and amounts fall back to the previous (single-currency) behaviour.Crypto balance is net of fees
A crypto payment settled into your managed vault now credits your balance with
the net amount (settled amount − the Suby fee that is split off on-chain),
not the gross. Previously the balance briefly over-counted by the fee. The
ledger entry carries the gross + fee breakdown for reconciliation.
Out-of-order webhook safety
Payment status transitions are now guarded by the state machine on every
webhook write. A late or duplicate
payment.failed that arrives after a
payment was captured (succeeded) is dropped instead of flipping the payment
to failed — a captured payment never regresses to a failure state. A genuine
post-capture problem still comes through as its own payment.refunded /
chargeback event. This prevents a settled payment from being incorrectly
marked failed (and its funds from silently dropping off your balance).Card intents expire
Card/APM payments now carry an
expiresAt (previously only crypto did).
It’s bounded to the originating checkout-session window (or 30 minutes on the
direct POST /v3/payments path). An unfinished intent — a payer who closed the
tab before completing 3-D Secure — is swept to EXPIRED once past it,
instead of sitting PENDING indefinitely. Genuinely-in-flight amounts on the
dashboard balance no longer include these abandoned intents.Receipt billing cadence
The receipt payload (
GET /v3/payments/{id}/receipt), its PDF invoice, and
the payment-receipt email now reflect the real billing cadence.Receiptgains arecurringobject (recurringInterval+recurringIntervalCount), set for a subscription charge andnullfor a one-time payment.- The invoice PDF’s line Interval now reads
"monthly"/"every 3 months"for subscriptions instead of always"one-time". - The receipt email shows a
Billed <cadence>line only for subscription charges; one-time receipts omit it.
Subscriptions & renewals
Subscription lifecycle is now fully driven by Suby.
POST /v3/subscriptionsacceptsCARD/APPLE_PAY/GOOGLE_PAY/CRYPTO(crypto sendscryptoMode+chainId+assetIdand returns a depositinstruction).- No-code subscriptions on the hosted checkout: a
mode=subscriptionsession starts a subscription + first cycle. - Automatic renewals — card/wallet re-charged off-session with a progressive smart-retry (up to 8 attempts over 30 days; soft declines retried, hard declines end the subscription). Crypto renews via a per-cycle email.
Subscriptionnow exposes read-only dunning state:currentCycleDueAt,renewalAttempt,nextRenewalAttemptAt,lastDeclineCategory.- Full
subscription.*webhook coverage:created,renewed,past_due,expired,canceled. subscription.createdfires at activation (first cycle confirmed →ACTIVE), not at create time — you never receive acreatedfor a subscription whose first charge is declined.
Initial
Initial public release of the v3 RESTful API under the
/v3 prefix.- Plural, resource-oriented endpoints (
/v3/payments,/v3/products, …). - Setup Intents + saved payment methods for off-session charges.
- Checkout Sessions (signed
cs_…tokens) for hosted checkout. - Webhook Endpoints managed via the API, with secret rotation.
- Org / product / customer analytics endpoints.
- Dotted webhook event names (
payment.succeeded,subscription.renewed, …).

