Changelog

Recent updates, new features, and improvements to the RevKeen platform.

Stay up to date with everything we ship. Major releases are announced on our blog — this page covers the full history.


October 2026

Usage events: a reused idempotency key with a different payload is refused (behaviour change)

  • POST /v2/usage-events now compares the payload when an idempotency_key is reused. The same payload still returns duplicate. A different payload returns 409 idempotency_key_reused with existing_event_id for a single event, or a conflict result inside a 207 batch, and nothing is recorded.
  • Before, the changed event was returned as duplicate and silently dropped.
  • This is switched on account by account; you will be told before it reaches yours. See Usage-based billing.
  • The batch response summary is now documented as it has always been sent: total, ingested, duplicates, skipped, failed, plus the new conflicts. The API reference previously listed a duplicate field that was never returned.

Send a copy of a Direct Debit advance notice from the dashboard

  • A subscription's Direct Debit panel has a Send notice copy button. It emails the customer a copy of the advance notice already sent, for the customer who did not get or lost it. A copy is not a new notice: it changes no amount or date. It is refused when the original bounced or was never sent, or when the collection has changed since. Up to 3 copies per notice, at least 15 minutes apart. See Emails and notices.

prorationBehavior: invoice_immediately is deprecated on the plan-change operations; new opt-in API version 2026-11-02

  • On POST /v2/subscriptions/{id}/change-plan and POST /v2/subscriptions/{id}/preview-change-plan, invoice_immediately is applied as next_invoice and never charges, as before, on every version up to 2026-05-01 (the default). Responses now carry a Deprecation header and a Link to the versioning guide. Send next_invoice.
  • New opt-in version 2026-11-02: there, invoice_immediately means "charge the card now", which is a dashboard action. A card subscription gets 403 charge_now_requires_interactive_session and any other subscription gets 400 charge_now_card_only; nothing is changed or charged. Nothing changes for a request that does not send RevKeen-Version: 2026-11-02: the default stays 2026-05-01.
  • The dashboard's plan change dialog gains "Charge difference now" for active card subscriptions, when it is switched on for your account. The plan changes only if the charge succeeds.

POST /v2/subscriptions starts the trial its price asks for (behaviour change)

  • A price with trial_period_days now starts the subscription in a trial. Before, POST /v2/subscriptions ignored the price's trial and only an explicit trialEnd started one, so the subscription was billed at once. If you create subscriptions on a price that has a default trial and want no trial, send trial_period_days: 0.
  • New optional request field trial_period_days (0 to 730): the days of trial, counted from the start of the first period. It overrides the price's value. It cannot be combined with trialEnd: sending both is a 400 with the code trial_conflict. trialEnd on its own works as before.
  • A trial does not need a saved paymentMethodId, but a trial that starts without one cannot collect payment when it ends yet: the subscription moves to incomplete. Save a payment method for the customer before the trial ends.

GET /v2/customers/{id}/state needs three scopes and says when a list is cut short (breaking)

  • The snapshot returns the customer's subscriptions and invoices, so the key now needs customers:read, subscriptions:read and invoices:read. A key with only customers:read gets 403 instead of billing data it was not granted.
  • subscriptions.active and invoices.overdue are read on their own, so an overdue invoice older than the newest 10, or an active subscription older than the newest 20, is no longer missing. Each list has a *_has_more flag (active_has_more, all_has_more, overdue_has_more, recent_has_more) that is true when the customer has more rows than the list holds.
  • amount_due_minor is null when an invoice records no amount due. It no longer falls back to the invoice total, or to 0.
  • The response is typed in the API reference and the SDKs (CustomerStateCustomer, CustomerStateSubscription, CustomerStateInvoice) instead of free-form objects.

Webhook events mandate.created and mandate.auddis_rejected are removed (deprecated)

  • Neither event was ever sent. Both are removed from the event catalogue and the API reference. An AUDDIS rejection is reported as mandate.suspended.
  • POST /v2/webhook-endpoints and PATCH /v2/webhook-endpoints/{id} still accept both names in enabled_events, as deprecated no-ops. They are stored and returned as before, and they match no event. Remove them from your endpoint configuration; a later release may refuse them with 400 invalid_event_type.

