Skip to navigation

truvo.md

Everything an agent needs to use the Truvo API, in one Markdown file.
View as Markdown

If you’re a coding agent, this file is for you. It explains what the Truvo API does, how to authenticate, every operation, the sandbox, and the rules for errors, retries, polling, and request keys. Each section links to the guide with more detail. Every example uses the sandbox. Sandbox quotes are synthetic, and a sandbox key never reads a live record or causes a live effect.

What Truvo does

The Truvo API gets insurance quotes from inside your product. You send one applicant’s facts for one line, Truvo gets the quotes in the background, and you read the result when it’s ready.

  • Lines: personal_auto, renters, and pet. One quote request covers one line.
  • Pet is quote plus a hand-off: the customer buys on the carrier’s site, and Truvo doesn’t learn the result.
  • Purchase: the API doesn’t have the purchase operations yet.

Terms

TermMeaning
quote requestThe asynchronous job that POST /v1/quote-requests starts. Its ID starts with qreq_.
quoteOne priced result, read with GET /v1/quotes/{id}. Its ID starts with qt_, and each quote has numbered versions.
linepersonal_auto, renters, or pet.
market_outcomesThe list on a quote request of each carrier that Truvo asked, and how it answered. Each entry names the carrier in source.
keyYour API key. It starts with trv_sandbox_ or trv_live_.
request keyThe value of the Idempotency-Key header. Over MCP, it’s the request_key argument.
sandbox workspaceThe sandbox state of one key: its active scenario, its clock, and its records.
scenarioA catalog entry that decides what a sandbox quote request returns.
final statusAny quote request status other than queued or running.

Keys and environments

Send your key as a bearer token on every request:

Authorization: Bearer trv_sandbox_...
  • Both environments use the base URL https://api.truvo.com/v1/, and the key prefix picks the environment: trv_sandbox_ is sandbox, and trv_live_ is live. After the prefix, a key has 32 letters and digits.
  • Truvo reads the environment and the customer from the key. Don’t send environment, customer, or customer_id in the query or the body, or an X-Environment, X-Customer, or X-Customer-Id header, because the API refuses that with 422 invalid_input.
  • The sandbox works before your organization is approved. Live traffic needs Truvo’s approval.
  • A key proves which integration is calling. It doesn’t prove authority over a particular customer, so Truvo checks the two separately. A resource that doesn’t exist and one outside your authority get the same 404.
  • A missing or invalid key gets 401 authentication_failed. An outage never returns 401, so treat a 401 as a problem with the key.
  • Every answer, success or error, carries a Request-Id header. An error body repeats it as request_id.

More: Keys and environments.

Operations

Every path sits under https://api.truvo.com. The OpenAPI document for these operations is https://api.truvo.com/v1/openapi.json, and the API reference shows the same schemas.

OperationHTTPRequest keyMCP tool
Discover capabilitiesGET /v1/capabilitiesNoget_insurance_capabilities
Start a quote requestPOST /v1/quote-requestsRequiredrequest_insurance_quotes
Read a quote requestGET /v1/quote-requests/{id}Noget_quote_request
List quote requestsGET /v1/quote-requestsNolist_quote_requests
Cancel a quote requestPOST /v1/quote-requests/{id}/cancelNoNone
Read a quoteGET /v1/quotes/{id}Noget_insurance_quote
Select a sandbox scenarioPOST /v1/sandbox/scenariosRequiredNone
List the sandbox scenariosGET /v1/sandbox/scenariosNoNone
Reset the sandboxPOST /v1/sandbox/resetRequiredNone
Run a sandbox controlPOST /v1/sandbox/controlsRequiredNone
Read the sandbox workspaceGET /v1/sandbox/workspaceNoNone
Send feedbackPOST /v1/feedbackNosend_feedback
Read a feedback reportGET /v1/feedback/{id}NoNone
Create a webhook subscriptionPOST /v1/event-subscriptionsRequiredNone
List or read subscriptionsGET /v1/event-subscriptions, GET /v1/event-subscriptions/{id}NoNone
Change a subscriptionPATCH /v1/event-subscriptions/{id}NoNone
Disable a subscriptionDELETE /v1/event-subscriptions/{id}NoNone
Rotate a signing secretPOST /v1/event-subscriptions/{id}/rotateRequiredNone
Send a test eventPOST /v1/event-subscriptions/{id}/testRequiredsend_test_event
List a subscription’s deliveriesGET /v1/event-subscriptions/{id}/deliveriesNolist_event_deliveries
Read one deliveryGET /v1/event-subscriptions/{id}/deliveries/{event_id}Noget_event_delivery
Replay a deliveryPOST /v1/event-subscriptions/{id}/replayRequiredreplay_event_delivery
Check delivery healthGET /v1/event-subscriptions/{id}/healthNoget_event_subscription_health
Read the event feedGET /v1/eventsNoNone
List recent requestsGET /v1/requestsNolist_recent_requests
Read a recent requestGET /v1/requests/{id}NoNone

