Skip to main content
A policy’s money comes in three parts: its pricing (fullTermPricingInfo), its billing (fullTermBillingInfo) and its active invoices. Each part builds on the one before it, so a policy, and a saved quote, sits at one layer of a pricing stack. A saved quote states the layer its bind should leave the policy at, and a change without a saved quote names any move it makes between layers; the platform checks both. This page applies to companies that invoice: policy invoicing turned on, and a Quote billing calculation other than NO_BILLING(). At any other company the pricing stack endpoints and layerChange return 403 finv2-policy-invoicing-disabled, and nothing here is checked.

The four layers

A layer is read from four facts, the stack state:
  • whether fullTermPricingInfo is stated (a zero total counts);
  • whether fullTermBillingInfo is stated (one with no lines counts);
  • how many of the policy’s invoices are active, that is, neither voided nor deleted;
  • whether the billing owes nothing: every line is 0, or there are no lines.
Billing that owes nothing needs no invoices, so a zero bill with no invoices sits at both billing and invoicing. No layer accepts billing without pricing, or active invoices without billing, so a change that would leave a policy in either state fails its layer check.

The intended layer

A saved quote’s intended layer is the layer its bind is meant to leave the policy at. Choose it with Set Quote Intended Layer:
PUT /api/v1/companies/{companyId}/quotes/{quoteId}/intended-layer
Get Quote Intended Layer reads it, and the app’s Billing step chooses the same value with its Intended layer card, so either side of a quote can set it. It is stored on the quote apart from its fields: the entity endpoints neither return nor take it, and it is never copied, so every quote starts with none, including one saved from a generated draft, copied in the app or created for a renewal. Choosing a layer changes nothing else on the quote; you make its pricing, billing and invoices match. Three requests check it, all with the same rule: the bind must leave the policy at the intended layer. A quote with no intended layer can be neither bound nor completed: 422 finv2-quote-intended-layer-required. A bind that would leave the policy at another layer returns 422 finv2-quote-intended-layer-mismatch, and nothing is saved. The message names the intended layer, the layer the bind would reach, the first part that differs, checked in the order pricing, billing, invoices, and the request that fixes it, with your ids. Choosing the layer the bind would reach is the other way out. The check reads what the bind would write. Pricing and billing are the ones the bind prepares: the converted policy’s for new business and renewal; for an endorsement, the quote’s pricing or, when it states none, the policy’s; for a cancellation or reinstatement, the pricing the platform derives. The billing is always the quote’s own. Active invoices are counted after the plan the bind applies:
  • an endorsement, cancellation or reinstatement quote counts the policy’s active invoices, less the plan’s voids, plus its creates, so a bind of no invoices keeps them all;
  • a new business or renewal quote counts only the plan’s creates: a renewal never inherits the expiring term’s invoices.
A saved quote’s bind runs no other layer check, so an endorsement, cancellation or reinstatement quote can take a policy to any layer its data reaches, with one limit: it keeps the policy’s pricing, so on a policy with pricing it cannot bind at base. The message then says so, and points to the pricing layer or higher.

Doors

Which check a request gets depends on its door (Invoicing a policy): Every door runs the integrity checks as well.

Layer changes

A change to an existing term without a saved quote states its own pricing, billing and invoices, so the costly mistake is leaving something out: an endorsement that forgets fullTermBillingInfo would drop the policy’s billing. So such a change keeps the policy at its current layer, unless its request names the move in layerChange:
  • Without layerChange, the change passes when the policy ends at the layer it started at. Billing that owes nothing counts at both billing and invoicing.
  • With layerChange, the policy must sit at from before the change and at to after it.
  • layerChange only names the move; the request’s own data makes it. Nothing is written differently because of it.
These are the moves you will meet most: A plan that voids every active invoice and creates none leaves nothing to add up, so it needs no billing, which is why one change can take a policy from invoicing straight to pricing. A change keeps the policy’s pricing unless it restates it, and a cancellation or reinstatement derives its pricing, so no change takes a priced policy to base. A change that moves the policy without naming the move, or names a move it does not make, returns 422 finv2-policy-layer-change and saves nothing. The message names the move the change makes and, where the request can name it, the exact layerChange to send. Naming one layer as both from and to returns 400, as does a layerChange on a new term or on a saved quote’s bind.

