Documentation

Cajari Cases API

Read endpoints are live. Listing cases, reading a case thread, the ASIN/shipment/category filters, attachment downloads, and the new-reply webhook are available now. The write endpoints (replying to a case and the submission tracker, further below) are still in design and not yet available; their shape may change before release.
The Cases API is enabled per merchant-marketplace on request right now. Contact us to turn it on for your account.

Overview

The Cases API exposes your Amazon Seller Central support, compliance, and account-health cases as an API (and matching MCP tools), scoped to your account like the rest of the Cajari API.

It has two halves that behave differently:

  • Reads are fast. Listing cases and reading a case thread are served from a continuously-refreshed mirror, so they return immediately. Every response includes a synced_at timestamp telling you how fresh the data is.
  • Writes are asynchronous. Replying to a case drives Amazon's own flow behind the scenes, which is not a real-time request/response. A write returns a submission you can track: we acknowledge receipt, then attempt it, and record the outcome. You poll the submission (or receive a webhook) for the result.

Authentication

Same as the rest of the Cajari API. Use your API Key as a Bearer token in the HTTP Authorization header. Every call is scoped to your account — cases from other accounts are never visible.

All identifiers are opaque IDs. List endpoints paginate with limit and cursor.

Example Request

curl https://api.cajari.com/v2/cases \
    -H "Authorization: Bearer <your_api_key_here>"
                

Read endpoints

List cases

GET /v2/cases

Lists cases for your account. Defaults to open cases, most-recent reply first.

ParameterDescription
merchant_marketplace_idRestrict to one merchant marketplace. Default: all of your MMs.
statusopen, pending_amazon, pending_merchant, resolved, closed, or all. Default open. Comma-separated for multiple.
categoryFilter to categories: fba_inventory, listing, account_health, feedback, other. Comma-separated.
exclude_categoryExclude categories (e.g. fba_inventory to drop reimbursement claims). Comma-separated.
asinOnly cases referencing this ASIN (matches any ASIN on the case, not just the primary).
shipment_idOnly cases referencing this FBA shipment ID.
updated_sinceOnly cases with activity at/after this ISO-8601 time.
created_sinceOnly cases created at/after this ISO-8601 time.
sortlast_reply_desc (default) or created_desc.
limit, cursorPagination.

Example Request

curl "https://api.cajari.com/v2/cases?status=open&sort=last_reply_desc" \
    -H "Authorization: Bearer <your_api_key_here>"
                

Example Response

{
    "synced_at": "2026-10-08T17:02:11Z",
    "cases": [
        {
            "id": "22451523931",
            "merchant_marketplace_id": "a1b2c3d4",
            "status": "pending_amazon",
            "amazon_status": "PendingAmazonAction",
            "subject": "FBA19L555DM7 - Missing Items from Inbound",
            "asin": "B0XXXXXXXX",
            "asins": ["B0XXXXXXXX"],
            "shipment_id": "FBA19L555DM7",
            "category": "fba_inventory",
            "created_at": "2026-10-07T06:18:53Z",
            "last_reply_at": "2026-10-07T06:19:05Z",
            "escalated": false,
            "synced_at": "2026-10-08T17:02:11Z"
        }
    ],
    "next_cursor": "..."
}
                

status is a normalized value; amazon_status is Amazon's raw value. asin, shipment_id, and category are parsed from the case subject and thread (best-effort; null/other when nothing obvious is found). The list view omits the message thread — fetch a single case for that.


Get a case

GET /v2/cases/{id}

Returns a single case with its full correspondence thread.

Example Response

{
    "id": "22451523931",
    "merchant_marketplace_id": "a1b2c3d4",
    "status": "pending_amazon",
    "amazon_status": "PendingAmazonAction",
    "subject": "FBA19L555DM7 - Missing Items from Inbound",
    "asin": "B0XXXXXXXX",
    "asins": ["B0XXXXXXXX"],
    "shipment_id": "FBA19L555DM7",
    "category": "fba_inventory",
    "created_at": "2026-10-07T06:18:53Z",
    "last_reply_at": "2026-10-07T06:19:05Z",
    "escalated": false,
    "messages": [
        {
            "id": "...",
            "direction": "inbound",
            "author": "Amazon",
            "sent_at": "2026-10-07T06:19:05Z",
            "body": "...",
            "has_attachments": true,
            "attachments": [
                {
                    "file_name": "invoice-12345.pdf",
                    "content_type": "application/pdf",
                    "download_url": "/v2/cases/22451523931/attachments/0A1B2C3D"
                }
            ]
        }
    ],
    "synced_at": "2026-10-08T17:02:11Z"
}
                

