# Support — Eto API

> Report errors, bugs and requests straight to the Eto team, and read their replies.

Base URL `https://eto.tools/api/v1/`. Every request carries the `X-Eto-API-Key` header. Part of the [Eto API reference](https://eto.tools/dev/docs/).

## Endpoints in this category

- [POST /api/v1/reports](https://eto.tools/dev/docs/support/report-issue.md): Report a problem to Eto
- [GET /api/v1/reports](https://eto.tools/dev/docs/support/reports-list.md): List your reports
- [GET /api/v1/reports/{report_id}](https://eto.tools/dev/docs/support/report-detail.md): Get one report

## 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.


## GET /api/v1/reports

List your reports

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

Your reports, newest first, with their status (new, seen, resolved, wont_fix) and the Eto team's reply. Check here before sending a duplicate.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | `string` | no | Only reports in this state. One of: `new`, `seen`, `resolved`, `wont_fix`. |
| `limit` | query | `integer` | no | Page size. Default: `25`. Constraints: max 100. |
| `offset` | query | `integer` | no | Pagination offset. Default: `0`. |

### Request

```bash
curl -H "X-Eto-API-Key: eto_your_key" "https://eto.tools/api/v1/reports?status=resolved"
```

```python
import requests

url = "https://eto.tools/api/v1/reports?status=resolved"
headers = {"X-Eto-API-Key": "eto_your_key"}

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

```javascript
const url = "https://eto.tools/api/v1/reports?status=resolved";

const response = await fetch(url, {
  method: "GET",
  headers: {
    "X-Eto-API-Key": "eto_your_key",
  },
});
if (!response.ok) throw new Error(`Eto API ${response.status}`);
const data = await response.json();
```

### Response

`application/json`. This endpoint has no worked response example in the registry yet; the [HTML reference](https://eto.tools/dev/docs/#ep-reports-list) shows the fields it returns.

### 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.


## GET /api/v1/reports/{report_id}

Get one report

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

One of your reports in full: explanation, details, logs, status and the Eto team's reply.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `report_id` | path | `string` | yes | The report id (rep_...). |

### Request

```bash
curl -H "X-Eto-API-Key: eto_your_key" "https://eto.tools/api/v1/reports/rep_9a8b7c6d5e4f3a2b"
```

```python
import requests

url = "https://eto.tools/api/v1/reports/rep_9a8b7c6d5e4f3a2b"
headers = {"X-Eto-API-Key": "eto_your_key"}

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

```javascript
const url = "https://eto.tools/api/v1/reports/rep_9a8b7c6d5e4f3a2b";

const response = await fetch(url, {
  method: "GET",
  headers: {
    "X-Eto-API-Key": "eto_your_key",
  },
});
if (!response.ok) throw new Error(`Eto API ${response.status}`);
const data = await response.json();
```

### Response

`application/json`. This endpoint has no worked response example in the registry yet; the [HTML reference](https://eto.tools/dev/docs/#ep-report-detail) shows the fields it returns.

### 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.
