curl --request POST \
--url https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/generate \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"policyId": "550e8400-e29b-41d4-a716-446655440000",
"effectiveDate": "2026-06-01",
"transactionType": "ENDORSE"
}
'{
"data": {
"quoteType": "endorsement",
"quoteNumber": null,
"quoteStatus": "inProgress",
"policyType": "GL",
"effectiveDate": "2026-06-01",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Acme Co"
},
"primaryInsuredName": "Acme Co",
"description": null,
"fullTermBillingInfo": null,
"referencingPolicy": null,
"endorsementEffectiveDate": null
},
"sourcePolicy": {
"policyId": "550e8400-e29b-41d4-a716-446655440000",
"policyVersion": 4
},
"effectiveWindow": {
"startDate": "2026-01-01",
"endDate": "2026-12-31"
},
"validationIssues": []
}Generate Quote from Policy (Stateless)
Returns the editable Quote data a transaction on an existing policy would start from — without persisting anything. No quote is stored, no quote number or id is allocated, no relationship is created, no audit row is written, and no token, draft session or retry receipt is minted. Generation is a pure read.
Use it to build your own transaction UI: generate, let your user edit the
returned data, then either bind it by value with
Bind Quote by Reference or by Value,
or save it as a quote and bind that quote, as described below. Bound by
value, everything the server needs travels in the request, so there is no
state to keep between the two calls.
Changing a bound policy through a saved quote. An endorsement, cancellation or reinstatement can go through a quote of its own, as in the app, so that its bind replaces the policy’s invoices the way the quote’s invoicing says (Quote invoicing):
- Generate the change’s draft here. Nothing is saved.
- Save it with Create Entity
(
POST …/entities/quote): send the draft’s wholedatawith your edits applied (for an endorsement, change only the fields that change and keep the rest as generated), and set two fields the draft leavesnullunless your Conversion Rules write them:referencingPolicy, the policy’s id, and the change’s date inendorsementEffectiveDate,cancellationEffectiveDateorreinstatementDate. Use theeffectiveDateyou generated with, written the way the quote writespolicyStartDate, for example{"date": "2026-12-15", "timezone": "America/New_York"}. An endorsement generated with anendDatealso setsendorsementEndDate; without it the endorsement runs topolicyEndDate. - For an endorsement, rate the quote with
Rate Saved Quote by Id,
which returns the rating without saving it on the quote (a rating that
fails is still a
200, withdiagnosticsand nodata), and save the rating outputs from itsdatawith Update Entity. Don’t rate a cancellation or reinstatement (it returns400): its draft already has the pricing the platform derives. - Bind it with Bind Quote
and
{"invoices": "generate"}, or prepare its plan with the quote invoicing endpoints and bind with{"invoices": "saved"}.
Saving a change quote without referencingPolicy is refused. Without its
change date it saves, but
Generate Quote Invoices
and Attach Quote Invoice Plan
refuse it with 400 finv2-invalid-quote-transaction-metadata, and its bind
returns 400.
validationIssues reports neither field, because a bind by value takes
the policy and the date from its own request.
What produces the data. Your company’s configured Conversion Rules for
(POLICY_TO_QUOTE, the requested transactionType) are evaluated
server-side against a single resolved segment of the source policy. Each rule
writes one destination field on the Quote. The rules are part of your
field-model configuration — what carries between a policy and a quote is
authored and reviewable, not inferred.
The data is the finished draft. It has every field your Quote
configuration declares, with every calculated field worked out as a save
would, fullTermBillingInfo included (null while policy invoicing is
disabled). A field nothing fills is null. A value that needs a saved quote,
such as a generated quote number, is null until the quote is saved.
Nothing is saved. quoteType is set from transactionType — ENDORSE
gives endorsement, RENEW gives renewal, CANCEL gives
cancellation and REINSTATE gives reinstatement — whatever your rules
write, so calculated fields that read it are worked out for that
transaction. A field you must supply that the draft lacks is reported in
validationIssues and comes back null. If a value fails its field’s type
check, the calculated fields are not worked out and the finding names the
field.
Which segment of the policy is read, per transaction type — always against the policy’s latest committed version:
transactionType | Segment read |
|---|---|
ENDORSE | the segment covering effectiveDate |
CANCEL | the segment covering effectiveDate |
REINSTATE | the segment covering effectiveDate on the cancelled version |
RENEW | the last segment of the expiring term |
Four transaction types, and why NEW_BUSINESS is not one of them. This
operation converts from a policy, and new business has no source policy to
convert from. New business is fully supported at bind: compose the field bag
yourself and post it, exactly as you do today.
Concurrency. sourcePolicy.policyVersion is the version the returned bag
was derived from. Echo it as expectedPolicyVersion on the bind request and
the bind is refused with a 409 if the policy moved while your user was
editing. That is the entire concurrency contract — the server holds nothing
on your behalf.
200 with findings vs. an error. The dividing rule is FIXABILITY, not
severity. Anything your user can fix by editing the returned draft comes back
as a 200 with entries in validationIssues and a usable data bag.
Anything they cannot fix by editing — an unknown policy, a policy in the
wrong state for the transaction, missing or failing Conversion Rules — is a
structured error with no draft at all.
Conversion uses the company’s explicitly authored rules. Missing required configuration is an error; matching field names do not supply a fallback.
Required permission: the requested transactionType’s own permission —
policy.endorse, policy.cancel, policy.reinstate or policy.renew.
Generating is the read half of authoring that transaction.
curl --request POST \
--url https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/generate \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"policyId": "550e8400-e29b-41d4-a716-446655440000",
"effectiveDate": "2026-06-01",
"transactionType": "ENDORSE"
}
'{
"data": {
"quoteType": "endorsement",
"quoteNumber": null,
"quoteStatus": "inProgress",
"policyType": "GL",
"effectiveDate": "2026-06-01",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Acme Co"
},
"primaryInsuredName": "Acme Co",
"description": null,
"fullTermBillingInfo": null,
"referencingPolicy": null,
"endorsementEffectiveDate": null
},
"sourcePolicy": {
"policyId": "550e8400-e29b-41d4-a716-446655440000",
"policyVersion": 4
},
"effectiveWindow": {
"startDate": "2026-01-01",
"endDate": "2026-12-31"
},
"validationIssues": []
}Authorizations
API key authentication. Send your raw API key as the Authorization header value with NO scheme prefix — Authorization: YOUR-API-KEY. Do NOT prefix it with Bearer or ApiKey, and do not use an X-API-Key header; those are not accepted.
Path Parameters
Company identifier
Body
The source policy to convert from.
"550e8400-e29b-41d4-a716-446655440000"
The transaction's effective date. Selects which segment of the
source policy is read (see the table above) and is readable by a
Conversion Rule as transaction.effectiveDate.
"2026-06-01"
Which transaction the generated quote would start. NEW_BUSINESS
is not accepted here — it has no source policy to convert from.
ENDORSE, CANCEL, REINSTATE, RENEW "ENDORSE"
An endorsement's optional term end date, readable by a Conversion
Rule as transaction.endDate. null in that scope for every
other transaction type.
"2026-12-31"
Response
The editable, unpersisted Quote data with its provenance. Returned
whether or not validationIssues is empty — a non-empty list still
carries a usable draft. Nothing was persisted.
The finished Quote draft, in the same flat shape you would
POST to bind: every declared Quote field, with quoteType
set from transactionType, calculated fields worked out, and
null where nothing fills a field or a value needs a saved
quote. Edit it and send it on; it exists nowhere on the
server.
Show child attributes
Show child attributes
The coverage window of the source segment that was read.
Show child attributes
Show child attributes
What the draft's own checks find in data, such as a field
you must supply or a value that fails its field's type
check. Empty means nothing is left to fix for a bind by
value. A draft you
save as a quote also needs referencingPolicy and its change
date, which this list does not report.
Show child attributes
Show child attributes
