Claim Messages
Use one webhook for the whole claim. File the claim with POST /claims, then handle the events below. The same events are available on every account. Follow-up text is also emailed. The webhook is how your system receives it.
Store each event by its id. EasyPost may deliver the same event more than once.
description is the event name. result is the payload.
claim.message,directionoutbound. Showbodyand any attachments. Collect the reply in your system.claim.message,directioninbound. A customer reply, from this API or from email. Use the messageidto recognize one you already stored.claim.approved. Showapproved_amount. Ifstatusisapproved_partial, that amount is all that will be paid.claim.rejected. Showstatus_detail. That sentence is the denial reason.claim.submitted,claim.updated, andclaim.cancelled. Update the claim fromstatus.
On claim.message, result is a message (cmsg_...). On the other events, result is the Claim (clm_...).
1{
2 "description": "claim.message",
3 "result": {
4 "id": "cmsg_8f0c1c2e4b6a4d0a9c1e2f3a4b5c6d7e",
5 "object": "ClaimMessage",
6 "mode": "production",
7 "claim_id": "clm_09d89e88a0c943d59018bc26b041c41c",
8 "direction": "outbound",
9 "body": "This ticket is being handled by our Automated Insurance Claim Assistant.\n\nSend proof of purchase that shows the completed purchase, line items, and total — an invoice, receipt, checkout thank-you screenshot, or order-confirmation email. This is required; the claim may be rejected if you cannot provide it:\n\n- the purchase invoice or receipt — so we can confirm the item and its value — this is required, and the claim may be rejected without it (for example, a checkout thank-you screenshot or order confirmation email that shows the completed purchase, line items, and total)",
10 "attachments": [],
11 "created_at": "2026-09-26T17:04:11Z",
12 "updated_at": "2026-09-26T17:04:11Z"
13 }
14}Show status_detail as written. When EasyPost knows what was missing or unclear, the sentence names it.
1{
2 "description": "claim.rejected",
3 "result": {
4 "id": "clm_09d89e88a0c943d59018bc26b041c41c",
5 "object": "Claim",
6 "status": "rejected",
7 "status_detail": "We could not approve this claim because we did not receive a purchase invoice or receipt that shows the item and its value.",
8 "approved_amount": null
9 }
10}The same sentence names other gaps. For example: "We could not approve this claim because the damage photo did not show the item clearly enough to review." When EasyPost does not know the gap, status_detail is "Insufficient evidence", "Item not covered under policy", "Claim filed outside the allowed window", "Required information was not provided", or "Claim does not meet policy requirements".
GET /claims/:id returns the same status and reason if you missed the webhook.
POST /claims/:id/messages
Send the seller's text in body and files in attachments as base64 images or PDFs, the same way you attach files when creating a claim. Include idempotency_key, up to 64 ASCII characters, so a retry does not file the reply twice. A retry sent while the first request is still being delivered returns 409; send it again with the same key.
1curl -X POST https://api.easypost.com/v2/claims/clm_.../messages \
2 -u "EASYPOST_API_KEY": \
3 -H "Content-Type: application/json" \
4 -d '{
5 "body": "Here is the order confirmation showing the item and the total.",
6 "attachments": ["REPLACE_WITH_BASE64_STRING"],
7 "idempotency_key": "order-confirmation-1"
8 }'EasyPost adds that reply to the claim, including when a person is handling it. The next question arrives as another claim.message event.
GET /claims/:id/messages lists the thread oldest first if you missed
a webhook. Use before_id or after_id, not both.
A test API key stores the reply and sends a test-mode event. In production, retry if the claim is not ready to receive messages yet. A cancelled claim cannot take a reply.