A cancel answers cancelled, or cannot_stop when the work already went out and can’t stop.

The feedback, webhook, event feed, and request log operations answer 404, the same as an unknown path, while Truvo has them turned off. The webhook and event feed routes aren’t in the OpenAPI document yet.

Get a quote

These four steps price one personal auto quote in the sandbox. Set your key first:

export TRUVO_API_KEY="trv_sandbox_..."

1. Check what your key can do

curl https://api.truvo.com/v1/capabilities \
-H "Authorization: Bearer $TRUVO_API_KEY"

The answer gives the line, the environment, the states, a JSON Schema of the facts the line requires, and the action types a quote can offer. Build the application from that schema, and ask the person for each fact it needs. Don’t fill in a fact with a guess.

2. Start a quote request

Send the facts for one line, with a new request key. Every value in this body is synthetic:

curl -X POST https://api.truvo.com/v1/quote-requests \
-H "Authorization: Bearer $TRUVO_API_KEY" \
-H "Idempotency-Key: quickstart-quote-01" \
-H "Content-Type: application/json" \
-d '{
"line": "personal_auto",
"consent_receipt_id": "consent-auto-one-owned",
"application": {
"applicant": {
"name": { "first_name": "Test", "last_name": "Applicant One" },
"email": "alex@example.com",
"phone": "5550100000"
},
"garaging_address": {
"line1": "100 Example Way",
"line2": null,
"city": "Austin",
"state": "TX",
"postal_code": "78701"
},
"drivers": [
{
"name": { "first_name": "Test", "last_name": "Applicant One" },
"date_of_birth": "1990-04-12",
"gender": "female"
}
],
"vehicles": [
{
"vin": "SYNTHVIN000000001",
"year": 2019,
"make": "Toyota",
"model": "Camry",
"ownership": "owned",
"use": "pleasure",
"annual_mileage": 8000,
"comprehensive_deductible_minor": 100000,
"collision_deductible_minor": 100000
}
],
"protection": {
"bodily_injury_per_person_minor": 10000000,
"bodily_injury_per_accident_minor": 30000000,
"property_damage_minor": 5000000
}
}
}'
  • consent_receipt_id is the ID of the applicant’s consent for Truvo to get quotes for them. It covers quoting only. Consent receipts lists the other receipts.
  • For auto, driver 1 is the named insured, and the API takes the applicant’s date of birth from driver 1.
  • Money values are integers in minor units, so 10000000 is $100,000.

The API answers 202 with a quote request in the queued status. Save its id.

This body names no scenario, so in a new sandbox workspace it runs auto-one-driver-one-vehicle and returns one quote. Sandbox shows how to pick another outcome.

3. Wait for the result

curl https://api.truvo.com/v1/quote-requests/qreq_... \
-H "Authorization: Bearer $TRUVO_API_KEY" \
-H "Prefer: wait=20"

Read it again while the status is queued or running. Polling has a loop that does this.

4. Read a quote

Once the status is completed, quotes gives the ID and the version of each quote. Read one:

curl https://api.truvo.com/v1/quotes/qt_... \
-H "Authorization: Bearer $TRUVO_API_KEY"

Without version, you get the latest version. Add ?version= to read a specific one.

