# List recent requests in the key's project, or in every project of its organization

> Per-request records from the ephemeral request log, newest first, for the API key's project (every key in that project, not only this key).

Source: https://docs.spicrawl.com/api-reference/requests/requests-list

## GET /v1/requests

Operation ID: `requestsList`. API key scope: `none`.

Per-request records from the ephemeral request log, newest first, for the API key's project (every
key in that project, not only this key). With `all_projects=true` and a key carrying the `read`
scope, the records of every project in the key's organization (archived projects included), merged
into one newest-first list under the same cursor. Every record carries `project_id`. Records expire
after `page.retention_hours`; for durable billing totals use `GET /v1/usage`. Totals here will not
match an invoice.

Pitfalls:
- Page with BOTH `before` and `before_id` copied from `page.next_before` / `page.next_before_id`.
  `before` alone re-returns the boundary record and cannot break same-millisecond ties; `before_id`
  alone does not bound the page at all.
- A cursor older than the retention window returns 410 `ERR::REQUEST::BEYOND_RETENTION`. Restart
  from the first page.
- An empty `data` means "nothing in the last `retention_hours`", not "never". Check `retained_since`.
- A page can be shorter than `limit` while `has_more` is true. Keep paging until `has_more` is false.
- `limit` is clamped silently: missing, non-numeric or non-positive gives 50, above 200 gives 200.
- `all_projects=true` without the `read` scope is 403 `ERR::AUTH::INSUFFICIENT_SCOPE`, naming `read`.
  The default list needs no scope beyond a valid key. The organization is always the key's own;
  no parameter names another.
- Keep `all_projects=true` on every page of one walk: the cursor pages whichever list it came from.

### Example

```bash
curl "https://api.spicrawl.com/v1/requests" \
  -H "Authorization: Bearer $SPICRAWL_API_KEY"
```

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `all_projects` | query | string: `true`, `false`; default `"false"` | no | When `true`, lists every project in the key's organization instead of only the key's project. Requires the `read` scope (403 `ERR::AUTH::INSUFFICIENT_SCOPE` without it). Only `true` and `false` are accepted; any other value is 400. |
| `limit` | query | integer; default `50` | no | Page size. Never refused; invalid values fall back to 50 and values above 200 become 200. |
| `status` | query | string: `success`, `failed`, `timeout`, `blocked`, `rejected`, `cancelled` | no | Only records with exactly this status. Not validated; an unknown value returns an empty page. Ignored when `only_errors=true`. |
| `only_errors` | query | string: `true`, `false`; default `"false"` | no | When exactly `true`, returns every record whose status is not `success`. Any other value (including `1`) is treated as false. |
| `before` | query | string (date-time) | no | Cursor time, RFC 3339 with optional fractional seconds, copied from `page.next_before`. Must be sent together with `before_id`. |
| `before_id` | query | string | no | Cursor id, copied from `page.next_before_id`. Must be sent together with `before`. |

### Responses

#### 200

One page of request records plus the retention facts needed to interpret it.

`application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `data` | array of object (`RequestLogEntry`) | yes | Records, newest first. Can be shorter than `limit` even when `has_more` is true. |
| `page` | object (`RequestLogPageInfo`) | yes |  |

Example `page`

```json
{
  "data": [
    {
      "id": "01M0FK1EP2E7FBMWAR7W10SMXW",
      "created_at": "2026-09-22T12:41:22.183Z",
      "project_id": "01M0FJZ8Q3W4B5T8J2V9K6X1RD",
      "engine": "chromium",
      "status": "blocked",
      "http_status": 403,
      "error_code": "ERR::UPSTREAM::CHALLENGE",
      "error_detail": "The target served an Akamai challenge page.",
      "attempts": 2,
      "url": "https://shop.example.com/p/123",
      "url_host": "shop.example.com",
      "proxy": {
        "source": "pool",
        "endpoint_id": "dc-198.51.100.7-6646",
        "requested_tier": "datacenter",
        "requested_country": "de",
        "country": "de",
        "endpoints": [
          "dc-198.51.100.9-6646",
          "dc-198.51.100.7-6646"
        ]
      },
      "spans": {
        "admission_ms": 2,
        "dispatch_ms": 4731,
        "worker_ms": 4718,
        "queue_ms": 0,
        "engine_ms": 4706,
        "upstream_ms": null,
        "extract_ms": null,
        "total_ms": 4735
      },
      "blocked": {
        "vendor": "akamai",
        "signal": "\"Access Denied\"",
        "rule": "body_marker"
      },
      "bytes_in": 18231,
      "credits_micro": 0
    }
  ],
  "page": {
    "retention_hours": 24,
    "retained_since": "2026-09-21T12:45:00Z",
    "has_more": true,
    "next_before": "2026-09-22T12:41:22.183Z",
    "next_before_id": "01M0FK1EP2E7FBMWAR7W10SMXW"
  }
}
```

#### 400

The request is invalid. Not retryable; fix the request using `code` and `diagnostics.hint`.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 401

Missing, invalid, revoked or expired key. Not retryable with the same key.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 403

`all_projects=true` from a key without the `read` scope (`ERR::AUTH::INSUFFICIENT_SCOPE`, naming `read`).

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 410

The resource existed but is past its retention window or was purged. Not retryable.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 500

Internal error. Retryable when `retryable` is true.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

Full OpenAPI spec: https://docs.spicrawl.com/openapi.yaml
