Skip to navigation

Summary

A subscription can be paused and resumed. Billing stops for as long as the pause runs, and the subscription keeps its plan version, its pricing, its discounts and its payment method, so the customer comes back on the same contract instead of signing up again. Approval policies now behave the way they are configured: rules that silently never fired, or fired on every quote, were fixed, and a policy can be paused. A payment says what it was for, and a one-off invoice from a US billing entity no longer needs a tax percentage to be created.

Subscriptions

Pause a subscription, and resume it later POST /v1/pricing-plan-subscriptions/{id}/pause stops billing without ending the subscription. The pause starts NOW, at the NEXT_BILLING_PERIOD, AFTER_INITIAL_TERM or on a DATE, and ends on a date, after a period such as one month, at the next billing period, or not at all until someone resumes it. While the pause runs the subscription is PAUSED: no invoices, no fees, no minimum-commitment top-ups, and usage is not priced. Invoices raised before the pause are still collected.

The subscription keeps its id, its plan version, its negotiated pricing and its payment method, so resuming is not a new sign-up and starts no new initial term. A fee already paid in advance is credited from the pause date, and the resume raises a prorated invoice up to the next billing date; pass realign_billing_dates: true to move the billing date to the resume date instead. PATCH /pause changes the end of a scheduled or running pause, DELETE /pause removes one that has not started, and POST /resume ends it early. The calls need the new PRICING_PLAN_SUBSCRIPTION.PAUSE permission, and Desk offers all of them from the subscription menu, with a PAUSED filter on the subscription lists. See Pausing and resuming.

A scheduled cancellation has its own delete DELETE /v1/pricing-plan-subscriptions/{id}/cancel removes a cancellation that has not taken effect, where this meant sending cancel type UNDO. UNDO still works and is deprecated. The two are kept apart: deleting a cancellation never removes a pause, and deleting a pause never removes a cancellation.

Subscription changes send their own webhooks PRICING_PLAN_SUBSCRIPTION gained the events that until now had to be inferred by comparing status between data and previous_data: PAUSE_SCHEDULED, PAUSE_UPDATED, PAUSED, RESUMED, PAUSE_DELETED, CANCEL_SCHEDULED, CANCEL_DELETED, CANCELLED, UPGRADE_SCHEDULED and UPGRADE_DELETED. A request and the transition it leads to are separate events, so a cancellation scheduled for next quarter is reported when it is asked for and again when it takes effect. See Webhook event types.

Build a seat ramp in Desk The Seats panel edits a ramp of dated seat counts, for example ten seats now and twenty from 1 October, on a quote, a draft subscription and a live one. The API has accepted several dated seats_values per price for a while; Desk could only display them, so a committed seat increase had to be remembered and entered on the day. Each step is saved on its own with a Starting from date, bounded by the step before and the step after: no earlier than today or the day after the previous step, no later than the day before the next one or the end of the schedule, and never two steps on the same day. On a live subscription a step that has started is locked, and choosing today warns that the change cannot be edited afterwards. On a draft every step can still be changed, and Reset seats returns the schedule to a single value at the price’s default. The menu item is now Manage seats, and the separate add, edit and reset dialogs are gone.

Fixes

  • A subscription created directly as ACTIVE through POST /v1/pricing-plan-subscriptions/init schedules its auto-renewal, and its free-trial reminder. The subscription carried auto_renewal: true, a renewal term and an end date, but nothing renewed it when its last schedule ended.
  • Deleting a VOID subscription answers the ordinary “cannot delete a resource with status” validation error. It returned 500.

Quotes