Each receipt is the ID of the person’s own record of one choice, and it covers only that choice. Never send one receipt ID in two fields, and never make a receipt up. Truvo reads IDs that differ only in case or separators, or that add segments to another ID on either side, as one receipt: Consent_1, consent-1.contact, and x:consent-1:y all match consent-1.

FieldCoversLines
consent_receipt_idQuoting. Required.All
credit_disclosure_receipt_idA credit check. Without it, credit_mode is declined.personal_auto
contact_consentContact by each channel in its channels: email, sms, or phone.All

contact_consent holds the receipt ID and the channels the person agreed to, each listed once. Set a channel in contact_channels to true only if the receipt lists it. A channel you leave out stays false.

"contact_consent": { "receipt_id": "tcpa-7f3a91", "channels": ["email", "phone"] },
"contact_channels": { "email": true, "phone": true }

A mismatch gets 422 invalid_input with a field error:

RequestField error
A channel set to true without contact_consentcontact_channels.phone: Send a contact consent receipt, or set the channel to false.
A channel that the contact receipt doesn’t listcontact_channels.phone: The contact consent receipt does not cover contact by phone.
The quote receipt as contact_consentcontact_consent.receipt_id: This receipt matches the quote consent receipt. It does not cover contact.
The quote receipt as credit_disclosure_receipt_idcredit_disclosure_receipt_id: This receipt matches the quote consent receipt. It does not cover a credit check.
contact_consent as a stringcontact_consent: Send contact_consent as an object with receipt_id and channels.

The quote request

queued and running mean the work is still going. Every other status is final, so stop reading when you see one.

StatusFinal
queuedNo
runningNo
completedYes
failedYes
cancelledYes
  • completeness is pending, partial, or complete. A partial result can still be useful.
  • quotes gives the ID and the version of each quote.
  • market_outcomes gives one outcome for each carrier: quote, decline, missing_information, failed, unknown, or no_answer. A quote outcome names its quote_id and quote_version.
  • requirements lists what’s still needed. Each entry has a kind (missing_fact or interaction), a path, and a code.
  • next_actions lists what you can do next.
  • failure is null unless the request failed. Then it says why: no_quotes_by_deadline or quote_run_not_started. Its retry action is use_new_request_key, so send the request again with a new Idempotency-Key.

A completed request with zero quotes isn’t a failure: a decline or an answer with no offers still completes. Check market_outcomes to see how each carrier answered.

Truvo stops collecting answers 60 seconds after it accepts a quote request. A carrier that hasn’t answered by then reads no_answer, and an answer that arrives later never reopens the request.

More: Get quote results.

The quote

FieldWhat it holds
sourceThe carrier and the product that priced the quote.
pricepremium, with an amount_minor and a currency of USD, or null when the price is unknown. Also term_months, billing_cycle (pay_in_full or monthly), fees, and comparison. premium is the price for the whole term, as the carrier states it. On a renters quote, premium already includes every fee in fees: show it as the total, and don’t add the fees to it. On other lines, the quote doesn’t say whether premium includes fees.
coverageconditions and the covered subjects.
availabilitystatus (active, expired, withdrawn, or unknown), expires_at, and revalidation (none, required, or unknown). When a renters quote states expires_at, it is 24 hours after Truvo rated the quote, or the start of the start date at the rented address, whichever comes first.
next_actionsThe actions this quote supports.
evidencelabel (mock, test, or live), source_time, and the assumptions the quote rests on, each with a path, a value, and a source.

The next action types are read_status, continue_on_carrier_site, prepare_purchase, open_hosted_checkout, and request_assistance. A quote lists only the ones it supports. Two of them work like this:

  • read_status names a resource to read again.
  • continue_on_carrier_site gives a url to open in a new tab. The link goes through a Truvo redirect to the carrier’s site and works until availability.expires_at. After that, it opens a Truvo page that says the quote has expired. In the sandbox, the link opens a Truvo sandbox page, never a carrier site.

An expired quote lists only read_status. Send a new quote request for a new price.

