POLICY_CREATED → the contract exists, unpriced. POLICY_QUOTED → the risk has been priced.
POLICY_CONFIRMED → the terms are locked and the paperwork can be produced. POLICY_SIGNED → the
policyholder has committed. POLICY_STARTED → cover has begun, which on some products waits for the first
premium as well as the start date.
Statuses carry their entity prefix in every response, and assets and customers use ASSET_* and
CUSTOMER_*.
This page walks the whole journey. It assumes you have credentials and can call the API — see
Authentication — and that you have read
Read the product configuration, because which fields you must
send at each step comes from the product, not from this page.
The journey at a glance
One example run. The product’s own configuration decides parts of it — whether a payment method is needed before signature, which fields are required at which step, whether cover starts on signature — so read yours rather than assuming this shape.Step by step
1
Read the product configuration
tenant header. Every step after it needs one.Keep the response. Its six field lists tell you what to send in the next four steps, and its
payment, billing and signature sections tell you whether this product needs a payment method
before signature and how signing is delivered.If you are building a form on top of this, read
Should your form be config-driven?
first — the short version is that the config drives which fields you ask for and how they behave, while
labels, ordering and grouping are yours to write, because the config holds none of them.2
Initialize a customer, and with it a policy
One call creates the policyholder, the policy, and the branch you will work on. The body is optional —
send A branch is a working copy of the contract. New business happens on its own branch; mid-term
adjustments and renewals each get theirs. Reads and writes are branch-scoped, which is why querying
a policy without the right
{} for a direct sale, or name the distributing firm with brokerageFirmId:Response
branchId can look as though your data never landed.3
Fill in the customer
Custom fields go in Field keys are per-product — read them from the configuration rather than copying these. Note the birth
date: a
customFields; the customer’s aggregate fields (name, role, siret) are
top-level:DATE field wants 1985-04-12, and rejects a full ISO datetime.For a company product, expect the company block you read back to differ from what you sent. Supplying
the SIRET triggers a registry lookup that overwrites company name, address, postcode, city, activity
code and legal statuses, and nulls legal statuses the registry does not return. This is intended
behaviour, explained in
Fields the platform owns.
4
Create the insured items
startedAt is an aggregate field on most products — a top-level property, not a custom field:assetAggregateFields rather than assuming: if startedAt is declared there with
requiredFor: QUOTE, quoting fails without it. Use POST /assets/batch/create when a contract covers
many items.5
Set the contract-level terms
The policy’s aggregate fields — how often the customer is invoiced, and who pays — are top-level
properties of
PATCH /policies/{policyId}. Two different kinds of data live there, and they are not
collected at the same moment:invoicingConfigis a term you set. It is required before pricing, so it belongs in a call your code makes as it prepares the quote.- Policy custom fields are usually answers a person gives. They can be sent any time before the
action their
requiredFornames — often confirmation, not quote.
invoicingConfig straight from the product’s billing.defaultConfig — that is the shape it
expects, and there is nothing for you to invent:6
Price the risk
Two endpoints price a contract, and the difference matters:Add Pricing can fail on underwriting grounds rather than on your payload — an ineligible risk, a value
outside the carrier’s appetite. Those failures are recorded against the policy, so a rejected quote
is an outcome to handle, not necessarily a bug in your request.
POST /policies/{policyId}/calculate-quote computes a premium and persists nothing. Use it to
show a price, to compare options, or to try overrides — it accepts customFieldsToOverride,
brokerageFeesOverride, periodDurationOverride and assetIds for exactly that. It also tolerates
assets without a startedAt.POST /policies/{policyId}/quote computes the premium and writes it to the policy. This is the
call that moves the contract forward; confirmation works from the quote it stored.Both are covered in detail in Quotes.options is an array with one entry per asset, each naming the coverage the customer chose. The
permitted values come from the config’s quote object — quote.availableTiers,
quote.availableExcesses and quote.availablePerils. Not publicQuoteConfig, which is a smaller
summary carrying only productId, defaultTier and tiers:perils to an option to sell optional cover, where the product offers any. Check
quote.availablePerils and look at each peril’s options array first: a peril with a single permitted
option is not a choice, and sending another value is rejected with
INVALID_QUOTE_OPTIONS_INVALID_PERIL_OPTION.POST /policies/{policyId}/quote returns an empty body. It records the quote rather than handing it
back, so read the result afterwards — or use calculate-quote, which does return the full breakdown.Read it from the right place: the premium lands on the policy, but the chosen tier is on the asset
(GET /assets/{assetId} → quote.options.tier), because cover is chosen per insured item. See
Read a contract back.7
Confirm the contract
Confirmation locks the terms:Every field whose
requiredFor is CREATION, QUOTE or CONFIRMATION must be present, across the
customer, the policy and every asset. This is where an integration that treated aggregate fields as
custom fields — or never sent them at all — discovers the gap.8
Collect a payment method, if the product needs one first
Whether payment comes before signature is a product decision, and it is in the configuration. See
Payments for the mechanics, the Stripe hand-off, and the mandate.
9
Send it for signature
10
Watch it come into force
Activation is not a call you normally make. A signed contract comes into force when its start date
arrives and, on products that require it, when the first premium has been collected. Poll
GET /policies/{policyId} and read the status.A contract that is signed but not yet in force is the normal state for a future-dated start or an
uncollected first premium — not a failure. There is nothing to call: wait for the start date, or
collect the premium.Where integrations get stuck
- Fields rejected as “cannot be modified with this context”. You omitted
branchIdon a write. - A required field you believe you sent. Check which of the six configuration lists it came from.
Aggregate fields are top-level properties; custom fields go in
customFields. - Quoting refuses fields you treated as read-only. An
integrationKeydoes not mean the platform fills the field; only the registry family is filled for you. See Fields mapped onto an integration. PAYMENT_CUSTOMER_NOT_FOUNDwhen asking for a setup secret. The payment customer is created when the policy is quoted. Quote first.- The contract is two hours short.
startedAtneeds to be Paris-local midnight. - Confirmation rejected on a field the customer never sees.
invoicingConfigandbillingAssignmentare contract terms you set, not customer input. - A value you sent came back different. A field with an
integrationKeyis owned by its integration; company identity comes from the registry. - Nothing appears to have been saved. You are probably reading a different branch than you wrote.
- The contract is signed but not in force. Check the start date, then the first premium.

