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

# Creating and managing Claims

> How to file and track carrier claims through the API

A claim is what you file with us when a shipment goes wrong, either it never showed up (`LOST`) or it arrived broken (`DAMAGED`). You send us the shipment info and what you're claiming, and Opereit takes it from there: preparing documentation and running the claim through the carrier's process.

This page walks through the practical stuff: what you need before you call the API, what the fields actually mean, and a few things that'll trip you up if you don't know about them. For the full field-by-field breakdown, see the [API Reference](/api-reference/endpoint/claims/create).

## Before you start

You'll need:

* An **API key** (see [Authentication](/api-reference/introduction#authentication) if you don't have one yet).
* The shipment's **tracking number** and **carrier**.
* The **destination address** the parcel was headed to.
* What's being claimed: item(s), quantity, price, and the total amount you're claiming.

## Creating a claim

```bash theme={null}
curl -X POST "https://api.opereit.ai/v1/claims" \
  -u "your_key_id:your_key_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "shipment": {
      "tracking_number": "1Z999AA1234567890",
      "carrier": "UPS",
      "line_items": [
        { "description": "Electronic Component", "quantity": 2, "unit_price": 15000, "currency": "EUR" }
      ],
      "origin": { "postcode": "28001", "country": "ES" },
      "destination": {
        "postcode": "08001",
        "country": "ES",
        "city": "Barcelona",
        "address": "Passeig de Gràcia, 5",
        "customer_name": "John Doe",
        "customer_phone": "+34987654321"
      }
    },
    "incidence": {
      "type": "DAMAGED",
      "description": "Items arrived with cracked casing.",
      "claimed_amount": 30000,
      "currency": "EUR"
    }
  }'
```

A few things worth knowing about the fields:

* **Amounts are always in the smallest unit of the currency**, not decimals, so `unit_price: 15000` and `claimed_amount: 30000` above mean €150.00 and €300.00 (EUR has 2 decimal places, so the minor unit is 1/100). That conversion isn't the same for every currency, e.g. JPY has no decimal places at all, so 150 JPY is sent as `150`, not `15000`. Check the ISO 4217 minor unit for whatever currency you're sending before assuming ×100.
* **`claimed_amount` is independent of `line_items`.** We don't sum the line items for you, whatever you put in `incidence.claimed_amount` is the amount that gets claimed. Line items are there to document *what* was in the shipment, not to calculate the total.
* **`destination.city`, `address`, and `customer_name` are all required.** `customer_phone` is optional, but if you send one it needs to be 6 to 20 characters.
* **`carrier` has to be one of the values below.** Anything else gets rejected with a 400 before we even touch the shipment.

### Supported carriers

|                   |                  |              |           |
| ----------------- | ---------------- | ------------ | --------- |
| `BPOST`           | `BRT`            | `CHRONOPOST` | `CORREOS` |
| `CORREOS_EXPRESS` | `CTT`            | `DPD`        | `EVRI`    |
| `FEDEX`           | `GLS`            | `INPOST`     | `MAERSK`  |
| `PAACK`           | `PC_COMPONENTES` | `POSTAG`     | `SEUR`    |
| `UPS`             |                  |              |           |

If your carrier isn't on this list, get in touch, we're adding more regularly.

### The `provider` field

`provider` is optional and only relevant if you booked the shipment through a multi-carrier platform or aggregator rather than directly with the carrier. Most integrations can just leave it out. Known values:

|                   |                  |              |             |
| ----------------- | ---------------- | ------------ | ----------- |
| `BPOST`           | `BRT`            | `CHRONOPOST` | `CORREOS`   |
| `CORREOS_EXPRESS` | `CTT`            | `DPD`        | `EVRI`      |
| `FEDEX`           | `GLS`            | `INPOST`     | `MAERSK`    |
| `PAACK`           | `PC_COMPONENTES` | `POSTAG`     | `SENDCLOUD` |
| `SEUR`            | `UPS`            | `WING`       |             |

### Filing more than one claim for the same tracking number

You can only have one *open* claim per tracking number at a time, if one's already open, a second `POST` for the same `tracking_number` gets a `409`.

A claim counts as **closed** (not open) when it's:

* `REJECTED`, for any reason, or
* `CANCELED` with a status reason of `CREATED_INCORRECTLY` or `SHIPMENT_NOT_CLAIMABLE_YET` (see [Status reasons](#status-reasons) below).

Any other status, including a `CANCELED` claim with a different reason, still counts as open.

<Warning>
  Once a shipment's tracking number has been used for a claim before, sending it again reuses the shipment record we already have on file. That means the `origin` and `destination` you send only actually get saved the *first* time a claim is filed for that tracking number. If you file a second claim later (say, the first one got resolved and now something else went wrong with the same parcel), the origin/destination in the response will reflect what was originally submitted, not whatever you sent this time around. If an address genuinely changed, that's a case for support rather than the API.
</Warning>

## DAMAGED vs LOST

There isn't much nuance here. `LOST` means the parcel never arrived. `DAMAGED` means it did arrive, but something inside was broken, missing, or otherwise not right. Use `incidence.description` to say what actually happened, it helps a lot when the claim gets reviewed and when we're building the paperwork for the carrier.

## What happens after you create a claim

Every claim starts at `CREATED`. From there it moves through review with the carrier, and eventually lands somewhere final. Here's the full list:

| Status                            | Meaning                                                                                                                                                                                         |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CREATED`                         | Just filed, hasn't been reviewed yet.                                                                                                                                                           |
| `UNDER_REVIEW`                    | The carrier is looking at it.                                                                                                                                                                   |
| `PENDING_ACTION`                  | We need to do something on our end before it can move forward.                                                                                                                                  |
| `PENDING_REFUND`                  | A refund is coming, but the amount isn't confirmed yet.                                                                                                                                         |
| `PENDING_REFUND_AMOUNT_CONFIRMED` | The refund amount is confirmed, just hasn't been paid out yet.                                                                                                                                  |
| `RESOLVED`                        | Done, resolved in your favor.                                                                                                                                                                   |
| `CANCELED`                        | The claim was withdrawn. Closed if the reason was `CREATED_INCORRECTLY` or `SHIPMENT_NOT_CLAIMABLE_YET`, open otherwise, see [above](#filing-more-than-one-claim-for-the-same-tracking-number). |
| `REJECTED`                        | The carrier rejected it. Always closed, regardless of the reason.                                                                                                                               |
| `CLOSED`                          | Closed out, for reasons other than the above.                                                                                                                                                   |

## Status reasons

`PENDING_ACTION`, `CANCELED`, and `REJECTED` also come with a `status_reason`, extra detail on specifically why the claim landed there. Every other status leaves `status_reason` as `null`.

### PENDING\_ACTION

| Reason                                         | What it means                              |
| ---------------------------------------------- | ------------------------------------------ |
| `RESTRICTED_ACCOUNT_VIEW`                      | Restricted account view.                   |
| `PENDING_UPLOAD_DOCUMENTS`                     | We're waiting on documents to be uploaded. |
| `UPDATE_ITEMS_INFORMATION`                     | The item information needs to be updated.  |
| `TRACKING_REVIEW_REQUIRED`                     | The tracking info needs a review.          |
| `CUSTOMER_ACTION_REQUIRED_DAMAGE_PROOF`        | We need proof of the damage from you.      |
| `CUSTOMER_ACTION_REQUIRED_AFFIDAVIT`           | We need a signed affidavit from you.       |
| `CUSTOMER_ACTION_REQUIRED_REFUND_CONFIRMATION` | We need you to confirm the refund.         |

Right now, whatever the reason, the only way to act on a `PENDING_ACTION` claim (including the three `CUSTOMER_ACTION_REQUIRED_*` ones above) is to reach out to Opereit support. We're working on letting you resolve these directly through self-service actions, but that's not available yet.

### CANCELED

| Reason                          | What it means                                                            |
| ------------------------------- | ------------------------------------------------------------------------ |
| `TIME_EXCEEDED`                 | Too much time passed to keep pursuing the claim.                         |
| `CLAIM_ALREADY_EXISTS`          | A claim already existed for this shipment.                               |
| `DELIVERED_BY_CARRIER`          | The carrier shows the shipment as delivered.                             |
| `CUSTOMS_HOLD_UNKNOWN`          | The shipment is held at customs for an unknown reason.                   |
| `CUSTOMS_HOLD_AWAITING_PAYMENT` | The shipment is held at customs awaiting duty payment from the receiver. |
| `SHIPMENT_NOT_CLAIMABLE_YET`    | The shipment was sent too recently to be claimable.                      |
| `SHIPMENT_NOT_SENT`             | The shipment was never sent.                                             |
| `PACKAGE_AT_ACCESSPOINT`        | The package is sitting at an access point.                               |
| `CREATED_INCORRECTLY`           | The claim was created incorrectly and needs to be recreated.             |

Of these, `CREATED_INCORRECTLY` and `SHIPMENT_NOT_CLAIMABLE_YET` are the two that count as closed, meaning they don't block a new claim on the same tracking number. See [Filing more than one claim for the same tracking number](#filing-more-than-one-claim-for-the-same-tracking-number). The rest still count as open.

### REJECTED

| Reason                            | What it means                                   |
| --------------------------------- | ----------------------------------------------- |
| `MISSING_PRODUCT_INFORMATION`     | The product information provided wasn't enough. |
| `CLAIM_VOIDED_BY_CARRIER`         | The carrier voided the claim.                   |
| `NOT_ABLE_TO_CONTACT_DESTINATARY` | We weren't able to reach the recipient.         |

Any `REJECTED` reason counts as closed.

## Checking on a claim

```bash theme={null}
curl "https://api.opereit.ai/v1/claims/clm_3Ccox6eQUYYeg9RIo6qXCwGN3nQ" \
  -u "your_key_id:your_key_secret"
```

This returns everything about the claim: its status, the shipment, and the incidence (the claim reason and amount). Poll this if you want to watch a specific claim move through review.

## Listing your claims

```bash theme={null}
curl "https://api.opereit.ai/v1/claims?limit=25&status=UNDER_REVIEW&carrierId=ups" \
  -u "your_key_id:your_key_secret"
```

You can filter by `status`, `carrierId`, `trackingNumber`, and a `fromDate`/`toDate` range on the claim date. Results are paginated, if `pagination.hasMore` is `true`, pass `pagination.cursor` back as the `cursor` query param to get the next page.

## Handling errors

Every error response looks like this:

```json theme={null}
{
  "statusCode": 400,
  "statusReasonCode": "INVALID_REQUEST_BODY",
  "error": "Invalid request body",
  "details": { "...": "only present on 400s" }
}
```

`statusReasonCode` is the one to branch your code on, it won't change wording on you the way `error` might.

| statusReasonCode                                                                                                  | Status | What it means                                                                                                                                                     |
| ----------------------------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INVALID_REQUEST_BODY`                                                                                            | 400    | Something in the request body failed validation, e.g. a bad `carrier`, a missing required field, or a non-positive `claimed_amount`. Check `details.fieldErrors`. |
| `INVALID_QUERY_PARAMETERS`                                                                                        | 400    | A query param on `GET /v1/claims` is invalid, usually an unrecognized `status` or a `limit` outside 1-100.                                                        |
| `CLAIM_NOT_FOUND`                                                                                                 | 404    | No claim with that ID exists for your organization.                                                                                                               |
| `CLAIM_ALREADY_EXISTS`                                                                                            | 409    | There's already an open claim for that tracking number. Contact Opereit support if you need to correct the existing one.                                          |
| `AUTHENTICATION_REQUIRED` / `INVALID_CREDENTIALS_FORMAT` / `INVALID_CREDENTIALS_ENCODING` / `INVALID_CREDENTIALS` | 401    | Something's wrong with your `Authorization` header, missing, malformed, or the credentials themselves aren't valid.                                               |
| `INTERNAL_ERROR`                                                                                                  | 500    | Something broke on our end. Safe to retry; if it keeps happening, send us the claim/tracking number.                                                              |

One thing to watch for on `INVALID_REQUEST_BODY`: `details.fieldErrors` is keyed by `shipment` or `incidence`, not by the specific nested field. So if both your `carrier` and your `line_items` are wrong, they'll both show up as messages under the single `"shipment"` key rather than under `"shipment.carrier"` and `"shipment.line_items"` separately. Read the message text, not just the key.