Each message lists its attachments' file_name, content_type, and a download_url. We re-host attachments in our own storage (Amazon's URLs expire within minutes), so the link is stable. download_url is null until the file has been captured — we capture attachments for non-resolved cases.

GET a download_url (with your Bearer token) to stream the file back with its original content type.


Write endpoints (asynchronous — not yet available)

These endpoints are still in design and not yet callable; the shape below is proposed and may change.

A write request creates a submission and returns 202 Accepted with the submission in status: received. Poll GET /v2/case_submissions/{id} (or register a webhook) until the submission reaches a terminal status. A write never returns the final result directly.

Reply to a case

POST /v2/cases/{id}/replies

Adds a reply to an existing case. Send an Idempotency-Key header (or client_reference_id) so a retry returns the original submission instead of posting a second reply.

Example Request

curl https://api.cajari.com/v2/cases/22451523931/replies \
    -H "Authorization: Bearer <your_api_key_here>" \
    -H "Idempotency-Key: 9f1c-..." \
    -H "Content-Type: application/json" \
    -d '{"body": "Following up on the reimbursement."}'
                

Example Response (202 Accepted)

{
    "submission": {
        "id": "sub_01J...",
        "type": "reply",
        "case_id": "22451523931",
        "status": "received",
        "handling": null,
        "attempts": 0,
        "received_at": "2026-10-08T17:05:00Z",
        "last_attempt_at": null,
        "completed_at": null,
        "request": { "body": "Following up on the reimbursement." },
        "result": null,
        "error": null,
        "poll_url": "/v2/case_submissions/sub_01J..."
    }
}
                

Get a submission

GET /v2/case_submissions/{id}

The status tracker you poll after a write.

GET /v2/case_submissions lists your submissions, filterable by status, type, case_id, and created_since.

Example Response

{
    "submission": {
        "id": "sub_01J...",
        "type": "reply",
        "case_id": "22451523931",
        "status": "succeeded",
        "handling": "automatic",
        "attempts": 1,
        "received_at": "2026-10-08T17:05:00Z",
        "last_attempt_at": "2026-10-08T17:12:30Z",
        "completed_at": "2026-10-08T17:12:33Z",
        "request": { "body": "Following up on the reimbursement." },
        "result": {
            "case_id": "22451523931",
            "reply_id": "...",
            "message": "Reply posted to Amazon."
        },
        "error": null
    }
}
                

Submission status lifecycle

A submission tells you three things at a glance: that we received your request, whether we have attempted it, and how it ended.

StatusMeaningReceived?Attempted?Result known?
receivedStored and accepted. Not yet worked.YesNoNo
queuedWaiting for a processing window.YesNoNo
processingActively being submitted to Amazon.YesIn progressNo
succeededAmazon accepted it. result is populated.YesYesYes
failedAttempted and rejected, or errored. error is populated. May be retried.YesYesYes
canceledCanceled before completion.YesMaybeYes

Supporting fields: received_at (we accepted it), attempts + last_attempt_at (whether/when we tried), and completed_at + result/error (the outcome). The handling field (automatic, manual, or null) indicates how a submission was processed; it does not change the status flow.

Webhook (optional)

Case notifications go to a dedicated Cases webhook URL, configured separately from your report/result webhook — so these never reach a receiver that only expects report payloads. If no Cases webhook URL is set, nothing is sent (poll instead).

We POST a case event when Amazon activity lands — a new case (case.created) or a new Amazon reply on an existing case (case.reply) — so you're notified within minutes instead of polling. The body is { "event": "...", "sent_at": "...", "case": { ... } } where case is the same object returned by the list endpoint. (Once asynchronous replies are live, their status transitions post here too.)

Requests carry Authorization: Bearer <md5 of your API key> plus X-Cajari-Webhook: case and X-Cajari-Event: case.created|case.reply headers, so even on a shared endpoint they're unambiguous — the report webhook sends no X-Cajari-* headers.


MCP tools

Each endpoint has a matching MCP tool:

  • list_cases
  • get_case
  • reply_to_case — returns a submission
  • get_case_submission
  • list_case_submissions

Availability

The Cases API is being rolled out in stages:

  1. Reads — list and read cases.
  2. Replies — reply to an existing case (asynchronous submission).