> ## Documentation Index
> Fetch the complete documentation index at: https://docs.armin.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from legacy /public

> Move from deprecated /public/* endpoints to /public/v1 with envelope, pagination, and scope changes.

Legacy public endpoints under `/public/*` are **deprecated** and sunset on **31 October 2026**. New integrations should use `/public/v1/*`.

Every legacy response includes deprecation headers:

```
Deprecation: true
Sunset: Fri, 31 Oct 2026 23:59:59 GMT
Link: <https://docs.armin.cx/api/v1/migration>; rel="successor-version"
```

## Why migrate

| Legacy `/public/*`                      | Public API v1 `/public/v1/*`                            |
| --------------------------------------- | ------------------------------------------------------- |
| Inconsistent envelopes                  | Unified `{ success, data }` + structured errors         |
| Offset pagination (`page`, `page_size`) | Cursor pagination (`cursor`, `has_more`, `next_cursor`) |
| Ad-hoc list filters (dates, status)     | Saved views via `view_id`                               |
| Full-access API keys                    | Scoped keys (`tickets:read` default)                    |
| No message thread endpoint              | `GET /tickets/:ticketNumber/messages`                   |
| No saved views listing                  | `GET /views`                                            |

## Base URL change

|        | URL                              |
| ------ | -------------------------------- |
| Legacy | `https://api.armin.cx/public`    |
| v1     | `https://api.armin.cx/public/v1` |

Authentication is unchanged: `cx-api-key` header.

## Response envelope

**Legacy list (example):**

```json theme={null}
{
  "success": true,
  "tickets": [ ... ],
  "page": 1,
  "total_pages": 10
}
```

**v1 list:**

```json theme={null}
{
  "success": true,
  "data": [ ... ],
  "pagination": {
    "has_more": true,
    "next_cursor": "..."
  }
}
```

**Legacy error:**

```json theme={null}
{
  "success": false,
  "message": "Something went wrong",
  "error": "..."
}
```

**v1 error:**

```json theme={null}
{
  "success": false,
  "code": "VALIDATION_ERROR",
  "message": "Validation failed",
  "request_id": "req_..."
}
```

Branch on `code`, not `message`. See [Errors](/api/errors).

## Pagination migration

| Legacy                              | v1                                                               |
| ----------------------------------- | ---------------------------------------------------------------- |
| `page=2&page_size=50`               | `cursor=<next_cursor>&limit=50`                                  |
| `total_pages` / total count in body | `pagination.has_more` + `next_cursor` (no total on ticket lists) |
| Re-fetch page 1 to poll             | Cursor walk + backoff; use view `count` for totals               |

See [Pagination](/api/pagination).

## Endpoint mapping

| Legacy endpoint                         | v1 equivalent                                                 | Notes                                             |
| --------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------- |
| `GET /public/tickets` (list)            | `GET /public/v1/views` + `GET /public/v1/tickets?view_id=...` | Encode list filters in a saved view               |
| `GET /public/tickets` (by filters/date) | Saved view + `view_id`                                        | No `date_from` / `date_to` on v1 list             |
| `GET /public/tickets/:id` (if used)     | `GET /public/v1/tickets/:ticketNumber`                        | v1 uses numeric **ticket number** in the path     |
| —                                       | `GET /public/v1/tickets/:ticketNumber/messages`               | **New** — conversation thread for agents          |
| —                                       | `GET /public/v1/views`                                        | **New** — discover saved views                    |
| `POST /public/tickets`                  | *No v1 equivalent*                                            | Stay on legacy until v2; requires `tickets:write` |
| `POST /public/tickets/export`           | *No v1 equivalent*                                            | Stay on legacy; requires `tickets:export`         |
| `GET /public/tickets/statistics`        | *No v1 equivalent*                                            | Stay on legacy; requires `analytics:read`         |
| `GET /public/agents/metrics`            | *No v1 equivalent*                                            | Stay on legacy; requires `analytics:read`         |

## Scopes during migration

Create new keys with explicit scopes:

| Integration type       | Recommended scopes                |
| ---------------------- | --------------------------------- |
| Read-only agent / sync | `tickets:read` only               |
| Legacy create ticket   | `tickets:read` + `tickets:write`  |
| Legacy export          | `tickets:read` + `tickets:export` |
| Legacy analytics       | `tickets:read` + `analytics:read` |

Keys with empty `scopes` (pre-migration) still have full access until rotated.

## Migration checklist

<Steps>
  <Step title="Audit legacy usage">
    List which `/public/*` endpoints your integration calls today.
  </Step>

  <Step title="Create scoped v1 key">
    [Settings → API](https://armin.cx/app/_/settings/api) — `tickets:read` for read paths.
  </Step>

  <Step title="Map filters to views">
    For each legacy list filter, create or identify a matching [saved inbox view](/inbox/views-and-filters).
  </Step>

  <Step title="Update client code">
    Switch base URL, envelope parsing, and pagination to cursor model.
  </Step>

  <Step title="Add message/thread fetch">
    Replace custom workarounds with `GET /tickets/:ticketNumber/messages`.
  </Step>

  <Step title="Test in staging">
    Verify view access for agent-linked keys vs service keys.
  </Step>

  <Step title="Deploy and rotate">
    Deploy v1 client, then delete legacy-only API keys.
  </Step>
</Steps>

## Documentation and tools

<CardGroup cols={2}>
  <Card title="OpenAPI v1 reference" icon="book" href="https://api.armin.cx/docs/v1">
    Interactive Scalar docs for all v1 endpoints.
  </Card>

  <Card title="Legacy OpenAPI" icon="book-open" href="https://api.armin.cx/docs">
    Deprecated `/public/*` reference (sunset Oct 2026).
  </Card>

  <Card title="Getting started" icon="rocket" href="/api/getting-started">
    First v1 request walkthrough.
  </Card>

  <Card title="Agent tool examples" icon="robot" href="/api/agent-tool-examples">
    AI agent patterns on v1.
  </Card>
</CardGroup>

## Timeline

| Date           | Event                                                |
| -------------- | ---------------------------------------------------- |
| v1 GA          | `/public/v1/*` recommended for all new integrations  |
| **2026-10-31** | Legacy `/public/*` sunset — endpoints may be removed |

<Warning>
  Plan migration before the sunset date. Legacy write, export, and analytics endpoints have no v1 replacement yet — keep scoped legacy keys only for those calls until v2.
</Warning>