GET /v2/usage/balance no longer returns cost and margin figures (breaking)

  • The response no longer includes total_cost_minor, total_payment_processing_cost_minor, total_platform_fee_minor, true_net_margin_minor or true_net_margin_percent, nor margin_minor and total_cost_minor on each meter. These are your own costs and fees, not figures for a customer-facing balance; they remain in the dashboard.
  • Balances, usage and the rest of the response are unchanged. If you read any of the removed fields, stop reading them before you update.

Customer create and update take snake_case fields (behaviour change)

  • POST /v2/customers and PATCH /v2/customers/{id} take external_id, company_name, address_line1, address_line2, postal_code and custom_fields, matching the rest of the API. An unknown field is now refused with 400 naming it in param, instead of being ignored.
  • The camelCase spellings externalId, companyName, addressLine1, addressLine2, postalCode and customFields are still accepted for now. A request that uses one gets a Deprecation header and a Link to the Customers guide. Sending the same field under both spellings with different values is refused with 400 on the snake_case name.

Checkout session create takes snake_case fields; three path parameters are renamed (behaviour change)

  • POST /v2/checkout-sessions takes invoice_id, success_url, cancel_url, allowed_methods and companion_device_id, matching the rest of the API. An unknown field is refused with 400 naming it.
  • The camelCase spellings invoiceId, successUrl, cancelUrl, allowedMethods and companionDeviceId are still accepted for now. A request that uses one gets a Deprecation header and a Link to the Checkout sessions page. Move to the snake_case names.
  • Three path parameters are renamed in the API reference and in the SDKs: lineId to line_id (PATCH and DELETE /v2/cart-sessions/{id}/line-items/{line_id}), productId to product_id (GET /v2/storefront/products/{product_id}) and originId to origin_id (DELETE /v2/storefront/origins/{origin_id}). A path parameter is matched by position, so no URL you send changes. If you call these operations through a generated SDK, the argument name changes when you update it.

checkout.session.completed and checkout.session.expired webhooks are now sent

  • Both events were listed in the event catalogue but never delivered. checkout.session.completed is now sent when a checkout session is paid, and checkout.session.expired when an open or pending session is expired with POST /v2/checkout-sessions/{id}/expire. A session that only reaches its expiry time is not sent as an event.
  • A paid checkout also sends commerce.checkout.completed, which is not part of the catalogue. An endpoint subscribed to * receives both events, each with its own id; checkout.* receives only the checkout.session.* events. To act once per payment, subscribe to checkout.session.completed by name.
  • The checkout.session.completed example showed status: "complete". The value is completed.
  • POST /v2/payment-links, GET /v2/payment-links, GET /v2/payment-links/{id} and POST /v2/payment-links/{id}/expire now return the documented snake_case fields. Before, they returned the stored record with camelCase keys such as merchantId, successUrl and isActive. If you read those keys, switch to merchant_id, success_url and status.
  • Every link now carries url, the hosted checkout page to share with your customer. You no longer need to build it from the id.
  • public_id is gone from the response schema. It was documented as required but was never returned.
  • status is one of active, inactive, archived or expired, in responses and in the status filter of GET /v2/payment-links. A newly created link is active and is listed under ?status=active. The old values draft and completed were never returned and are now refused as a filter with 400.
  • mode is invoice, subscription or custom. A link created in the dashboard returns custom.
  • Authorization: Bearer <key> now works on /v2/payment-links, as it does on the rest of the API. Before, only X-API-Key was accepted here. A request with no credential gets 401 with a WWW-Authenticate header.
  • POST /v2/payment-links/{id}/expire, /activate, /deactivate and /archive are no longer marked deprecated. They remain supported.
  • idempotency_key in the create body is deprecated and ignored. Send the Idempotency-Key header: a repeat request with the same header returns the original response.

Change a subscription's plan through the API, with a proration preview

  • POST /v2/subscriptions/{id}/change-plan moves an active, trialing or past due subscription to another recurring price. Nothing is charged when the plan changes: the difference for the rest of the period is added to (or credited on) the next renewal invoice, as in the dashboard. It needs the subscriptions:write scope and the subscription:update permission.
  • POST /v2/subscriptions/{id}/preview-change-plan shows the same figures without changing anything. It needs the subscriptions:read scope and the subscription:read permission.
  • A new price with no amount above zero is refused with 400 price_amount_missing, in the dashboard too. A Direct Debit subscription is refused with 409 direct_debit_plan_change_unsupported and can still be changed from the dashboard.
  • New webhook event subscription.plan_changed. See Subscriptions.