Rules for showing quotes to a person

  • Offer only the actions a quote lists. Never infer an action from the line or the carrier.
  • A quote is a price offer, not coverage. A checkout link isn’t proof of payment or coverage either.
  • One carrier’s quote isn’t a market comparison.
  • An unknown value stays unknown. Don’t fill in a price, a fee, or a limit that the quote doesn’t give.
  • A sandbox quote has evidence.label mock, no comparison amount, and the coverage condition Sandbox premium. Not a carrier price.

Polling

A quote request runs in the background, so read it until its status is final. A read never starts a new rating run.

  • Add Prefer: wait=N to hold the read open for up to N seconds, where N is a whole number from 0 to 20. The API answers as soon as the status is final, or when the time runs out. Without the header, it answers at once.
  • When the server held the read open, the answer carries Preference-Applied: wait=N.
  • When the server can’t hold the read, it answers at once without Preference-Applied and with Retry-After. Wait that many seconds before you read again.
  • A Prefer value that isn’t valid gets 422 invalid_input.
  • Over MCP, get_quote_request takes wait_seconds, from 0 to 20, in place of the header.

This loop waits for the Retry-After seconds when the answer has that header, and for 1 second when the server didn’t hold the read open:

while true; do
body=$(curl -s -D headers.txt "https://api.truvo.com/v1/quote-requests/$QUOTE_REQUEST_ID" \
-H "Authorization: Bearer $TRUVO_API_KEY" \
-H "Prefer: wait=20")
state=$(printf '%s' "$body" | jq -r .status)
if [ "$state" != "queued" ] && [ "$state" != "running" ]; then
break
fi
retry_after=$(awk -F': ' 'tolower($1) == "retry-after" { print $2 + 0 }' headers.txt)
if [ -n "$retry_after" ]; then
sleep "$retry_after"
elif ! grep -qi '^preference-applied:' headers.txt; then
sleep 1
fi
done
printf '%s\n' "$body"

Request keys

Networks drop responses. If that happens after you send a create, you can’t tell whether Truvo accepted it. A request key fixes that: send the same request with the same key, and Truvo returns the original result instead of starting a second request.

  • POST /v1/quote-requests, POST /v1/event-subscriptions, POST /v1/event-subscriptions/{id}/rotate, POST /v1/event-subscriptions/{id}/test, POST /v1/event-subscriptions/{id}/replay, and the three sandbox commands (POST /v1/sandbox/scenarios, POST /v1/sandbox/reset, and POST /v1/sandbox/controls) require the Idempotency-Key header. Reads don’t take one.
  • A key is 1 to 255 characters long, made of letters, digits, ., _, :, and -. Use a new key for each new request. A UUID works well.
  • The same key with the same body returns the original result. Truvo checks your current authority first, and it doesn’t start a second request.
  • The same key with a different body gets 409 conflict, with the retry action use_new_request_key. In the sandbox, a changed scenario counts as a different body.
  • A key’s scope is one environment, one integration, one resource, and one operation.
  • Over MCP, request_key carries the same key, with the same replay rules.

A key replays for at least 24 hours.

More: Retry safely with request keys.

Errors

When a request fails, the body tells you what went wrong, which fields caused it, and what to do about it. Branch your code on error.code and error.retry_action.type. The message is written for a person.

{
"error": {
"code": "needs_information",
"message": "The quote request needs more information.",
"field_errors": [
{
"path": "application.applicant.email",
"message": "This fact is required."
}
],
"retry_action": {
"type": "supply_facts",
"summary": "Supply the missing facts and send the request again."
},
"doc_url": "https://docs.truvo.com/v1/errors/needs_information"
},
"request_id": "req_..."
}

field_errors is a list of fields, each with a path and a message, or null. doc_url has the form https://docs.truvo.com/v1/errors/<code>, and it opens the code table in the Errors guide.

