curl --request POST \
--url https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/rate \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"ratingWorkflowName": "standard"
}
'import requests
url = "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/rate"
payload = { "ratingWorkflowName": "standard" }
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'})
};
fetch('https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/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/{quoteId}/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'
]),
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/{quoteId}/rate"
payload := strings.NewReader("{\n \"ratingWorkflowName\": \"standard\"\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/{quoteId}/rate")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ratingWorkflowName\": \"standard\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/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}"
response = http.request(request)
puts response.read_body{
"data": {
"quoteType": "newBusiness",
"quoteNumber": "Q-000123",
"quoteStatus": "inProgress",
"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 Saved Quote by Id
Rates an already-saved quote, named by id, and returns the rating results without persisting the returned field values.
The rated field bag remains stateless. No quote field or rating run is
persisted, and the quote row is byte-identical before and after — same field
values, same updatedAt. On a successful rate, the service records the
requested ratingWorkflowName as Quote system metadata so later saved-quote
workflows know which workflow was selected. A failed rating does not change
that selection. The rating results exist only in the response you receive,
so if you want them stored on the quote, write them back
yourself with PATCH /api/v1/companies/{companyId}/entities/quote/{entityId}
(for an in-force policy, a policy endorse transaction instead). That
write-back is the mutation — 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.
This is the by-id sibling of
POST /api/v1/companies/{companyId}/quotes/rate; the field-bag difference is
where the field bag comes from — loaded from the saved quote here, supplied
in the request body there. Only the by-id endpoint can record a saved quote’s
workflow selection.
The quote id is a path parameter; the request body carries only
ratingWorkflowName. There are deliberately no data overrides — to
rate what-if values (“as if field X were Y”), GET the quote, tweak it, and
POST the full-body /quotes/rate endpoint, which supports inline overrides.
Semantics. The saved quote’s stored field bag is validated with the
identical create-quote pipeline (shape, resolution, tenant invariants, entity
invariants), embedded exposure id references are looked up and merged from
their stored data exactly as the full-body endpoint does, and then the named
rating workflow runs. For a supported quote type there is no quote-status
gate — any saved quote rates regardless of quoteStatus (bound and
cancelled included), because rating a saved quote is a read-only
computation that can corrupt nothing. This status promise does not expand
the supported quote types: cancellation and reinstatement return a
structured 400 InvalidRequest before any rater or vendor call because
those transactions preserve rating and derive or restore pricing.
The 200 response returns the saved quote’s bag 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 a rate that prices nothing returns those containers empty rather than carrying the quote’s previously stored figures. Writing such a response back wholesale would therefore clear the stored money — check the response for the values you expect before persisting it.
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/{quoteId}/rate \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"ratingWorkflowName": "standard"
}
'import requests
url = "https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/rate"
payload = { "ratingWorkflowName": "standard" }
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'})
};
fetch('https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/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/{quoteId}/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'
]),
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/{quoteId}/rate"
payload := strings.NewReader("{\n \"ratingWorkflowName\": \"standard\"\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/{quoteId}/rate")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ratingWorkflowName\": \"standard\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://go.aiinsurance.io/api/v1/companies/{companyId}/quotes/{quoteId}/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}"
response = http.request(request)
puts response.read_body{
"data": {
"quoteType": "newBusiness",
"quoteNumber": "Q-000123",
"quoteStatus": "inProgress",
"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
Quote identifier
Body
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. There is no fallback to any per-quote persisted
selection.
"standard"
Response
The rating outcome. A successful rate records the requested workflow selection, but the returned field values remain caller-persisted.
Success: data carries the saved quote's 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 saved quote's stored field bag, 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
