# Request logs

> Every API call your keys made in the last 14 days, with redacted bodies for errors, in the dashboard and the API.

Source: https://tickwire.io/docs/request-logs/

Tickwire records every authenticated call to its API, so you can see what your
integration actually sent and what it got back, without adding logging of your own. Open
**Logs** in the dashboard, read them with `GET /v1/request-logs`, or follow them in your terminal
with [`tickwire logs tail -f`](https://tickwire.io/docs/cli/#logs-tail-your-request-log).

## What each entry holds

| Field | Meaning |
|---|---|
| `id` | The entry id (`req_…`). |
| `requestId` | The `X-Request-ID` of the call; quote it to support. |
| `createdAt` | When the call arrived (UTC). |
| `method`, `path`, `route` | The call. `path` never includes the query string; `route` is its template, e.g. `/users/current/accounts/{accountId}/positions`. |
| `status`, `errorCode` | The HTTP status and, for errors, the [error code](https://tickwire.io/docs/errors/). |
| `latencyMs` | Time until the whole answer was sent. |
| `outcome` | `completed`, or `aborted` when the answer was cut short: the upstream broke off, or your client disconnected before reading it all. |
| `keyId`, `accountId` | The API key (its id, never its value) and the trading account. |
| `apiVersion`, `rateLimitBucket` | The version that served the call, and the rate-limit bucket it drew on. |
| `clientIp`, `userAgent` | Where the call came from. |

WebSocket sessions are logged too (`kind: "websocket"`), when they end.

## Bodies: errors only, redacted

For calls that failed (status 400 or above), the entry also keeps short excerpts of the request
and response bodies (`requestBody`, `responseBody`, at most 2 KiB each). Successful calls never
keep a body.

- Only JSON objects and form bodies (`application/x-www-form-urlencoded`) are kept. XML,
  multipart uploads, JSON arrays and plain text are never stored.
- Every value under a name that may hold a secret is replaced by `[REDACTED]`: passwords, PINs,
  one-time codes, keys, secrets, tokens, authorization headers, cookies, sessions and signatures,
  at any depth. Free text is scrubbed of `name=value` pairs and of anything that looks like a
  credential (API keys, bearer tokens, JWTs), including URL-encoded and escaped forms.
- When a body cannot be redacted with certainty, no excerpt is kept at all.
- Bodies with a lot of text (roughly more than 16,000 characters of keys and strings) get no
  excerpt, and under heavy error load some entries may be kept without one. The rest of the
  entry is always recorded.

**Who can see bodies.** In the dashboard, owners and admins. Members and viewers see the entry
without its bodies. Through the API, a full-access key with the writer role; other credentials
get the entry with `excerptsHidden: true`.

## Retention and limits

Entries are kept for **14 days**, within limits set by your plan; when a limit is reached, the
oldest entries go first.

| Organisation | Entries | Storage |
|---|---|---|
| Sandbox | 2,000 | 2 MiB |
| No paid subscription (trial, unpaid, cancelled) | 10,000 | 16 MiB |
| Paid subscription | 100,000 | 128 MiB |

Sizes are counted in UTF-8 bytes. If the service's total request-log storage nears its limit
(90 %), new entries keep their metadata but no body excerpts until space is freed. If it is
full, entries are removed first from the organisations furthest over a fair share of the total,
sandbox organisations first, then those without a paid subscription; a paid organisation's
entries are only removed once every lower tier is at or below its share, and never below that
share. Calls to `/v1/request-logs` itself are not logged.

## API

```http
GET /v1/request-logs?status=errors&limit=50
```

Filters: `status` (`404`, `4xx`, `5xx`, `errors` or `aborted`), `method`, `route` (part of the
path or template), `errorCode`, `keyId`, `accountId`, `requestId`, `since` and `until` (ISO 8601).
Answers `{data, nextCursor, hasMore}`, newest first; pass `cursor=<nextCursor>` for the next page.

```http
GET /v1/request-logs/summary?hours=24
GET /v1/request-logs/{id}
```

The summary gives totals, the error rate and the most frequent error codes and routes. An unknown
id answers [`request_log_not_found`](https://tickwire.io/docs/errors/request_log_not_found/).