CodeHTTPWhat it means
invalid_json400The request body isn’t valid JSON.
invalid_cursor400The cursor isn’t one that this list or feed returned. It applies to every paged read: GET /v1/quote-requests, GET /v1/requests, GET /v1/event-subscriptions, and the event feed, GET /v1/events. Send a next_cursor from an earlier page of the same read, or leave the cursor out to start again.
authentication_failed401The key is missing or isn’t valid.
forbidden403The key doesn’t have authority for this action.
not_found404The resource doesn’t exist, or it’s outside your authority.
conflict409A request key conflict or a version conflict.
quote_expired409The quote has expired.
price_changed409The quote has a newer version with a different price.
purchase_not_supported409The quote has no purchase through the API.
event_cursor_expired410The event feed, GET /v1/events, keeps events for 30 days. It can’t resume from this cursor because retention deleted an event after it, or a sandbox reset voided it. Read each resource you track, then read the feed again without a cursor.
request_too_large413The request body is too large.
invalid_input422The input isn’t valid. field_errors lists the fields.
needs_information422Required facts are missing. Truvo returns this before it asks any carrier.
rate_limited429The key or its organization reached a rate limit, per minute or, in the sandbox, per day. The message names the limit.
internal_error500Something went wrong inside Truvo.
service_unavailable503A service that Truvo needs is down. Try the request again later, after the seconds in the Retry-After header.

Only the purchase operations return quote_expired, price_changed, and purchase_not_supported. The API doesn’t have those operations yet.

Retry actionWhat to do
noneDon’t send the request again.
retryTry the request again later.
correct_inputFix the fields in field_errors, then send the request again.
supply_factsAdd the missing facts in field_errors, then send the request again.
read_statusRead the resource again.
use_new_request_keySend the request with a new Idempotency-Key.
waitWait, then send the request again.
contact_supportContact Truvo support with the request_id.

When to retry

  • A timeout or a network error. Send the same body with the same request key.
  • 503 service_unavailable. Wait for the time in Retry-After, then send the same body with the same key.
  • 500 internal_error. Send the same body with the same key.
  • 429 rate_limited. Wait for the time in Retry-After, then send the request again.
  • 409 conflict. Your body is different from the first request with this key. To make a new request, use a new key.
  • A quote request that ends failed. Send it again with a new key.

Every operation except capabilities reports its rate limit in the RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset headers. They describe the limit you’re closest to reaching. RateLimit-Reset is the seconds until its count resets. Most windows are fixed at one minute, and a burst of up to twice the limit across a window edge is possible.

The sandbox also has daily limits, which reset at 00:00 UTC. Each organization can send 5,000 quote requests a day, and each call that counts toward its quote request limit counts toward this one too, even one that fails validation. When all organizations together have 25,000 sandbox quote requests accepted in a day, the sandbox is busy: until 00:00 UTC, it accepts new quote requests only from organizations with fewer than 500 accepted that day, up to 50,000 in all. A request that fails validation doesn’t count toward the 25,000 and 50,000 totals. A 429 from a daily limit says Try again after 00:00 UTC., and Retry-After gives the seconds until then.

Truvo can suspend an organization’s sandbox, for example when its traffic looks like abuse. Then each of its sandbox keys gets 403 forbidden with the retry action contact_support, and it can’t create sandbox keys, until Truvo restores it. Its live keys keep working.

More: Errors.

Webhooks

Instead of polling, subscribe a URL to the event types you want, and Truvo sends a signed POST each time one happens. The Webhooks guide has the details and the list of event types.

  • Subscribe. Send POST /v1/event-subscriptions with an Idempotency-Key, an https url on a public host, and the exact event_types you want. There’s no wildcard. The answer shows the signing_secret once, so store it right away. Only a server key can manage subscriptions, and each integration can hold 10 active subscriptions in each environment. PATCH and DELETE on /v1/event-subscriptions/{id} change or disable one, and POST /v1/event-subscriptions/{id}/rotate replaces the secret. The old secret keeps working for 24 hours.
  • Verify. Each delivery carries the svix-id, svix-timestamp, and svix-signature headers. The signature is an HMAC-SHA256 over {svix-id}.{svix-timestamp}.{body}, keyed with the part of your signing secret after whsec_, decoded from base64. Verify the raw body, before any JSON parsing. The svix libraries accept these headers as they are, and their verify refuses a timestamp more than 5 minutes from your clock.
  • Retries. Answer 2xx within 15 seconds. Any other answer counts as a failure, and the message is sent again after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours, and 10 hours. If every delivery fails for 5 days, delivery turns off until you send PATCH with your URL. The same event can arrive more than once and out of order, so skip an id you’ve already processed.
  • Thin events. An event names the resource that changed, in resource.type, resource.id, and resource.version, and it carries no customer data. Read the resource to see what changed, and never apply an older resource.version over a newer one. Ignore an event type or a field you don’t know, and still answer 2xx.
  • Resync through the feed. GET /v1/events holds every event of the last 30 days, with the same id as its webhook. Page through it with cursor and limit (10 by default, 100 at most), store each next_cursor only after your work is saved, and stop at an empty page. After event_cursor_expired, read each resource you track, then read the feed again without a cursor.

