Skip to main content
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 charged price + VAT.
  • inclusive — the price already includes VAT; the buyer is charged the listed price and the VAT is extracted from it.
Added to 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 (send null) restores the default.
The resolution is applied fresh at checkout, so an edit takes effect on every already-issued link immediately. See the 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 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": "…" } }.
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 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.succeeded fires 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).
The field is no longer part of the contract: sending it is ignored rather than rejected, so existing integrations keep working — but 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) → 422 PAYMENT_NOT_REFUNDABLE.
  • The refund is triggered at the payment processor; the REFUNDED / PARTIALLY_REFUNDED transition and the balance debit arrive asynchronously via the payment.refunded webhook, so the returned payment may still read COMPLETED.
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.paymentProvider and Subscription.providerSubscriptionId (GET /v3/subscriptions, GET /v3/subscriptions/{id}).
No request field changes and no behavioural change — the same charge is processed identically. If you branched on these values, drive off the processor-neutral fields (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.
  • Receipt gains a recurring object (recurringInterval + recurringIntervalCount), set for a subscription charge and null for 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/subscriptions accepts CARD / APPLE_PAY / GOOGLE_PAY / CRYPTO (crypto sends cryptoMode + chainId + assetId and returns a deposit instruction).
  • No-code subscriptions on the hosted checkout: a mode=subscription session 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.
  • Subscription now exposes read-only dunning state: currentCycleDueAt, renewalAttempt, nextRenewalAttemptAt, lastDeclineCategory.
  • Full subscription.* webhook coverage: created, renewed, past_due, expired, canceled.
  • subscription.created fires at activation (first cycle confirmed → ACTIVE), not at create time — you never receive a created for 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, …).
See the migration guide to move from v2.