Approval policies do what they are configured to do Several rule types were accepted on creation and then never fired, fired on every quote, or blocked the platform outright. A CUSTOM_FIELD rule with a comparator other than EQUALS is now refused when the policy is created, instead of being accepted and failing every quote finalization on the platform afterwards. CUSTOM_FIELD rules resolve the field on whatever resource it belongs to: customer, quote, quote version, quote subscription, pricing plan or product, where only customer fields were ever read, so “deal type is partner” or a CRM field on the quote could not trigger anything. BILLING_PERIOD and DUE_DATE with is_custom compare against the same resolved default that quote creation uses, so an untouched quote no longer counts as customised. A rule group can hold two DISCOUNT or two COMMITMENT rules on the same source when they form a range, so “more than 10% and at most 25%” is expressible; yes/no rules stay one per group. An inactive or uninvited user is refused as an approver, PRICING has_override no longer asks for a meaningless comparator, and a policy created with approval_type: LEVEL is returned as LEVEL. See Approval policies.

An approval policy can be paused POST /v1/approval-policies/{id}/pause suspends a policy without retiring it, and activating it brings it back. DEPRECATED was the only way to stop a policy and is terminal, so a policy taken out of service for a quarter had to be rebuilt from scratch. A PAUSED policy can still be deprecated.

An approval request that nobody could approve is refused up front A requester cannot approve their own request. When the requester was also the only eligible approver on the policy, the request was created and then sat PENDING_REVIEW for ever. Finalizing a quote or an invoice, or activating a schedule, now answers 400 on approvers, naming the policy and saying to add another approver.

Decline a signature request POST /v1/signature-requests/{id}/decline records that the customer refuses to sign, and the signature request moves to the new DECLINED status, next to IN_PROGRESS, COMPLETED and VOID. A refusal to sign had no status of its own, so it was indistinguishable from a request still waiting. This is the customer declining to sign; a quote version’s own DECLINED status, which means an internal approver rejected the quote, is unrelated.

Fixes

  • A signer picked from the customer’s contacts reaches the quote PDF with their name and email. expand[]=recipients.contact.contact_id returned the contact unexpanded, so the Signing section showed a bare “Signature” label and the e-signature provider could not place its tab.
  • Attachments added while a quote was in draft appear once the quote is finalised, without refreshing the page.

Invoices

A one-off invoice for a US billing entity no longer needs a tax percentage sales_tax_percentage falls back to 0 when a US billing entity has no tax calculation integration, instead of rejecting the call as “mandatory for US to US billing” or failing later in a tax engine that holds no US rates. With a tax integration such as AvaTax on the billing entity, the provider determines the rate and the field stays empty. An explicit percentage still wins over both. The field is also editable now: PATCH /v1/invoices/{id} accepts it on an OPEN or DRAFT one-off invoice and recalculates the tax on every line, where the call answered 200 and dropped the value. Send null to clear it and hand the invoice back to the integration.

Fixes

  • Creating an invoice preview for a subscription that has no schedules answers a validation error rather than 500.
  • A preview with a pricing_currency customization no longer leaves that currency behind on the subscription it previewed, where a later read of the same subscription could report the preview’s currency.
  • Adding a one-off line without a period answers a validation error naming the field. It returned 500.

Payments

A payment says what it was for GET /v1/payments returns the stored context for every kind of payment, not only some of them. A schedule change, a payment request and the verification charge that creates a payment method each report their own context object, and a context_types[] query parameter filters the list on one or more of them. Desk uses it: the payments list and panel name what each payment was for, with the resource it belongs to, so payments raised outside an invoice stop showing an empty Invoice column and “Unknown customer”. The list also shows the payment’s own reference, the provider’s reference, the refunded amount and whether a dunning retry is scheduled.

Customer portal

The self-serve plan change has its screens The portal exposed the plan change endpoint last release; now there is somewhere for the customer to use it. The subscription card offers the change when the subscription’s plan sits in an ACTIVE pricing plan group with somewhere to move to. The options come from the group, in the group’s own order, with any transition it marks NOT_ALLOWED left out, and each option says when the move takes effect, because the group’s timing policy decides that and not the screen. A subscription that belongs to no group renders exactly as before. See Self-serve plan changes.