Checkout sessions through the API are created for an invoice, and the URL can be read back (behaviour change)

  • POST /v2/checkout-sessions now takes an invoiceId, and only an invoiceId. The session charges the invoice's amount due. productId and amountMinor are removed: a session created from a product and an amount returned a link the hosted checkout page could not open, so no working integration is affected. Sending either, or any key the request does not define, is refused with 400 that names the key. To collect for something that is not yet an invoice, create the invoice first.
  • An invoice in draft is refused with 400 ("Invoice status draft cannot start checkout"), as POST /v2/invoices/{id}/pay already refuses it. Finalize the invoice first. Issued, sent, approved and other payable statuses still start a session.
  • GET /v2/checkout-sessions/{id} now returns the hosted checkout url while the session is pending or open and has not expired, when the request is made with an API key. Before, url was always null. It is null once the session can no longer be paid, and for requests made through an OAuth app, an agent or MCP.
  • POST /v2/checkout-sessions/{id}/expire only expires a session that is still open or pending. A session whose payment has started is left alone and the call returns 409. An unknown session returns 404.

Pause and resume a subscription through the API

  • POST /v2/subscriptions/{id}/pause pauses an active or trialing subscription immediately, and POST /v2/subscriptions/{id}/resume resumes a paused one. Neither takes any parameters. They need the subscriptions:write scope and the subscription:pause / subscription:resume permission. A Direct Debit pause lists the invoices left open in dd_collection_stopped.
  • On resume, the periods that elapsed while the subscription was paused are not billed: it keeps its billing day and the next charge is the next billing date after the resume. A Direct Debit subscription resumes only if its mandate can collect now; otherwise the call is refused with 409 mandate_not_usable and the subscription stays paused.
  • New webhook events subscription.paused and subscription.resumed. See Subscriptions.

Collect an invoice by Direct Debit through the API

  • POST /v2/invoices/{id}/pay with mode: "collect" and payment_method: "direct_debit" asks RevKeen to collect the invoice's outstanding amount by Direct Debit, against the customer's active mandate. It returns 202. The invoice stays unpaid until the collection settles.
  • The customer is sent the Direct Debit advance notice first. While that notice is being delivered, the response shows collection.status awaiting_advance_notice; the collection is submitted once delivery is confirmed.
  • The amount collected is always the invoice's outstanding amount. A collect request that sends amount_minor, or any other field, is refused with 400. Card collection is not available through this operation, and payment_method: "card" is refused with 400.
  • It is refused with 409, and nothing is scheduled, when the invoice is already paid, void, a draft or not collectable, when a Direct Debit collection for it is already pending, when the customer has no usable Direct Debit mandate (mandate_not_usable), or when Direct Debit is not enabled for your account (direct_debit_not_configured).
  • It needs the invoices:write scope, and for an API key also mandates:write, plus the direct_debit:submit_collection permission. Your account owners and admins are emailed whenever an API key starts a collection. Send an Idempotency-Key header: a replay schedules nothing a second time.

Record a payment received outside RevKeen through the API (behaviour change)

  • POST /v2/invoices/{id}/pay records a payment the customer made outside RevKeen, such as a bank transfer, cash or a cheque, and applies it to the invoice. RevKeen collects no money. Send mode: "record", a payment_method, a reference and an amount_minor. All four are required and nothing is defaulted. notes and paid_at are optional, and paid_at cannot be in the future.
  • A payment that covers what is outstanding moves the invoice to paid; a smaller one moves it to partially_paid. An amount above the invoice total less what is already paid is refused with 400. Every recorded payment creates a payment record.
  • It is refused with 409, and nothing changes, when the invoice is already paid, void, a draft or uncollectible, or when a Direct Debit collection for the invoice is still pending. Cancel the collection first.
  • It needs the invoices:write scope and the invoice:mark_paid permission. Send an Idempotency-Key header to make retries safe: a replay records nothing a second time.
  • Behaviour change: PATCH /v2/invoices/{id} no longer accepts status set to paid or partially_paid. It returns 400. Use POST /v2/invoices/{id}/pay instead, so a paid invoice always has a payment record.

