# HTTP — `GET /v1/userFills`

Durable confirmed fills for a user over an inclusive time range. Public
endpoint.

```http
GET /v1/userFills?user=0x0000000000000000000000000000000000000001&startTime=1780000000000&endTime=1780003600000
```

| Param | Required | Meaning |
| --- | --- | --- |
| `user` | yes | EVM address. Missing fails with `invalid_query`; malformed with `bad_request`. |
| `startTime` | yes | Inclusive start, Unix milliseconds. Missing fails with `invalid_query`. |
| `endTime` | no | Inclusive end, Unix milliseconds; defaults to now. `startTime > endTime` fails with `invalid_time_range`. |
| `cursor` | no | Opaque cursor from a prior response. Unparseable values fail with `invalid_cursor`. |

```jsonc
{
  "status": "ok",
  "data": {
    "user": "0x0000000000000000000000000000000000000001",
    "userFills": [
      {
        "fillId": "123456",
        "orderId": "2a4d4983-9057-4da9-bcd7-0aa0e4185bb0",
        "cloid": "0x00000000000000000000000000000001",
        "a": "BTC",
        "venue": "lighter",
        "b": "buy",
        "size": "0.01",
        "price": "65000",
        "liquidityRole": "maker",
        "fees": { "exchange": "0", "mosaiq": "0.195" },
        "createdAtMs": 1780000100000
      }
    ],
    "nextCursor": "uf1_42",
    "hasMore": false
  },
  "server_time_ms": 1780003600100
}
```

Rows follow Mosaiq's durable application order, not event time, so
`createdAtMs` can decrease between rows. `(venue, fillId)` identifies a fill;
fill ID spaces differ per venue. `fees` is absent when the fee settlement row
is not yet available.

## Pagination

A page holds at most 500 fills. While `hasMore` is `true`, repeat the same
query with `cursor=nextCursor` and the same `startTime`. When `hasMore` is
`false`, `nextCursor` covers every fill durable when the response started;
reuse it to poll for later commits in the same window, including late commits
with an older `createdAtMs`.

## WebSocket recovery

The `userFills` topic does not replay a gap. After a disconnect, subscribe
again and buffer live fills, query this endpoint with a conservative inclusive
`startTime`, follow `nextCursor` until `hasMore` is `false`, merge, and
deduplicate by `(venue, fillId)`.
