> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.solvimon.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.solvimon.com/_mcp/server.

## Summary

A wallet denominated in a currency now pays for the invoice. Solvimon deducts the money from the taxable base of the lines the wallet covers, so no amount is taxed twice. You can now require approval before a pricing plan schedule becomes active. A coupon can now continue on the next schedule of a subscription. You can now backdate a discount to billing periods whose invoices are still draft. Solvimon now bills AvaTax partial exemptions as partial. You can now manage pricing plan groups in Desk. The customer portal is now available in German and Italian. Solvimon now disables a webhook after 20 consecutive failed deliveries. Desk now shows workflow executions on the customer and the invoice they ran for.

## Pricing

**Activating a pricing plan schedule can require approval**
An [approval policy](/platform-guides/customers-and-billing/quoting/approval-policy) now accepts `PRICING_PLAN_SCHEDULE` as its source resource type. When such a policy applies, [POST /v1/pricing-plan-schedules/\{id}/activate](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-schedules/post-pricing-plan-schedules-by-resource-id-activate) does not activate the schedule. It creates an approval request, sets the schedule's `approval_status` to `PENDING_REVIEW`, and returns the schedule in `DRAFT`. The schedule becomes active when an approver approves the request. A user who prepares a change can therefore ask for its release without the permission to release it.