Detach a payment method and set the default customer payment method through the API

  • POST /v2/payment-methods/{id}/detach removes a stored payment method from a customer. It is refused with 409 payment_method_in_use, and nothing changes, while the method is the customer's default or a subscription that is active, trialing or past due bills on it.
  • POST /v2/payment-methods/{id}/set-default makes a payment method the customer's default. It changes the customer's default only; existing subscriptions keep the payment method they bill on. A payment method that is no longer active is refused with 409 payment_method_not_active.
  • Both need the payment_methods:write scope. Send an Idempotency-Key header to make retries safe.

POST /v2/subscriptions refuses fields it never used (breaking)

  • businessId, planId, billingAnchorDay, pauseAtPeriodEnd, cancelAtPeriodEnd, billingEndStrategy, billingEndsOn, billingMaxCycles and prorationMode were accepted and ignored: the subscription was created without them, so a request for a fixed term produced a subscription that never ends. They are removed from the request schema, and a request that sends one gets 400 naming the field. Any other unknown field is refused the same way.
  • To end a subscription, call POST /v2/subscriptions/{id}/cancel (immediately, or at the end of the period). Remove the nine fields from your requests; generated clients lose them from the create request type.

September 2026

Product collections

  • Group products into collections from the dashboard or the API (/v2/product-collections). A product can belong to more than one collection. See Core concepts.

RevKeen Commerce add-on

  • Fee schedule fees-2026-09-28-v1 adds the optional RevKeen Commerce add-on, a managed RevKeen Storefront for merchants without a website: £29/month, included on Pro and Unlimited. No existing fee changed. See Fees.

Sanity Cart integration removed

  • The merchant Sanity Cart integration has been removed, including the CLI's Sanity project scaffolding. Use RevKeen Cart with your own storefront instead; see Build a storefront.

RevKeen CLI v0.2.1 and v0.3.0

  • CLI v0.2.1 was released on 27 September and v0.3.0 on 30 September. See CLI.

Subscriptions created through the API now bill their first period (behaviour change)

  • POST /v2/subscriptions now bills the first period when the subscription is created, at the price's amount for the quantity and at the price's interval. Before, an API-created subscription had no amount and never collected.
  • On card, the saved card is charged straight away. paymentMethodId is required unless the subscription starts in a trial; without it you get 400 payment_method_required.
  • By Direct Debit, the first collection is scheduled with advance notice, typically 5 to 7 working days after creation.
  • With a trial, nothing is billed until the trial ends.
  • A price that cannot be billed (no amount, not recurring, or pay-what-you-want) is refused with 400.

Installing and uninstalling apps now needs an Owner, Admin or Developer role (behaviour change)

  • Installing or uninstalling an app from Apps → Marketplace now needs the Owner, Admin or Developer role. Finance, Support and Viewer members get 403 and nothing is installed or removed.
  • Apps you already have installed are unaffected.

Create a Direct Debit subscription through the API

  • POST /v2/subscriptions accepts paymentRail: "direct_debit" with the mandateId of an active mandate the customer already has. GBP only. See Start from the API.
  • It needs a signed-in team member or an OAuth app with access to mandates. API keys are refused with 403, the same answer they get from the mandate endpoints.
  • Subscription responses now include payment_rail, mandate_id and payment_method_id.
  • Subscriptions created through the API don't collect payment yet, on card or Direct Debit. They are created without an amount, so no renewal takes a payment. To collect today, send the customer a checkout link or an invoice.

