# List changes

> Returns every public-field change to a listing since since, oldest first.

Source: https://api.tailend.dev/docs/api/list-changes

```http
GET https://api.tailend.dev/v1/changes
X-API-Key: $TAILEND_API_KEY
```

Returns every public-field change to a listing since `since`,
oldest first. To sync incrementally, keep the last `version_id` you
saw and pass it as `cursor`. Removals (`status` leaving `published`,
`is_active` becoming `false`, or a hard delete) appear here even
though the resource itself returns `404`.

Each item exposes only the change time, a closed change kind, and
allowlisted public field names. Values, actors, pipeline attributes,
and rows that touch only internal fields are never returned. Read
freshness from `source.crawled_at` (`include=source`) on the resource.

Authorization: send your key in the `X-API-Key` header. Available on every plan.

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `since` | string (date-time) | yes | Return changes with changed_at strictly after this instant. |
| `metro` | string | no | Restrict to one metro slug (must be in the key's scope). |
| `type` | string | no | Restrict to one listing type. |
| `cursor` | string | no | This is not an opaque cursor: pass back the decimal string returned by meta.next_cursor, and the feed resumes strictly after it. |
| `limit` | integer | no |  |

## Example request

```bash
curl -sS \
  -H "X-API-Key: $TAILEND_API_KEY" \
  "https://api.tailend.dev/v1/changes?since=2026-10-01T00%3A00%3A00Z"
```

## Responses

### 200

A page of changes

```json
{
  "data": [
    {
      "version_id": 18231,
      "listing_id": "2f3c9d4e-3d2b-4b7d-9a3e-1b2c3d4e5f60",
      "slug": "storytime-in-the-park-2026-09-12",
      "type": "event",
      "metro": "philadelphia",
      "changed_at": "2026-09-10T06:12:05Z",
      "kind": "date_changed",
      "fields": [
        "starts_at"
      ]
    }
  ],
  "meta": {
    "limit": 1,
    "count": 1,
    "has_more": false
  }
}
```

### 400

Malformed or contradictory parameters (lat without lng, to before from, unknown category), or a cursor this API did not issue for this exact request — replayed from another endpoint, resource, metro or filter set, hand-crafted, or altered.

```json
{
  "error": {
    "code": "bad_request",
    "message": "radius_m: must be at least 100",
    "details": {
      "param": "radius_m"
    },
    "request_id": "req_dfbc3295a8382b05"
  }
}
```

### 401

Missing, unknown or revoked X-API-Key.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "missing X-API-Key header",
    "request_id": "req_90e63908273f6bff"
  }
}
```

### 403

Two different reasons share this status.

```json
{
  "error": {
    "code": "forbidden",
    "message": "key is not scoped to metro 'boston'",
    "details": {
      "metros": [
        "philadelphia"
      ]
    },
    "request_id": "req_9e7a750acef48ab2"
  }
}
```

### 405

The path exists; the method does not.

```json
{
  "error": {
    "code": "method_not_allowed",
    "message": "POST is not allowed on this path; this API is read-only",
    "details": {
      "allow": [
        "GET",
        "HEAD",
        "OPTIONS"
      ]
    },
    "request_id": "req_01J9Z3"
  }
}
```

### 429

A limit was reached.

```json
{
  "error": {
    "code": "rate_limited",
    "message": "3 requests per minute exceeded",
    "request_id": "req_06bfd3c2d5e8aa9f"
  }
}
```

### 500

A bug on our side.

```json
{
  "error": {
    "code": "internal",
    "message": "internal error",
    "request_id": "req_01J9Z3"
  }
}
```

### 501

This endpoint or feature is not available and will not become available without a configuration change — for ?address=, this means no geocoder is configured.

```json
{
  "error": {
    "code": "not_implemented",
    "message": "this endpoint is not enabled on this deployment; it is not a fault and retrying will not help",
    "request_id": "req_01J9Z3"
  }
}
```

### 503

A transient outage: a dependency could not be reached or did not answer in time.

```json
{
  "error": {
    "code": "unavailable",
    "message": "the service is temporarily unable to serve this request; retry after the interval in Retry-After",
    "request_id": "req_01J9Z3"
  }
}
```