Approval uses the same endpoints as quotes and invoices: [POST /v1/approval-requests/\{id}/approve](https://docs.solvimon.com/api-docs/configuration-api/approval-request/post-approval-requests-by-resource-id-approve), [POST /v1/approval-requests/\{id}/decline](https://docs.solvimon.com/api-docs/configuration-api/approval-request/post-approval-requests-by-resource-id-decline), and [POST /v1/approval-requests/\{id}/cancel](https://docs.solvimon.com/api-docs/configuration-api/approval-request/post-approval-requests-by-resource-id-cancel). The same approver models apply: by group or ranked. A renegotiation usually changes more than one schedule. The three actions are therefore also available in bulk: [POST /v1/approval-requests/approve](https://docs.solvimon.com/api-docs/configuration-api/approval-request/post-approval-requests-approve), [POST /v1/approval-requests/decline](https://docs.solvimon.com/api-docs/configuration-api/approval-request/post-approval-requests-decline), and [POST /v1/approval-requests/cancel](https://docs.solvimon.com/api-docs/configuration-api/approval-request/post-approval-requests-cancel).

**`Approve every schedule of a change in one request`**

```bash Approve every schedule of a change in one request
curl -X POST https://test.api.solvimon.com/v1/approval-requests/approve \
  -H "X-API-KEY: <apiKey>" \
  -H "Content-Type: application/json" \
  -d '{
    "resource_ids": ["appr_jwDeeN0tYSY3F7BkeN1v", "appr_QwDeeN0vcYJaBLAc0C29"]
  }'
```

Solvimon acts on each request separately. The response contains one result for each resource id. Each result has a `status` of `SUCCEEDED` or `FAILED`. A failed result also contains the error that stopped it. One failed request does not roll back the others.

To find the schedules that wait for review, read the subscription with [GET /v1/pricing-plan-subscriptions/\{id}](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-subscriptions/get-pricing-plan-subscriptions-by-resource-id). `pending_review_pricing_plan_schedule_ids` lists the schedules of the subscription that are pending review, in `start_at` order. `pricing_plan_schedule_infos` is unchanged: it lists only the active schedules. [GET /v1/approval-requests](https://docs.solvimon.com/api-docs/configuration-api/approval-request/get-approval-requests) now accepts `source_ids[]` for several sources in one request, in addition to `source_id`. Solvimon rejects a request that sends both.

A platform can have one active approval policy for each source type. These policies contain a single always-approve rule, and a second policy would repeat it. Solvimon also approves schedules in timeline order. You cannot activate a schedule while the schedule before it is still draft or pending review. See [Requiring approval to activate](/platform-guides/customers-and-billing/subscriptions/draft-schedules#requiring-approval-to-activate).

**A coupon can carry over to the next schedule**
You redeem a coupon against a pricing plan schedule, so its discounts belong to that schedule. [POST /v1/pricing-plan-schedules/\{id}/migrate](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-schedules/post-pricing-plan-schedules-by-resource-id-migrate) and [POST /v1/pricing-plan-schedules/\{id}/copy](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-schedules/post-pricing-plan-schedules-by-resource-id-copy) now accept `coupon_discount_behaviour`. This field sets what happens to the coupons that are still active when you replace the schedule:

**`Continue the active coupons on the new schedule`**

```json Continue the active coupons on the new schedule
{
  "pricing_plan_version_id": "ppve_QwDeeN0vcYJaBLAc0C29",
  "start_at": "2026-10-01T00:00:00+02:00",
  "coupon_discount_behaviour": "CARRY_OVER"
}
```

`NONE` is the default. The discounts end with their schedule, as before. `CARRY_OVER` continues them on the new schedule for the remaining time of the coupon. Solvimon calculates the end date from the original start of the coupon. A three-month coupon that has run for two months therefore continues for one month on the new schedule. Solvimon does not redeem the coupon a second time. See [Coupons across schedule changes](/platform-guides/products-and-pricing/product-catalog/coupons#coupons-across-schedule-changes).

**A discount can be backdated while its invoices are still draft**
A [discount](/platform-guides/customers-and-billing/subscriptions/schedule-configurations#discounts) can now start in any billing period whose invoice is not issued. The lock on billed periods now follows the last `FINAL` invoice. An invoice that is still `DRAFT`, for example on hold and not sent, therefore leaves its period open. You can add an ad hoc discount that you agreed on before the invoice goes out. A period with a `FINAL` invoice stays closed. The same rule applies when you remove a discount clause that has already started. See [Invoice lifecycle](/platform-guides/invoicing/invoices/invoice-lifecycle).

**An on-demand charge started from a payment carries its quantity**
When you [charge an on-demand item](/platform-guides/products-and-pricing/pricing-plans/on-demand-charges) through [POST /v1/payments/authorize](https://docs.solvimon.com/api-docs/transaction-api/payments/post-payments-authorize), you now state the quantity and the amount in the payment context. Each item accepts the same two optional fields as the direct request: `units` and `flexible_amount`. The flow can therefore charge a [one-off](/platform-guides/products-and-pricing/pricing-plans/one-off-pricing) item priced `FLAT` for the units ordered, and a [flexible](/platform-guides/products-and-pricing/pricing-plans/flexible-pricing) item for the agreed amount. `FIXED` items work as before.

**`Pricing items on the payment context`**

```json Pricing items on the payment context
{
  "pricing_items": [
    { "pricing_item_id": "prii_5RmXe2QbtKfYuA9DcNH3P", "units": { "number": "2" } },
    { "pricing_item_id": "prii_2PnBx7VdtRgLmE4WcQJ8K", "flexible_amount": { "quantity": "50.00", "currency": "EUR" } }
  ]
}
```

Solvimon validates both fields when you create the payment context. An incorrect quantity therefore returns an error to the caller before the customer pays. Solvimon still reads payment contexts stored in the earlier shape.

## Wallets and credits

**A wallet denominated in a currency pays for the invoice**
A `CREDIT` [wallet type](/platform-guides/wallets-credits/credit-types-wallets#wallet-types) funded with an amount holds money, not credits. Such a wallet now pays for the invoice lines it is allowed to cover. Solvimon invoices the customer for the remainder.

The wallet holds a net amount, because Solvimon already charged tax on the [top-up](/platform-guides/wallets-credits/wallet-top-ups) that funded it. Solvimon therefore deducts the money from the net amount of the line, and the covered part has no tax. Solvimon charges and taxes the remainder of the line as usual. For example, a 30.00 EUR line at 21% VAT against a 10.00 EUR balance invoices 20.00 EUR plus 4.20 EUR VAT:

|                         | Net    | VAT  | Total  |
| ----------------------- | ------ | ---- | ------ |
| Line as priced          | 30.00  | 6.30 | 36.30  |
| Covered from the wallet | -10.00 | 0.00 | -10.00 |
| Charged                 | 20.00  | 4.20 | 24.20  |

Solvimon always splits the coverage and never skips it. If the balance is less than the line, the wallet covers part of the line and Solvimon charges the remainder. Only lines whose product [tax category](/platform-guides/invoicing/tax#tax-categories) matches the tax category of the wallet type are in scope. Other lines do not change. Solvimon applies the deduction last: after included volume, credits, discounts, and minimum commitment, and before tax. The deduction applies to the net amount that remains. A customer with both types of wallet spends credits first, because credits reduce volume and the money wallet reduces the amount.

Each charge reports what each wallet paid in a new `wallet_balances` list. Each entry names the wallet and gives its figures:

**`What one wallet paid for a charge`**

```json What one wallet paid for a charge
"wallet_balances": [
  {
    "wallet_id": "wall_5RmXe2QbtKfYuA9DcNH3P",
    "used_balance": { "amount": { "quantity": "10.00", "currency": "EUR" } },
    "left_balance": { "amount": { "quantity": "0.00", "currency": "EUR" } },
    "available_balance": { "amount": { "quantity": "10.00", "currency": "EUR" } }
  }
]
```

The list has one entry for each wallet that paid. A charge that a credits wallet and a money wallet both paid therefore reports the figures of each wallet separately. `wallet_balances` replaces `wallet_balance_details`, which holds one wallet at a time and only credits. See "Deprecated API fields" below, and [An amount-denominated wallet pays for the invoice](/platform-guides/wallets-credits/credit-types-wallets#an-amount-denominated-wallet-pays-for-the-invoice).

A [grant](/platform-guides/wallets-credits/credits-in-pricing-plans) into such a wallet must be in the currency of the wallet. Solvimon rejects a fixed grant in a different currency with `wallet type <reference> is denominated in EUR, but the grant is in USD`. Solvimon also rejects a grant that takes a percentage of pricing in a different currency, because there is no conversion. The error tells you to use a fixed grant or a different wallet type. A wallet type created before the default currency became mandatory has no default currency. You cannot grant into it until you set one.

## Customers

**A live seat assignment protects the resources it references**
[Seat assignments](/platform-guides/customers-and-billing/customer/seat-assignments) record which child customer occupies which seat. Solvimon attributes per-seat credits against them. Solvimon now protects three resources while a live assignment references them: the child customer in the seat, the parent customer that holds the seat, and the per-seat product item that defines the seat type. For example, Solvimon rejects [POST /v1/customers/\{id}/archive](https://docs.solvimon.com/api-docs/configuration-api/customers/post-customers-by-resource-id-or-reference-archive) for a child customer who still holds a live seat. A seat therefore cannot stay occupied by a customer that is no longer operational. The error names the assignment that blocks the change, and its status. First end the assignment: set `end_at` with [PATCH /v1/seat-assignments/\{id}](https://docs.solvimon.com/api-docs/configuration-api/seat-assignments/patch-seat-assignments-by-resource-id). Then change the status. See [Seat-based credits](/platform-guides/wallets-credits/seat-based-credits).

### Fixes

bug-fix

* You can now remove a billing email. [PATCH /v1/customers/\{id}](https://docs.solvimon.com/api-docs/configuration-api/customers/patch-customers-by-resource-id-or-reference) with `{"email": null}` used to return `INVALID_FIELD`, although an empty string cleared the email. `null`, `""`, and whitespace now all mean no email.

## Invoices

**AvaTax partial exemptions are billed as partial**
Some jurisdictions tax part of a line and exempt the remainder. Software in Texas is a common example: 8.25% applies to 80% of the base, and the other 20% is exempt. Solvimon now stores the taxable fraction that AvaTax returns on the rate, and applies it. Solvimon calculates the rates on the taxable part of the base. The exempt remainder becomes a single 0% summary. The invoice and the tax filing therefore both show the split. The Texas example produces four tax lines: three on the 80% base, and one exempt line for the 20%. The invoice shows the exempt part once, not once per jurisdiction. A fully taxable or fully exempt line does not change. An invoice that is already issued keeps its tax. To apply the split to it, refresh it with [POST /v1/invoices/\{id}/refresh](https://docs.solvimon.com/api-docs/transaction-api/invoices/post-invoices-by-resource-id-refresh). See [Tax calculation and integrations](/platform-guides/invoicing/tax/tax-calculation-integrations).

### Fixes

bug-fix

* [Custom fields](/platform-guides/platform-configuration/custom-fields) now persist after an invoice refresh. A `CUSTOM_FIELD` refresh with [POST /v1/invoices/\{id}/refresh](https://docs.solvimon.com/api-docs/transaction-api/invoices/post-invoices-by-resource-id-refresh) used to update the "show on invoice" fields in the response and in the regenerated PDF. It did not write them to the invoice. The next `GET` returned the values from before the refresh.

## Workflows

**Filter and expand the resources a workflow ran against**
[POST /v1/workflow-action-executions/search](https://docs.solvimon.com/api-docs/transaction-api/workflow-action-executions/post-workflow-action-executions-search) now filters on `pricing_plan_subscription_id` and `wallet_id`. The existing invoice, customer, payment, action, workflow, trigger, and status filters still apply. [Workflow triggers](https://docs.solvimon.com/api-docs/transaction-api/workflow-triggers/get-workflow-triggers-by-resource-id) now [expand](/platform-guides/for-developers/expanding-responses) the resources they reference: `workflow_id` on a workflow trigger, `pricing_plan_subscription_id` and `pricing_plan_schedule_id` on a subscription trigger, `wallet_id` on a wallet trigger, and `payment_id` on a payment trigger. An execution row expands its `workflow_action_id`. You can therefore read the [execution log](/platform-guides/workflows/monitoring-and-audit) in one call, with the resources of each row inline.

**A condition on the billing entity of the invoice**
On invoice workflows, a [workflow condition](/platform-guides/workflows/workflow-triggers) can now test `invoice.billing_entity.id`. A platform that bills from several [billing entities](/platform-guides/platform-configuration/billing-entities) can give each entity its own automation. Before this, you had to run one workflow and filter afterwards.

**Workflow executions are shown where the work happened**
Desk now shows the execution table on the customer screen, on the invoice screen, and on the workflow. Each table lists the executions for that resource. To see what the automation did for an invoice, open the invoice. Select a row to open a panel with the details of that execution. The full log stays on its own page, "All workflow executions". See [Monitoring and audit](/platform-guides/workflows/monitoring-and-audit).

### Fixes

bug-fix

* An `EXPORT_TO_ERP` [action](/platform-guides/workflows/workflow-actions) now requires an integration. You could leave the field empty, and Desk saved an action that had no integration to export through.

## Integrations

**Solvimon disables a webhook that never succeeds**
Solvimon now disables a webhook automatically after 20 consecutive failed deliveries. `disabled_reason` on the [webhook](https://docs.solvimon.com/api-docs/configuration-api/webhooks/get-webhooks-by-resource-id) gives the reason, so you can tell a webhook that Solvimon disabled from one that you disabled. An endpoint that is permanently unavailable therefore leaves the delivery queue. Before this, Solvimon retried it without end, on a backoff of up to several hours. While a webhook is disabled this way, you cannot [send it a test event](https://docs.solvimon.com/api-docs/configuration-api/webhooks/post-webhooks-by-resource-id-send-test) or [resend its penalty box payload](https://docs.solvimon.com/api-docs/configuration-api/webhooks/post-webhooks-by-resource-id-send-penalty-box-payload). Reactivate the webhook with [PATCH /v1/webhooks/\{id}](https://docs.solvimon.com/api-docs/configuration-api/webhooks/patch-webhooks-by-resource-id) first. Reactivation also clears the reason. See [Webhooks](/platform-guides/for-developers/webhooks).

## Customer portal

**German and Italian**
The [customer portal](/platform-guides/customers-and-billing/customer-portal) and [hosted checkout](/platform-guides/customers-and-billing/hosted-checkout) are now available in German and Italian, in addition to English and Dutch. The language switcher is now a standard part of both. You do not have to enable it. The starting language is the selection the visitor made. Without a selection, it is the [locale](/platform-guides/for-developers/locale) on the customer record. Geolocation is the last fallback, because the location of the browser does not identify the customer. A regional variant falls back to its language: `de-AT` shows German and `nl-BE` shows Dutch.

**The pay-invoice page uses the checkout components**
Paying an invoice from the [customer portal](/platform-guides/customers-and-billing/customer-portal) and paying through the [hosted checkout](/platform-guides/customers-and-billing/hosted-checkout) now use the same components. A payment therefore behaves the same from both starting points. Solvimon now passes the invoice amount to the payment method options. The page therefore offers only the methods that can settle the currency of the invoice.

## Payments

**Restrict the payment methods an Adyen acceptor offers**
`allowed_payment_methods` on a [payment acceptor](https://docs.solvimon.com/api-docs/configuration-api/payment-acceptors/patch-payment-acceptors-by-resource-id) of type `PAYMENT_GATEWAY` on [Adyen](/integrations/paymentserviceproviders/adyen) limits the methods it offers to a set you select. For example, one [billing entity](/platform-guides/platform-configuration/billing-entities) can accept cards, and a second can accept cards and direct debit. Desk lists the methods enabled on the selected Adyen integration, for integrations that Solvimon owns. If you leave the field empty, the acceptor offers every method that the integration has enabled. See [Payment options](/platform-guides/platform-configuration/payment-options).

## Desk

**Manage pricing plan groups in Desk**
A [pricing plan group](/platform-guides/customers-and-billing/subscriptions/plan-changes) lets a subscription move between related plans. Plan groups are now a tab next to pricing plans. You can create and maintain a group in Desk, without the [pricing plan groups API](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-groups/post-pricing-plan-groups). You create a group with its name, its plans, and its portal settings. Drag the plans to order them, lowest tier first. That order is the upgrade path. Upgrades, downgrades, and cancellations each have their own timing: immediately, immediately with pro-rated fees, from the next billing period, or not allowed. A toggle sets whether customers can move between these plans themselves in the [self-serve portal](/platform-guides/customers-and-billing/self-serve-plan-changes). You deprecate and reactivate groups from the same context menu as the other catalog resources.

### Fixes

bug-fix

* Desk now creates a user with a [role](/platform-guides/platform-configuration/users-permissions/roles-permissions). The form used to allow a user without a role, and that user could not do anything. The form now preselects Read only.
* Clearing the end date of a [schedule](/platform-guides/customers-and-billing/subscriptions/subscription-schedules) now clears it. An absent `end_at` means "keep the end date of the source schedule", and only an explicit `null` means "no end date". Desk used to drop the key when you emptied the field. The schedule therefore kept the old end date, which was usually in the past.
* Extending an active schedule past a [draft schedule](/platform-guides/customers-and-billing/subscriptions/draft-schedules) that follows it no longer fails with `No adjacent schedule found but flag to adjust the NEXT schedule was passed`. The save used to ask to shift the next schedule without a check that this schedule was a draft.
* The customer screen now hides archived payment methods. The list shows only the methods you can charge.
* Revenue items on a pricing plan version now have even spacing. A gap used to appear between two of them.

## Deprecated API fields

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

* **`wallet_balance_details`** (pricing item summary price details): use `wallet_balances` instead. The block holds one wallet at a time. A charge paid by two wallets therefore reports only the figures of the wallet that paid last. The block can also express only credits.
* **`used_wallet_credits`**, **`left_wallet_credits`**, **`available_wallet_credits`** (pricing item summary wallet balance details): use the `used_balance`, `left_balance`, and `available_balance` of the matching entry in `wallet_balances` instead. These fields carry credits or an amount.