POST /v2/subscriptions now keeps paymentMethodId, quantity and productId (behaviour change)

  • These fields were accepted and then silently ignored: the subscription was stored with no payment method, a quantity of 1 and no product. They are now stored.
  • They are also checked. A paymentMethodId that is not this customer's active payment method returns 404 payment_method_not_found. A productId that is not yours returns 404 product_not_found, and one that does not match the price's product returns 400 product_price_mismatch.
  • If you were sending any of these, check that the values are the ones you intend, especially quantity.
  • POST /v2/payment-links now reads the snake_case fields it documents. A create with only product_ids works; it previously returned 400.
  • This affected the TypeScript, Go and PHP SDKs as well as direct API calls, because all of them send snake_case.
  • success_url, cancel_url, expires_at, selection_mode, default_product_id and highlighted_product_id are now applied. Before, they were accepted and silently ignored, and every link expired after 7 days whatever expires_at said. The body idempotency_key is not applied: send the Idempotency-Key header instead.
  • If you rely on the 7-day expiry, leave expires_at out. A link created without it still expires after 7 days.
  • A single_select link whose default_product_id or highlighted_product_id is not one of the link's products is now rejected with 400.
  • These documented fields still have no effect on create: redirect_url, collect_shipping, allow_promotion_codes, amount_minor, invoice_id, subscription_id and tax_behavior.
  • To retry a create safely, send the Idempotency-Key header.
  • created_via in payment-link metadata is now set only by RevKeen. It records where a link was created.
  • If you send it on POST /v2/payment-links or when updating a link, it is dropped without an error. The rest of your metadata is stored as before. See Checkout Links.
  • POST /v2/payment-links/{id}/expire, /activate and /archive, and PATCH /v2/payment-links/{id}/status, now require an API key with the payment_links:write scope, like create and update already did. A key without it gets 403.
  • Keys with payment_links:write or payment_links:*, and dashboard sessions, are unaffected.

No available payment method now returns 503 instead of 500

  • POST /v2/checkout-sessions and POST /v2/cart-sessions/{id}/convert now return 503 with code: "NO_PAYMENT_METHODS_AVAILABLE" when you have no online payment method enabled and live for the checkout, or none that can collect its currency. They previously returned an undocumented 500.
  • No session is created and the cart stays open. Enable a payment method in Settings → Payments, then retry. Other errors, and successful responses, are unchanged.

Retired: order create, order pay and tax-rate endpoints

  • POST /v2/orders, POST /v2/orders/{id}/pay and the five /v2/tax-rates endpoints are removed. They were not part of the published API reference, returned an error on every request since they were introduced, and never created, paid for or stored anything.
  • Orders are created when a checkout is paid. Listing, retrieving, updating, cancelling and fulfilling orders is unchanged.
  • The orders_create MCP tool is removed with them. It was never exposed to connected apps.

A new subscription takes its price's currency (behaviour change)

  • POST /v2/subscriptions with no currency now creates the subscription in its price's currency. It previously stored USD whatever the price was priced in. If the price has no currency, your default currency (Settings → Regional) is used.
  • A currency that differs from the price's currency is now rejected with 400, because the subscription renews at the price's amount and RevKeen does not convert between currencies. Leave currency out, or send the price's own.
  • The published OpenAPI no longer shows USD as a default for this field.

Omitted currency uses your default currency (behaviour change)

  • A /v2 request that leaves out currency now uses your default currency, the one you choose in Settings → Regional. It previously used USD.
  • This covers creating checkout sessions, payment intents and products, ad-hoc price_data on payment links, and the external product sync endpoints. The published OpenAPI no longer shows USD as a default for these fields.
  • Sending currency explicitly is unchanged, and is still the clearest way to be certain which currency a record gets. On payment links, the link's currency comes from its products; the top-level currency field is not used.

Canva (beta)

  • Connect your own Canva account from Apps → Marketplace to edit a design in Canva and import it as an image. You pay Canva directly for any subscription. See Product images and shared media.

September 2026 documentation update

Reviewed on 5 September: the guides now distinguish hosted checkout V13 from hosted invoice V6, document approved-origin checkout embedding, correct Cart SDK calls and usage deduplication behavior, and explain customer-scoped portal sessions. Start with checkout integration, usage integration, and portal integration.

Client releases have their own availability. Consult the release matrix before adopting candidate CLI or regenerated SDK methods. This documentation update does not declare an unpublished package or a beta integration generally available.

August 2026

Canonical API error contract (breaking for error-code branching)

  • 403 responses now carry type: authorization_error. They were previously typed authentication_error, so 401 and 403 can finally be told apart from the body alone.
  • Error codes are lower-snake-case throughout. IP_NOT_ALLOWED is now ip_not_allowed; the full 401 and 403 vocabularies are listed on Errors.
  • Every 401 now returns a WWW-Authenticate: Bearer realm="revkeen-api" challenge header.
  • Every 429 now returns a deterministic Retry-After in whole seconds, and X-RateLimit-Reset is a UNIX timestamp in seconds (it previously emitted milliseconds, contradicting the documented contract).
  • 403 scope denials no longer echo the granted scopes of the presented key.
  • The unkey_key_id field is removed from Cart API key status responses. id is the stable public identifier for a Cart key.