The invoice batch

Update Policy Invoices changes a bound policy’s invoices and nothing else. It keeps the policy at its layer, so a plan that voids every active invoice, or gives a policy with none its first invoices, names the move: Those are the only two moves the batch can name, because it changes neither pricing nor billing; any other returns 422 finv2-policy-layer-change, pointing you to a policy transaction. An ordinary re-plan that keeps some invoices names none. The app’s Policy Financials page asks for the same confirmation in Configure billing before it saves such a plan.

Integrity checks

Three checks run at every door, whatever the layer:
  • The receivable check. Stated billing’s receivable lines add up to fullTermPricingInfo.total; otherwise 400 finv2-policy-billing-checksum.
  • Invoice conservation. The policy’s active invoices add up to its billing, line by line, to the cent (Invoice plans).
  • The invoice ledger. A void names the version of the invoice it read (409 finv2-invoice-head-conflict when it changed since), and an invoice with payments is never voided.
Conservation is arithmetic: no invoices add up to nothing. Whether a change may leave a policy with none is its layer’s question, answered by the intended layer or by continuity.

Clearing pricing

Two requests remove a quote’s pricing, for a quote whose intended layer is base:
  • Clear Quote Rating, DELETE …/quotes/{quoteId}/rating, clears everything the quote’s rating workflow owns, its pricing included. Use it for pricing a rating produced.
  • Update Entity with fullTermPricingInfo: null, PATCH …/entities/quote/{quoteId}, clears pricing a client sent rather than a rating.
Either save recalculates the quote’s billing, and billing conditions that need pricing hold it at null. Neither touches the quote’s invoice plan. A change quote keeps the policy’s pricing, so clearing its rating does not take it to base.

Examples

The policy in these examples belongs to a company that invoices, and its billing states one line, Premium on the Policy Invoice type. The names are this example company’s; use your company’s own.

1. Bind an endorsement that voids every invoice

The policy has two unpaid invoices: it sits at invoicing. An endorsement quote, saved and rated for its change, should also stop invoicing the policy.
  1. Read the policy’s invoices and note each active invoice’s id and headJournalId: GET /api/v1/companies/{companyId}/financials/invoices?linkedPolicy={policyId}.
  2. Attach a plan that voids both and creates none:
    PUT /api/v1/companies/{companyId}/quotes/{quoteId}/invoicing/plan
  3. Choose the layer the bind should leave the policy at:
    PUT /api/v1/companies/{companyId}/quotes/{quoteId}/intended-layer
  4. Optionally, check the bind: GET /api/v1/companies/{companyId}/quotes/{quoteId}/bind-conditions?invoices=saved answers "readyToBind": true.
  5. Bind the plan:
    POST /api/v1/companies/{companyId}/quotes/{quoteId}/bind
Outcome: the policy has the endorsement’s pricing and billing and no active invoices: the billing layer. Had the intended layer been invoicing, the bind would have returned 422 finv2-quote-intended-layer-mismatch, saying the policy would have no active invoices while its billing owes an amount. This works only while neither invoice has a payment; a paid invoice cannot be voided. A saved endorsement must change something on the policy: a plan alone is not a change, so to void every invoice without one, use the invoice batch (example 3).

2. Add billing with an endorsement by value

The policy is priced at 1,200.00 and has no billing: it sits at pricing. The endorsement states its first billing, so it names the move.
POST /api/v1/companies/{companyId}/policies/{policyId}/transaction/endorse
Outcome: the policy is at billing: pricing and billing, and no invoices yet. Without layerChange, the endorsement returns 422 finv2-policy-layer-change:
Bind by value names it the same way, beside its data.

3. Void every invoice with the batch

The policy has two unpaid invoices, and its insured will pay outside the platform.
POST /api/v1/companies/{companyId}/financials/policies/{policyId}/invoices/batch
Outcome: both invoices are voided and the policy is at billing; its pricing and billing do not change. Without layerChange, the batch returns 422 finv2-policy-layer-change:
To invoice the policy again later, send a batch that creates its invoices with "layerChange": { "from": "billing", "to": "invoicing" }.

Refusals

Quote invoicing covers a quote’s invoice settings and plan, and Invoice plans every refusal of a plan.