curl --request POST \
--url https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"ratingWorkflowName": "standard",
"data": {
"quoteType": "newBusiness",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"exposureName": "Acme Co"
},
"otherExposures": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Beta LLC"
}
]
}
}
'import requests
url = "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate"
payload = {
"ratingWorkflowName": "standard",
"data": {
"quoteType": "newBusiness",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"exposureName": "Acme Co"
},
"otherExposures": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Beta LLC"
}
]
}
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
ratingWorkflowName: 'standard',
data: {
quoteType: 'newBusiness',
primaryInsured: {id: '550e8400-e29b-41d4-a716-446655440001', exposureName: 'Acme Co'},
otherExposures: [{id: '550e8400-e29b-41d4-a716-446655440002', exposureName: 'Beta LLC'}]
}
})
};
fetch('https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ratingWorkflowName' => 'standard',
'data' => [
'quoteType' => 'newBusiness',
'primaryInsured' => [
'id' => '550e8400-e29b-41d4-a716-446655440001',
'exposureName' => 'Acme Co'
],
'otherExposures' => [
[
'id' => '550e8400-e29b-41d4-a716-446655440002',
'exposureName' => 'Beta LLC'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate"
payload := strings.NewReader("{\n \"ratingWorkflowName\": \"standard\",\n \"data\": {\n \"quoteType\": \"newBusiness\",\n \"primaryInsured\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"exposureName\": \"Acme Co\"\n },\n \"otherExposures\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"exposureName\": \"Beta LLC\"\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ratingWorkflowName\": \"standard\",\n \"data\": {\n \"quoteType\": \"newBusiness\",\n \"primaryInsured\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"exposureName\": \"Acme Co\"\n },\n \"otherExposures\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"exposureName\": \"Beta LLC\"\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ratingWorkflowName\": \"standard\",\n \"data\": {\n \"quoteType\": \"newBusiness\",\n \"primaryInsured\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"exposureName\": \"Acme Co\"\n },\n \"otherExposures\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"exposureName\": \"Beta LLC\"\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"quoteType": "newBusiness",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"exposureName": "Acme Co",
"exposureRatingResponse": {
"premium": 1000
}
},
"otherExposures": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Beta LLC",
"exposureRatingResponse": {
"premium": 1000
}
}
],
"fullTermPolicyRatingResult": {
"policyPremium": 3000,
"policyGrandTotal": 3500
}
}
}Rate Quote (Read-Only)
Rates the quote a create-quote request WOULD create, and returns the rating results — without persisting anything. No quote is stored, no rating run is recorded, and no existing entity is touched. Use it to preview premium for a prospective quote, or to rate a quote you manage in your own system.
This endpoint is a read, not a mutation — as is its by-id sibling
POST /api/v1/companies/{companyId}/quotes/{quoteId}/rate, which rates a
saved quote without modifying it. The results exist only in the response, so
if you want them stored, write them back yourself with
PATCH /api/v1/companies/{companyId}/entities/quote/{entityId} — see the
Rating overview’s Persisting rating results. Copy the returned
fullTermPricingInfo (including pricingComponents and computed totals)
when it is present, read the quote back to verify the committed values, and
only then bind it. Bind reads the persisted quote, not this rate response.
The request body carries the exact create-quote payload under data (the
same flat field bag you would POST to
/api/v1/companies/{companyId}/entities/quote), plus the
ratingWorkflowName naming which configured rating workflow to run.
Semantics — “rate the quote this body would create.” The data bag is
validated with the identical create-quote pipeline (shape, resolution,
tenant invariants, entity invariants) with the same rules an external
create applies: embedded exposures must reference existing Exposure records
by id (id-less / draft embedded values are rejected). A body that
create-quote would reject fails here with the identical structured 400.
Then the named rating workflow runs over the resolved quote.
Hosted rating supports newBusiness, renewal, and endorsement quote
types. cancellation and reinstatement return a structured
400 InvalidRequest before any rater or vendor call because those
transactions preserve the source policy rating result and derive or restore
pricing instead of repricing.
Exposure id references are looked up and merged. Because an API-key
caller references exposures by id (embedded exposures cannot be
inline-created over the API), each referenced Exposure’s stored fields are
fetched and merged under the reference before rating, so the exposure is
rated against its real stored data rather than a blank record. Fields you
supply inline win over the stored values, per top-level field (the body
is treated as a draft-edit over the stored exposure). This lookup is
read-only — nothing is persisted. (Note: this is an interim behavior for
EmbeddedExposure exposure references; join-linked entities are not
hydrated.)
The 200 response echoes the same bag back under data, enriched with the
rating outputs (e.g. exposureRatingResponse on each exposure and the
full-term policy rating containers).
The response reflects only this run. The rating workflow clears the containers it owns before any rater runs and rebuilds them from this run’s output, so rating containers your request body happens to carry from an earlier run are not echoed back, and a rate that prices nothing returns those containers empty rather than repeating what you sent.
Rating failures also return 200 — with a diagnostics array
describing what went wrong and no data. Check for the presence of
data to detect success, not the HTTP status. Invalid requests (anything
under the 400/404/422 descriptions below) are still rejected with
their status codes; only failures during rating execution itself (e.g. a
rating vendor error) report as 200 + diagnostics.
Required permission: quote.rate
curl --request POST \
--url https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"ratingWorkflowName": "standard",
"data": {
"quoteType": "newBusiness",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"exposureName": "Acme Co"
},
"otherExposures": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Beta LLC"
}
]
}
}
'import requests
url = "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate"
payload = {
"ratingWorkflowName": "standard",
"data": {
"quoteType": "newBusiness",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"exposureName": "Acme Co"
},
"otherExposures": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Beta LLC"
}
]
}
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
ratingWorkflowName: 'standard',
data: {
quoteType: 'newBusiness',
primaryInsured: {id: '550e8400-e29b-41d4-a716-446655440001', exposureName: 'Acme Co'},
otherExposures: [{id: '550e8400-e29b-41d4-a716-446655440002', exposureName: 'Beta LLC'}]
}
})
};
fetch('https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ratingWorkflowName' => 'standard',
'data' => [
'quoteType' => 'newBusiness',
'primaryInsured' => [
'id' => '550e8400-e29b-41d4-a716-446655440001',
'exposureName' => 'Acme Co'
],
'otherExposures' => [
[
'id' => '550e8400-e29b-41d4-a716-446655440002',
'exposureName' => 'Beta LLC'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate"
payload := strings.NewReader("{\n \"ratingWorkflowName\": \"standard\",\n \"data\": {\n \"quoteType\": \"newBusiness\",\n \"primaryInsured\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"exposureName\": \"Acme Co\"\n },\n \"otherExposures\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"exposureName\": \"Beta LLC\"\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ratingWorkflowName\": \"standard\",\n \"data\": {\n \"quoteType\": \"newBusiness\",\n \"primaryInsured\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"exposureName\": \"Acme Co\"\n },\n \"otherExposures\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"exposureName\": \"Beta LLC\"\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/rate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ratingWorkflowName\": \"standard\",\n \"data\": {\n \"quoteType\": \"newBusiness\",\n \"primaryInsured\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"exposureName\": \"Acme Co\"\n },\n \"otherExposures\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"exposureName\": \"Beta LLC\"\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"quoteType": "newBusiness",
"primaryInsured": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"exposureName": "Acme Co",
"exposureRatingResponse": {
"premium": 1000
}
},
"otherExposures": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"exposureName": "Beta LLC",
"exposureRatingResponse": {
"premium": 1000
}
}
],
"fullTermPolicyRatingResult": {
"policyPremium": 3000,
"policyGrandTotal": 3500
}
}
}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 create-quote payload — the flat field bag, unchanged.
Custom fields are validated against your company's field
configuration (unknown fields rejected, required fields
enforced, values matched to their configured types). Embedded
exposure values are validated per-field against the Exposure
configuration and must reference existing Exposure records by
id; each referenced exposure's stored fields are then merged
in for rating, with any fields you supply inline winning over
the stored values.
The configured rating workflow to run. Required in practice —
there is no default even when a single workflow is configured —
but it is not schema-required: rather than a shape rejection, a
missing or unknown name returns a 400 listing the configured
workflow names (and a company with no workflows configured
returns a 422), so callers get an actionable error naming the
valid options.
"standard"
Response
The rating outcome. Nothing is persisted either way.
Success: data carries the quote bag enriched with rating outputs.
Rating failure: the response is still 200, with diagnostics
describing what went wrong and no data — the absent data is
the failure signal, so do not treat the presence of diagnostics
alone as failure: severity: warning diagnostics ride alongside a
successful data when a rater reports them. Rating failures are
engine/vendor faults during rating execution; an invalid request is
still a 4xx, and an unexpected application fault is still a 500.
The same field bag from the request, enriched with rating
outputs (per-exposure exposureRatingResponse, and the
full-term policy rating containers). Absent when the rate
failed.
Rating diagnostics. Present with severity: error entries
when the rate failed (in which case data is absent), or
with severity: warning entries beside a successful data.
Show child attributes
Show child attributes