Shipping addresses in the portal A customer can see, add, edit and remove their shipping addresses from the customer overview. The block lists the active addresses with the default first, and a Manage dialog holds the full list and the form, which takes the same fields as the checkout. It is off unless the host turns it on, so a merchant that ships nothing neither sees the block nor downloads its code.

French in the billing portal The portal is available in French, alongside the languages it already supported.

Fixes

  • An expired card is no longer offered when ordering an on-demand item, topping up a wallet, setting up an automatic top-up or managing a subscription. Such a card stays ACTIVE in the API, so it was offered and could even be preselected, only for the charge to be declined. It is still listed on the payment methods screen so the customer can replace it, and managing a subscription whose card has expired now says so and asks for a new one.
  • Tab moves through the fields of a dialog instead of jumping back to its close button.

Workflows

Be told when a workflow action fails A workflow takes notification_preferences.failure_notification_email. When an action execution fails, Solvimon emails that address with the workflow, the action, when it failed, the reason and a link to the execution. Failures are collected for ten minutes before the mail goes out, so one incident produces one email rather than a hundred. The address is set per workflow, so the team that owns a dunning workflow does not have to read about an ERP export. Set it to null to switch the notifications off.

Integrations

Belgian domestic B2B e-invoicing Belgium’s B2B mandate is supported as BE_B2B_PEPPOL: a structured invoice over Peppol in BIS 3 format, sent for every domestic B2B invoice a Belgian billing entity issues, as the law has required since 1 January 2026. Unlike the existing mandates, this one runs on Solvimon’s own connection to the network, so there is no provider account to open and no credentials to configure: pick the mandate in Desk, assign the Belgian billing entities that issue under it, and Solvimon sends. The e-invoicing workflows that come with the mandate are locked, and the invoice shows the mandate it was submitted for and the reason when the network refuses it. See E-invoicing.

Fixes

  • An AvaTax company code containing spaces is accepted.
  • The Rillet integration card carries the current brand mark.

Desk

Sign up for a sandbox with Google Creating a sandbox platform offers “Continue with Google” next to the email route. The sandbox is created with Google sign-in already configured for the domain of the account that created it, so the first user signs in with Google instead of setting a password from an invite mail.

Fixes

  • Creating a checkout page with calendar-aligned billing works. The form sent a field that is only valid for exact billing, and the call was refused.
  • Switching a tiered price to flat clears the tier bands it leaves behind.
  • The Uploaded column in the files overview shows the time as well as the date, so files uploaded on the same day can be told apart and read in order.
  • A coupon applied both directly and through its promotion code is refused with a message that describes that overlap, instead of claiming the customer had already redeemed it. An invoice preview with a coupon that discounts a line to nothing no longer fails.

AI and MCP

Buttons on a card act straight away A button on a card an AI client renders performs its action directly, instead of putting a sentence in the chat for the model to act on.

Cards for pricing plans and products A pricing plan has a card of its own, with switches for currency, billing period and plan version, so comparing what a plan costs per currency no longer takes a new question each time. A product card carries a popover explaining what the product is used for.

For developers

Several examples per endpoint in the API reference An endpoint can carry more than one request and response example, where a single example had to stand for every way of calling it. Pricing, pricing groups, pricing plan schedules, meter value calculations and ingest use it first, so the reference shows what a flat, a tiered and a usage-based setup each look like rather than one shape the reader has to generalise from. This matters most to an agent reading the specification as its only documentation.

Deprecated API fields

The following fields and values are now deprecated. They continue to work for backwards compatibility. Migrate to the replacements.

  • UNDO (pricing plan subscription cancel type): use DELETE /v1/pricing-plan-subscriptions/{id}/cancel.
  • INVOICE (payment context type): use PAY_INVOICE, whose pay_invoice.invoice_id names the invoice. Payments created before this release keep returning INVOICE without a body; their invoice is on the payment’s own invoice_id.
  • context.invoice_id (payment context): use context.pay_invoice.invoice_id.