> ## Documentation Index
> Fetch the complete documentation index at: https://docs.osaconnection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Polling for acceptance

> Find out which claims were accepted or rejected, efficiently and without missing any.

An adjuster accepting or rejecting a claim is the signal your system is waiting for. Today you read it by polling one endpoint across all your claims. (Webhooks are planned for a later release.)

## The pattern

Call `GET /v1/claims` every **1 to 5 minutes** with `updated_since`. Don't poll claims one by one.

```bash theme={"system"}
curl "https://api.osaconnection.com/v1/claims?updated_since=2026-09-28T15:04:42Z&limit=200" \
  -H "Authorization: Bearer $OSA_API_KEY"
```

1. Start from the latest `updated_at` you have processed, **minus about one minute**. On the very first poll, leave `updated_since` out to read every claim you have sent.
2. Follow `next_cursor` until it is `null`, sending the same filters with each cursor.
3. **De-duplicate by `id`.** The overlap means some claims come back more than once; that is expected and makes sure you never miss a change.
4. Save the newest `updated_at` you saw for the next poll.

```js theme={"system"}
const OVERLAP_MS = 60_000; // re-read the last minute on every poll

const since = loadCheckpoint(); // e.g. "2026-09-28T15:05:42Z"; null on the first run
const updatedSince = since ? new Date(Date.parse(since) - OVERLAP_MS).toISOString() : null;
let newest = since;
let cursor = null;
do {
  const params = new URLSearchParams({ limit: "200" });
  if (updatedSince) params.set("updated_since", updatedSince); // first run: read everything
  if (cursor) params.set("cursor", cursor);
  const res = await fetch(`https://api.osaconnection.com/v1/claims?${params}`, {
    headers: { Authorization: `Bearer ${process.env.OSA_API_KEY}` },
  });
  const page = await res.json();
  for (const claim of page.data) {
    if (claim.test && isProduction) continue;
    upsertClaim(claim.id, claim);    // keyed by id: safe to see a claim twice
    if (!newest || Date.parse(claim.updated_at) > Date.parse(newest)) newest = claim.updated_at;
  }
  cursor = page.next_cursor;
} while (cursor);
if (newest) saveCheckpoint(newest);
```

## What `updated_since` covers

* It is **inclusive**: a claim updated exactly at `updated_since` is returned.
* Results are ordered by `updated_at`, then `id`.
* `updated_at` moves only when something **you** can see changes: the claim is created, offered to another adjuster, accepted or rejected. The adjuster's work on the claim in the app doesn't move it, so polls stay small.

## Reading the result

Each claim's `assignment` describes the latest offer:

| `assignment.status` | Meaning | What you can do |
| - | - | - |
| `pending_acceptance` | Waiting for the adjuster | Wait, or offer it to someone else. An offer doesn't expire: it stays pending until the adjuster answers or you offer the claim to another adjuster |
| `accepted` | The adjuster has the claim | Nothing; the claim is in progress |
| `rejected` | The adjuster turned it down | Offer it to another adjuster with `POST /v1/claims/{id}/assignment` |
| `unassigned` | Not currently offered to anyone | Offer it to an adjuster with `POST /v1/claims/{id}/assignment` |

On a rejected claim, `assignment.adjuster_osa_id` is the adjuster who rejected it, `responded_at` is when, and `rejection_reason` is their optional reason. On an unassigned claim, `adjuster_osa_id` is `null`. When you offer the claim to someone else, `assignment` switches to the new offer.

Nothing you do through the API leaves a claim `unassigned`; the status is there for a claim OSA has taken back from its adjuster. Handle it the way you handle `rejected`.

The API reports a claim up to its acceptance. What the adjuster does afterwards (the inspection, the estimate, closing the claim) is not reported through the API today, so don't wait for a further status.

Statuses are an open enum: handle values you don't recognise without failing.

## Other filters

* `assignment_status=rejected`: only claims waiting to be re-offered.
* `external_id=CMS-884512`: look up a claim by your own id. A live key can get two results, a live claim and a test claim with the same `external_id`; `test` tells them apart.
* `limit`: 50 by default, up to 200.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.