Checkout V13 multi-rail hosted checkout

  • Hosted checkout collects card, Direct Debit, and wallets (Apple Pay / Google Pay) when those rails are enabled for the merchant.
  • Invoice payers land on the hosted invoice page at /i/{token} instead of hopping to a generic checkout link.
  • The public embed bundle at https://releases.revkeen.com/embed/v1/checkout.js mounts Direct Debit capture and a cart drawer on merchant sites. Hosted checkout can also be mounted in an approved-origin iframe; see the embed guide for callback limitations.

Direct Debit day-2

  • Mandate request, Active-status gate, advance notice, collections, and indemnity handling are documented in the Direct Debit section, including emails and the customer, invoice, and checkout starting points.
  • Customer portal can list mandates, cancel, and run change-of-bank with OTP.

Apps Marketplace

  • Integrations install from Apps → Marketplace, not Settings.
  • Slack, Linear, HubSpot, PracticeHub, Quaderno, Terminal, Messaging, Cart, and Customer Intelligence are in the catalog. Xero and QuickBooks Online remain in development and are not installable.

Official SDK release channels

  • Current availability and source locations are on Official SDKs.
  • TypeScript: npm install @revkeen/sdk (npm · GitHub).
  • Go: canonical module github.com/revkeen/sdk-go; reviewed public tag pending (GitHub).
  • PHP: generated source is on GitHub; supported package channel coming soon.
  • There is no Python SDK.

July 2026

Direct Debit mandate journey

  • Hosted Bacs mandate requests with London & Zurich bureau submission.
  • Statuses: Awaiting setup, Submitted, Active, Failed, Suspended, Cancelled.
  • Do not collect until the mandate is Active.

Usage meters in the dashboard

  • Merchants manage meters under Products → Meters.
  • Customer-facing balances use GET /v2/usage/balance. A dedicated usage-analytics dashboard is not live.

June 2026

API keys — full key lifecycle

  • Scope enforcement — keys are scoped and scopes are enforced on every request; a read-only key can never move money.
  • IP allowlists — restrict a key to specific IPs/CIDR ranges; off-allowlist requests return 403 IP_NOT_ALLOWED.
  • Zero-downtime rolling — rotate a key with an overlap window (default 24h, up to 168h) so you can cut dependents over with no downtime.
  • Last-used + inventory — see when each key was last used and which keys have gone stale (90+ days).
  • Audit trail — every key event (created / rolled / revoked) is recorded with actor and timestamp.
  • Immediate, durable revocation — revoked keys stop authenticating right away and stay blocked through restarts.
  • See Authentication → Key lifecycle & security.

Linear and HubSpot via Nango

  • Merchants connect Linear (workflow issue create) and HubSpot (read-only CRM context) through Nango OAuth from the Apps Marketplace.

March 2026

AI Copilot — Proactive Intelligence & Processing-Cost Tools

  • MCP customer-v1 tools available as a governed, read-only billing surface
  • Proactive alerts for processing-cost changes, churn risk, and dunning opportunities
  • Wording updated 27 Sep 2026. Processing-cost figures cover recorded Direct Debit collection costs only; card processing fees are not recorded.
  • Natural language queries across invoices, subscriptions, and revenue data
  • Full-page chat interface in dashboard with visual output

Marketing Site Rework

  • 5 new product pages: Payments, Billing, Intelligence, Platform, Future
  • Interactive savings calculator on homepage and pricing page
  • PostHog page view and CTA tracking across all pages

Search & Indexing

  • Full-text search indexing for customers, invoices, and products
  • Background indexing via cron-worker with BullMQ queue

February 2026

Customer Health Scores

  • AI-powered health scoring (0–100) for every customer
  • Factors: payment history, engagement, revenue trend, dispute rate
  • Health score column added to customer list and detail views

January 2026

Usage-Based Billing

  • Meter creation and usage event ingestion API
  • Support for sum, count, max, and unique aggregation types
  • Usage-based line items on invoices with configurable billing periods