To check your endpoint, send a test event with POST /v1/event-subscriptions/{id}/test and a new Idempotency-Key. To see a real delivery in the sandbox, start a quote request or run the force_expiry control.

Sandbox

Each sandbox key has its own sandbox workspace, with an active scenario, its own clock, and your sandbox records. The paths under /v1/sandbox/ work only with a sandbox key: a live key gets 404, and a sandbox key without authority gets 403.

A scenario decides what a sandbox quote request returns. Pick one in either of two ways:

  • For one request: add "scenario": "<id>" to the body of POST /v1/quote-requests, or the scenario argument over MCP. The scenario must be for the request’s line. A live request that names a scenario gets 422 invalid_input.
  • For the workspace: POST /v1/sandbox/scenarios with {"scenario": "<id>"} and an Idempotency-Key. The scenario applies to each later quote request of its line, until you select another one or reset the workspace. Requests for other lines keep their default.

A new workspace has no scenario selected, so each line runs its default and returns one quote: auto runs auto-one-driver-one-vehicle, renters runs renters-one-offer, and pet runs pet-one-dog. The default sandbox scenario prices whatever pets, drivers, or vehicles you send. GET /v1/sandbox/scenarios lists the whole catalog, with each scenario’s line, summary, status, and completeness.

LineScenarioResult
Autoauto-one-driver-one-vehicleOne driver and one owned vehicle.
Autoauto-several-drivers-vehiclesThree drivers and two vehicles. One vehicle is owned and one is financed.
Autoauto-financed-vehicleOne driver and one financed vehicle.
Autoauto-leased-vehicleOne driver and one leased vehicle for business use.
Autoauto-several-offersTwo mock offers for one owned vehicle.
Autoauto-no-offersThe request completes with zero quotes.
Autoauto-partial-resultOne mock offer and one failed carrier.
Autoauto-declineThe carrier declines. The request completes with zero quotes.
Autoauto-expiryThe mock offer is already expired.
Autoauto-delayThe mock offer arrives after a fixed delay.
Autoauto-no-answerOne mock offer arrives after the collection deadline.
Autoauto-unknown-resultThe carrier’s answer is unknown. The API doesn’t invent a premium.
Autoauto-duplicate-deliveryThe same mock offer arrives twice.
Rentersrenters-one-offerOne mock renters offer.
Rentersrenters-no-active-productA Florida address, where not every renters carrier quotes. The request still completes with one mock offer.
Rentersrenters-several-offersTwo mock renters offers, each with its own quote ID.
Rentersrenters-no-offersThe request completes with zero quotes.
Rentersrenters-partial-resultOne mock offer and one failed carrier.
Rentersrenters-declineThe carrier declines. The request completes with zero quotes.
Rentersrenters-expiryThe mock offer is already expired.
Rentersrenters-delayThe mock offer arrives after a fixed delay.
Rentersrenters-no-answerOne mock offer arrives after the collection deadline.
Rentersrenters-unknown-resultThe carrier’s answer is unknown. The API doesn’t invent a premium.
Rentersrenters-duplicate-deliveryThe same mock offer arrives twice, with the same quote ID.
Petpet-one-dogOne mock pet offer for one dog.
Petpet-several-carriersThree mock carriers quote one dog, each with its own quote ID.
Petpet-two-petsOne mock offer for a dog and a cat, with one subject for each pet.
Petpet-mixed-breedNo carrier breed matches the requested breed, so the carrier rates each pet as mixed and the quote labels it with breed_rated_as_mixed.
Petpet-coverage-adjustmentThe carrier sells a 250ora250 or a 1,000 deductible and moves any other requested deductible to the next lower one. The quote labels this with carrier_coverage_adjustment.
Petpet-unsupported-stateOne carrier doesn’t sell in the owner’s state and declines. The other carrier quotes.
Petpet-declineThe carrier declines the household. The request completes with zero quotes.
Petpet-no-offersNo carrier returns an offer. The request completes with zero quotes.
Petpet-no-answerOne mock pet offer arrives after the collection deadline.

