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

# GET /v1/diff/{from}/{to} — Ad-hoc version diff

> Returns an item-level diff between two arbitrary historical Valorant versions. Serves a precomputed diff when available, otherwise computes one on demand.

The `/v1/diff/{from}/{to}` endpoint returns an item-level diff between any two version directories the server still retains. It first looks for a precomputed `diff-from-{from}.json` inside the `to` version directory; if there isn't one, it computes the diff on demand.

Use this endpoint when you need a diff that isn't simply "the latest" — for example, replaying a sequence of patches against an older cache or comparing a specific historical pair.

## Endpoint

```
GET https://astra.teamfortuna.xyz/v1/diff/{from}/{to}
```

## Path parameters

<ParamField path="from" type="string" required>
  Manifest ID of the older version. Must match `^[A-Za-z0-9._-]+$`, be 1–128 characters, and must not start with a dot or equal `current` (those names are reserved for pipeline internals).
</ParamField>

<ParamField path="to" type="string" required>
  Manifest ID of the newer version. Same validation rules as `from`.
</ParamField>

## Request

The `User-Agent` header is required for all requests to the Astra API. Use the format `AppName/Version (+URL)`.

```bash theme={null}
curl https://astra.teamfortuna.xyz/v1/diff/VAL_12.06/VAL_12.07 \
  -H "User-Agent: MyApp/1.0 (+https://example.com)"
```

## Response fields

<ResponseField name="status" type="number">
  HTTP status code of the response (e.g. `200`).
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="properties" defaultOpen>
    <ResponseField name="fromVersion" type="string">
      Manifest ID of the `from` version.
    </ResponseField>

    <ResponseField name="toVersion" type="string">
      Manifest ID of the `to` version.
    </ResponseField>

    <ResponseField name="generatedAt" type="string">
      ISO 8601 timestamp of when the diff was generated. For precomputed diffs, this is the pipeline run time; for on-demand diffs, it is the request time.
    </ResponseField>

    <ResponseField name="categories" type="object">
      Map of category name (`agents`, `weapons`, etc.) to a category diff with `added`, `removed`, and `changed` arrays. `added` and `removed` contain UUIDs; `changed` contains objects with the `uuid` and the sorted list of top-level `fields` whose serialized value differs.
    </ResponseField>

    <ResponseField name="summary" type="object">
      <Expandable title="properties">
        <ResponseField name="totalAdded" type="number">
          Total number of added items across all categories.
        </ResponseField>

        <ResponseField name="totalRemoved" type="number">
          Total number of removed items across all categories.
        </ResponseField>

        <ResponseField name="totalChanged" type="number">
          Total number of changed items across all categories.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

## Response

```json theme={null}
{
  "status": 200,
  "data": {
    "fromVersion": "VAL_12.06",
    "toVersion": "VAL_12.07",
    "generatedAt": "2026-04-22T14:25:22.602Z",
    "categories": {
      "agents": {
        "added": [],
        "removed": [],
        "changed": [
          {
            "uuid": "8e9aa2e9-0e34-4d59-b2b3-9a8a7b6c5d4e",
            "fields": ["abilities"]
          }
        ]
      }
    },
    "summary": {
      "totalAdded": 0,
      "totalRemoved": 0,
      "totalChanged": 1
    }
  }
}
```

## Errors

<ResponseField name="400" type="status">
  Returned when either `from` or `to` is empty, longer than 128 characters, contains characters outside `[A-Za-z0-9._-]`, equals `.`/`..`, starts with a dot, or equals `current`.
</ResponseField>

<ResponseField name="404" type="status">
  Returned when either version directory does not exist on disk. Older versions are pruned by retention.
</ResponseField>

<ResponseField name="500" type="status">
  Returned when a precomputed diff file exists but is unreadable or corrupt.
</ResponseField>

<Tip>
  When the same diff is requested repeatedly, prefer the precomputed path: ask for the exact `from`/`to` pair the pipeline already wrote (each version dir has a single `diff-from-{prev}.json`). On-demand diffs are computed per request and are more expensive.
</Tip>