Terminal Payments — PAX A920

  • Full POS connector architecture: Cloud ↔ Tauri Connector ↔ PAX Terminal
  • Device registration, pairing, and heartbeat monitoring
  • In-person sale, refund, and void operations via dashboard and API
  • Real-time payment status via SSE

December 2025

Platform Launch

  • Engine-API on AWS ECS Fargate (Frankfurt)
  • PostgreSQL 18 on RDS with row-level security
  • Dashboard and Checkout on Vercel (global edge)
  • Cron-worker and background services on Hetzner

Core Billing Engine

  • Products with one-time, recurring, and usage-based pricing
  • Subscription lifecycle: trials, grace periods, proration, cancellation
  • Invoice pipeline: draft → open → finalized → paid
  • AI-powered dunning with configurable retry schedules

Payment Processing

  • NMI gateway integration with gateway-agnostic adapter layer
  • Card-on-file and merchant-initiated transaction compliance
  • Unified transaction model: sale, refund, void, capture, dispute
  • Pay by Bank / open banking collection is not a live merchant checkout rail. Do not treat the December 2025 launch note as a current product claim.

Developer Tools

  • REST API under /v2/*
  • Generated TypeScript, Go, and PHP SDK source; see current SDK availability
  • Webhook event types with signature verification
  • Interactive API playground powered by fumadocs-openapi
  • MCP server for AI agent billing automation

Integrations

  • PracticeHub (patients, packages, appointments sync)
  • Slack notifications
  • Quaderno tax automation
  • Xero and QuickBooks Online accounting sync was announced at launch and remains in development. It is not installable from the Apps Marketplace.

Owner: david · Reviewed 30 Sep 2026 · Next review 30 Oct 2026

On this page

October 2026Usage events: a reused idempotency key with a different payload is refused (behaviour change)Send a copy of a Direct Debit advance notice from the dashboardprorationBehavior: invoice_immediately is deprecated on the plan-change operations; new opt-in API version 2026-11-02POST /v2/subscriptions starts the trial its price asks for (behaviour change)GET /v2/customers/{id}/state needs three scopes and says when a list is cut short (breaking)Webhook events mandate.created and mandate.auddis_rejected are removed (deprecated)GET /v2/usage/balance no longer returns cost and margin figures (breaking)Customer create and update take snake_case fields (behaviour change)Checkout session create takes snake_case fields; three path parameters are renamed (behaviour change)checkout.session.completed and checkout.session.expired webhooks are now sentPayment links on /v2 return one consistent shape, with a hosted url (behaviour change)Change a subscription's plan through the API, with a proration previewCheckout sessions through the API are created for an invoice, and the URL can be read back (behaviour change)Pause and resume a subscription through the APICollect an invoice by Direct Debit through the APIRecord a payment received outside RevKeen through the API (behaviour change)Detach a payment method and set the default customer payment method through the APIPOST /v2/subscriptions refuses fields it never used (breaking)September 2026Product collectionsRevKeen Commerce add-onSanity Cart integration removedRevKeen CLI v0.2.1 and v0.3.0Subscriptions created through the API now bill their first period (behaviour change)Installing and uninstalling apps now needs an Owner, Admin or Developer role (behaviour change)Create a Direct Debit subscription through the APIPOST /v2/subscriptions now keeps paymentMethodId, quantity and productId (behaviour change)Payment-link create now applies every documented field (behaviour change)metadata.created_via is reserved on payment linksChanging a payment link's state now needs payment_links:writeNo available payment method now returns 503 instead of 500Retired: order create, order pay and tax-rate endpointsA new subscription takes its price's currency (behaviour change)Omitted currency uses your default currency (behaviour change)Canva (beta)September 2026 documentation updateAugust 2026Canonical API error contract (breaking for error-code branching)Checkout V13 multi-rail hosted checkoutDirect Debit day-2Apps MarketplaceOfficial SDK release channelsJuly 2026Direct Debit mandate journeyUsage meters in the dashboardJune 2026API keys — full key lifecycleLinear and HubSpot via NangoMarch 2026AI Copilot — Proactive Intelligence & Processing-Cost ToolsMarketing Site ReworkSearch & IndexingFebruary 2026Customer Health ScoresJanuary 2026Usage-Based BillingTerminal Payments — PAX A920December 2025Platform LaunchCore Billing EnginePayment ProcessingDeveloper ToolsIntegrations