> For the complete documentation index, see [llms.txt](https://docs.insurgrid.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.insurgrid.com/policy-comparison-api.md).

# Policy Comparison API

Send a client's current and proposed policy PDFs, get back a structured breakdown of what changed.

When you put a new policy in front of a client, the hard part is explaining what actually changed. This API does that reading for you.

Upload the policy they have today and the one you're proposing. InsurGrid reads both documents and returns a structured comparison: coverage that moved, how the premium differs, drivers and vehicles added or dropped, and plain-language talking points you can take into the conversation.

It works on personal and commercial lines, from auto and homeowners through to workers' compensation, cyber and commercial packages.

**You'll need:** an agent API key, and the policy documents as PDFs.

***

## How it works

Reading two policies takes longer than a web request should, so the work happens in the background:

1. **Submit** both sets of PDFs in one request.
2. **Get an id back** straight away, while processing continues.
3. **Poll** with that id every few seconds.
4. **Stop** when the status is `completed` or `error`.

A typical comparison finishes in well under a minute.

## Before you start

Every request carries your API key as a bearer token:

```
Authorization: Bearer YOUR_API_KEY
```

Create and revoke keys in the agent dashboard. A key belongs to the agent who made it, and only that agent can read the comparisons it creates.

Keys are server-side credentials. Keep them out of browser code, mobile apps, public repositories and logs.

| Environment | Base URL                                |
| ----------- | --------------------------------------- |
| Staging     | `https://phoenix-staging.insurgrid.com` |
| Production  | `https://phoenix.insurgrid.com`         |

Everything below lives under `/api/v1`. Only the host changes between environments — paths, fields and errors are identical, and a key works in one environment only. See [Environments](/guides/environments.md).

***

## Quick start

**Submit a comparison.** The PDFs go in the same request — there's no separate upload step.

```bash
curl -X POST 'https://phoenix-staging.insurgrid.com/api/v1/policy-comparisons' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -F 'prospect=Acme Corporation' \
  -F 'policy_type=auto_policy' \
  -F 'current_policy_files=@current-policy.pdf;type=application/pdf' \
  -F 'proposed_policy_files=@proposed-policy.pdf;type=application/pdf'
```

You get a `202 Accepted` and an id:

```json
{
  "id": "ef23d8f5-0dc3-46f2-b70d-6e0aef3ec6ae",
  "status": "processing",
  "createdAt": "2026-09-29T12:32:11Z"
}
```

**Then poll for the result**, every 3–5 seconds:

```bash
curl 'https://phoenix-staging.insurgrid.com/api/v1/policy-comparisons/ef23d8f5-0dc3-46f2-b70d-6e0aef3ec6ae' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

While it's working you'll see `"status": "processing"`. When it's done, the same response carries a `result`.

***

## Submitting a comparison

`POST /api/v1/policy-comparisons`, as `multipart/form-data`.

| Field                   | Required | What it is                                                         |
| ----------------------- | -------- | ------------------------------------------------------------------ |
| `prospect`              | Yes      | The client or prospect name, 1–200 characters.                     |
| `policy_type`           | Yes      | Which kind of policy these are. See the table below.               |
| `current_policy_files`  | Yes      | The policy they have now. Repeat the field to attach several PDFs. |
| `proposed_policy_files` | Yes      | The policy you're proposing. Repeat the field to attach several.   |

For a policy that spans several documents, repeat the field rather than zipping them together:

```bash
  -F 'current_policy_files=@current-property.pdf;type=application/pdf' \
  -F 'current_policy_files=@current-liability.pdf;type=application/pdf' \
```

### Policy types

| Personal          | Commercial                      |
| ----------------- | ------------------------------- |
| `auto_policy`     | `commercial_auto_policy`        |
| `home_policy`     | `commercial_home_policy`        |
| `umbrella_policy` | `commercial_bop`                |
|                   | `commercial_general_liability`  |
|                   | `commercial_worker_comp_policy` |
|                   | `commercial_umbrella`           |
|                   | `commercial_cyber`              |
|                   | `commercial_marine`             |
|                   | `commercial_package`            |

Anything else returns `422 unsupported_policy_type`.

### Document requirements

PDFs only — sent with a `.pdf` extension and the `application/pdf` content type. Password-protected, corrupted or unreadable files may fail during processing.

| Limit                | Value  |
| -------------------- | ------ |
| PDFs per side        | 10     |
| Combined upload size | 200 MB |
| Pages per PDF        | 1,000  |

***

## Reading the result

`GET /api/v1/policy-comparisons/{id}`, using a key belonging to the agent that created it.

| Status       | Done? | What it means                              |
| ------------ | ----- | ------------------------------------------ |
| `processing` | No    | Still reading the documents. Keep polling. |
| `completed`  | Yes   | The comparison is in `result`.             |
| `error`      | Yes   | Processing failed. Stop polling.           |

A completed response, trimmed:

```json
{
  "id": "ef23d8f5-0dc3-46f2-b70d-6e0aef3ec6ae",
  "status": "completed",
  "prospect": "Acme Corporation",
  "policyType": "auto_policy",
  "createdAt": "2026-09-29T12:32:11Z",
  "completedAt": "2026-09-29T12:32:52Z",
  "result": {
    "comparison": {
      "provider_changed": true,
      "insurer_changed": true,
      "key_changes": [
        "Liability limits increased from $100,000/$300,000 to $300,000/$500,000.",
        "The collision deductible increased from $1,000 to $2,500."
      ],
      "talking_points": [
        "The proposed policy provides higher liability protection."
      ],
      "premium_comparison": {
        "annual": { "old": 1200, "new": 1450, "difference": 250, "percent_change": 20.83 }
      }
    },
    "current_or_old_policy": { "policy": {}, "drivers": [], "vehicles": [], "discounts": [], "surcharges": [] },
    "new_policy":            { "policy": {}, "drivers": [], "vehicles": [], "discounts": [], "surcharges": [] }
  }
}
```

`result` has three parts:

* **`current_or_old_policy`** and **`new_policy`** — what was read out of each document: policy details, drivers, vehicles, discounts and surcharges.
* **`comparison`** — the differences between them.

In each policy, `policy.provider` is the company that quoted or issued it: the brand, MGA or program administrator named on the document (for example Fusion Cyber), not the insurer that underwrites it (for example Certain Underwriters at Lloyd's, London).

`policy.insurer` is the insurer that underwrites or issues the policy, as printed on the document (for example Certain Underwriters at Lloyd's, London). It is the same company as `provider` when the quoting company is itself the insurer, and `null` when the document names no insurer — for example a quote that shows only an MGA, wholesaler or agency. Comparisons created before 16 October 2026 don't have this field.

Inside `comparison`:

| Field                         | What it gives you                                                                                           |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `key_changes`                 | The headline differences, written as short sentences.                                                       |
| `talking_points`              | Phrasing you can use with the client.                                                                       |
| `premium_comparison`          | Old and new premiums, the difference and the percentage.                                                    |
| `coverage_comparison_table`   | Coverage by coverage, old limit against new.                                                                |
| `coverage_changes_by_vehicle` | The same, broken down per vehicle.                                                                          |
| `driver_changes`              | Drivers added, removed or amended.                                                                          |
| `vehicle_changes`             | Vehicles added, removed, replaced or amended.                                                               |
| `premium_difference_reasons`  | Why the premium moved.                                                                                      |
| `provider_changed`            | Whether the company that quoted or issued the policy (`policy.provider`) is different.                      |
| `insurer_changed`             | Whether the underwriting insurer (`policy.insurer`) is different. `null` when either policy has no insurer. |

What appears depends on the policy type and on what the documents actually contain — fields can be absent, empty or `null`.

> **Check the result against the policy documents.** The comparison is generated from the PDFs you supplied. Confirm limits, exclusions, deductibles and premiums against the originals before advising a client on them.

### When it fails

```json
{
  "id": "ef23d8f5-0dc3-46f2-b70d-6e0aef3ec6ae",
  "status": "error",
  "error": {
    "code": "comparison_failed",
    "message": "The comparison could not be completed."
  }
}
```

No further polling is needed.

***

## Errors

Errors always arrive in the same shape:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "Required multipart fields are missing or malformed."
  }
}
```

When the failure relates to a comparison that was already created, the body also carries `error.comparisonId`.

| Status | Code                           | What went wrong                                                      |
| ------ | ------------------------------ | -------------------------------------------------------------------- |
| 400    | `invalid_request`              | A required field is missing, duplicated or malformed.                |
| 401    | `invalid_api_key`              | The key is missing, invalid, revoked, or from the other environment. |
| 404    | `not_found`                    | No such comparison on this key's agent.                              |
| 413    | `too_many_files`               | More than 10 PDFs on one side.                                       |
| 413    | `file_too_large`               | Over the size or page limit.                                         |
| 415    | `pdf_required`                 | Something that isn't a readable PDF.                                 |
| 422    | `unsupported_policy_type`      | `policy_type` isn't one of the values above.                         |
| 429    | `rate_limited`                 | Too many requests. Wait for `Retry-After` seconds.                   |
| 500    | `comparison_submission_failed` | The comparison couldn't be submitted.                                |
| 503    | `service_unavailable`          | Temporarily unavailable. Try again.                                  |

## Rate limits

**60 requests per minute per agency**, counting both submissions and reads. Going over returns `429` with a `Retry-After` header telling you how many seconds to wait.

Comparisons aren't metered — there are no credits to run out of, and this limit is the only throttle.

## Keeping it safe

Policy documents contain personal information, so:

* call the API from your server, never the browser;
* store keys in a secrets manager or encrypted environment variable;
* use a separate key per agent or integration, and revoke immediately if one may have leaked;
* avoid logging uploaded documents or whole API responses.

## Related

* [Environments](/guides/environments.md) — staging and production addresses.
* [Authentication & tokens](/guides/authentication.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.insurgrid.com/policy-comparison-api.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