The catalog also has purchase and payment scenarios for auto and renters, but the API doesn’t have the purchase operations yet.

Sandbox controls go to POST /v1/sandbox/controls, one at a time, each with its own Idempotency-Key:

ControlBodyEffect
advance_time{"control": "advance_time", "by_seconds": 86400}Moves the workspace clock forward. Sandbox quotes expire 30 days after Truvo creates them.
force_expiry{"control": "force_expiry"}Quotes that Truvo created at or before this time read as expired.
replay_events{"control": "replay_events", "scenario": "..."}Needs an event scenario, and the catalog has none yet, so this control answers 422 invalid_input for every scenario. To see an event, make a real change, such as a quote request or force_expiry.

POST /v1/sandbox/reset with the body {} and an Idempotency-Key clears the workspace’s records, and puts the controls and every line’s scenario back to their start values. GET /v1/sandbox/workspace returns active_scenario, clock_offset_seconds, workspace_time, quotes_expired_at, reset_count, and scenario_catalog_version.

More: Sandbox scenarios.

MCP

The Truvo MCP server at https://api.truvo.com/v1/mcp serves the quote operations as tools, over Streamable HTTP, with the same key as a bearer token.

ToolWhat it does
get_insurance_capabilitiesShows what the key can quote for one line.
request_insurance_quotesStarts one quote request. It requires a request_key, and in the sandbox it takes an optional scenario.
get_quote_requestReads a quote request, with each quote inline. wait_seconds holds the answer for up to 20 seconds.
list_quote_requestsLists the key’s quote requests, newest first. It filters by status, line, created_after, created_before, or updated_since, and pages with limit and cursor.
get_insurance_quoteReads one quote. Leave out version to read the latest version.
send_feedbackSends a feedback report. The server lists it only while Truvo accepts feedback.
list_recent_requestsLists the integration’s recent requests, newest first, with each request’s status, error code, and request ID. The server lists it only while the request log is on.
send_test_eventSends a test event to one webhook subscription. It requires a request_key.
list_event_deliveriesLists one subscription’s deliveries from the last 30 days, newest first.
get_event_deliveryReads one delivery, with its attempts.
replay_event_deliverySends an event from the delivery log again, with the same event ID. It requires a request_key.
get_event_subscription_healthShows whether delivery to one subscription works.

The server lists the five webhook tools only while webhooks are on. A refused call comes back as a tool error that carries the same error envelope as HTTP. Canceling a quote request and the sandbox controls have no tool, so use HTTP for those.

More: Agent setup, with the config for Claude Code, Cursor, Codex, and VS Code.

Feedback

If the API is missing something, an answer is wrong, or an error or a page is unclear, tell Truvo. POST /v1/feedback takes a JSON body:

  • kind: missing_feature, bug, unclear_error, unclear_docs, or other. Required.
  • summary: one line, up to 200 characters, that says what went wrong or what’s missing. Required.
  • expected and actual: what you expected, and what happened instead, up to 2,000 characters each. Required.
  • tried: the operation or MCP tool you called, and the request_ids of up to 20 calls that show the problem.
  • agent: your agent’s name, such as Claude Code, and its version.

The API answers 201 with a feedback_id that starts with fb_ and the status received. GET /v1/feedback/{id} returns the report’s status (received, planned, shipped, or declined) and an optional note from Truvo. Leave out personal data: the API refuses text that looks like a Social Security, driver’s license, or card number.

  • Quickstart: the same first quote, step by step.
  • Agent setup: connect an MCP client, and an AGENTS.md block for your repo.
  • Webhooks: subscriptions, signatures, retries, event types, and the event feed.
  • API reference: every operation and its schemas.
  • /llms.txt: an index of every docs page. Add .md to any page URL to get its Markdown.