# Report a problem to Eto

> Eto API reference for `POST /api/v1/reports`. Base URL `https://eto.tools/api/v1/`. Authenticate with the `X-Eto-API-Key` header.

Part of the [Eto API reference](https://eto.tools/dev/docs/). The full reference in one file is at [llms-full.txt](https://eto.tools/dev/docs/llms-full.txt); the machine-readable schema is at [openapi.json](https://eto.tools/dev/docs/openapi.json).

## POST /api/v1/reports

Report a problem to Eto

- Operation ID: `report_issue`
- Slug: `report-issue`
- Category: Support
- Authentication: API key only. Reads or writes data Eto holds for your own account.
- HTML: https://eto.tools/dev/docs/#ep-report-issue
- Markdown: https://eto.tools/dev/docs/support/report-issue.md

Send an error, bug, feature request, question or feedback straight to the Eto team. Use it when a call fails and the error is not explained by your own input: every error response carries a `request_id`, and Eto has already recorded the full request, response and Etsy's own answer under that id. Put the ids in `request_ids` and say what you were doing, what you expected and what happened. Does not use the daily API quota; up to 30 reports an hour. Secrets in the body are redacted before storage.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `title` | body | `string` | yes | One line: what went wrong or what you need. Constraints: max 200 chars. |
| `explanation` | body | `string` | yes | What you were doing, what happened, and why it looks wrong. Plain text or Markdown. Constraints: max 20,000 chars. |
| `kind` | body | `string` | no | What this is. error: a call failed. bug: wrong result without an error. Default: `error`. One of: `error`, `bug`, `feature_request`, `question`, `feedback`. |
| `request_ids` | body | `array` | no | The request_id of each failed call (from the error body or the X-Eto-Request-Id header). Constraints: max 20. |
| `endpoint` | body | `string` | no | The call involved, e.g. "PUT /api/v1/listings/123/inventory". |
| `expected` | body | `string` | no | What you expected to happen. |
| `actual` | body | `string` | no | What happened instead. |
| `steps` | body | `string` | no | Steps to reproduce. |
| `request` | body | `object` | no | The body you sent, if relevant. |
| `response` | body | `object` | no | The response you got, if relevant. |
| `logs` | body | `string` | no | Relevant log lines or a stack trace from your side. Constraints: max 64 KB. |
| `agent` | body | `object` | no | Who is reporting: {"name", "model", "client", "version"}, e.g. {"name": "Claude Code", "model": "claude-opus-5-5"}. |
| `contact` | body | `string` | no | Optional email or handle for a follow-up. |

### Request

```bash
curl -X POST -H "X-Eto-API-Key: eto_your_key" -H "Content-Type: application/json" -d '{"kind": "error", "title": "Inventory PUT returns 502 for my own listing", "explanation": "Repricing listing 4554228175 in shop 64440680. GET inventory works, PUT with the same products and a new price returns UPSTREAM_ERROR.", "request_ids": ["req_3f9c0a1b2c3d4e5f6a7b"], "endpoint": "PUT /api/v1/listings/4554228175/inventory", "expected": "200 and the new price", "actual": "502 UPSTREAM_ERROR", "agent": {"name": "Claude Code", "model": "claude-opus-5-5"}}' "https://eto.tools/api/v1/reports"
```

```python
import requests

url = "https://eto.tools/api/v1/reports"
headers = {"X-Eto-API-Key": "eto_your_key"}
payload = {
    "kind": "error",
    "title": "Inventory PUT returns 502 for my own listing",
    "explanation": "Repricing listing 4554228175 in shop 64440680. GET inventory works, PUT with the same products and a new price returns UPSTREAM_ERROR.",
    "request_ids": [
        "req_3f9c0a1b2c3d4e5f6a7b"
    ],
    "endpoint": "PUT /api/v1/listings/4554228175/inventory",
    "expected": "200 and the new price",
    "actual": "502 UPSTREAM_ERROR",
    "agent": {
        "name": "Claude Code",
        "model": "claude-opus-5-5"
    }
}

response = requests.post(url, headers=headers, json=payload, timeout=120)
response.raise_for_status()
print(response.json())
```

```javascript
const url = "https://eto.tools/api/v1/reports";
const payload = {
  "kind": "error",
  "title": "Inventory PUT returns 502 for my own listing",
  "explanation": "Repricing listing 4554228175 in shop 64440680. GET inventory works, PUT with the same products and a new price returns UPSTREAM_ERROR.",
  "request_ids": [
    "req_3f9c0a1b2c3d4e5f6a7b"
  ],
  "endpoint": "PUT /api/v1/listings/4554228175/inventory",
  "expected": "200 and the new price",
  "actual": "502 UPSTREAM_ERROR",
  "agent": {
    "name": "Claude Code",
    "model": "claude-opus-5-5"
  }
};

const response = await fetch(url, {
  method: "POST",
  body: JSON.stringify(payload),
  headers: {
    "X-Eto-API-Key": "eto_your_key",
    "Content-Type": "application/json",
  },
});
if (!response.ok) throw new Error(`Eto API ${response.status}`);
const data = await response.json();
```

### Response

```json
{
  "success": true,
  "report": {"id": "rep_9a8b7c6d5e4f3a2b", "kind": "error", "status": "new", "reply": "",
             "linked_request_ids": ["req_3f9c0a1b2c3d4e5f6a7b"], "unmatched_request_ids": []},
  "message": "Received. The Eto team sees this report together with the recorded detail of every linked request."
}
```

### Errors

Failures answer with the shared error body described in the Errors section: `{"error": {"code", "status", "message", "hint", "docs"}}`. Branch on `code`, not on the message.
