# List events

# List events

Returns the calling club's **published** events (main club or co-host), same data as its public results
page's event list.

## Headers

| Header | Required | Value |
|---|---|---|
| `Authorization` | yes | `Bearer <access_token>` |

## Query parameters

| Param | Required | Default | Range |
|---|---|---|---|
| `page` | no | `1` | ≥ 1 |
| `pageSize` | no | `20` | 1–100 |

Full paging rules: [Pagination](/docs/pagination).

#### Request

```bash
curl -s "https://sail-club-server.cloud.run/api/v1/events?page=1&pageSize=20" \
  -H "Authorization: Bearer $TOKEN"
```

```javascript
const res = await fetch('https://sail-club-server.cloud.run/api/v1/events?page=1&pageSize=20', {
  headers: { Authorization: `Bearer ${token}` },
});
if (res.status === 304) { /* use your cached copy */ }
const page = await res.json();
```

```python
res = requests.get(
    "https://sail-club-server.cloud.run/api/v1/events",
    params={"page": 1, "pageSize": 20},
    headers={"Authorization": f"Bearer {token}"},
    timeout=10,
)
res.raise_for_status()
page = res.json()
```

```csharp
var res = await client.GetAsync("/api/v1/events?page=1&pageSize=20");
res.EnsureSuccessStatusCode();
var page = await res.Content.ReadFromJsonAsync<PublicEventPage>();
```

```php
<?php
$ch = curl_init('https://sail-club-server.cloud.run/api/v1/events?page=1&pageSize=20');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"],
]);
$page = json_decode(curl_exec($ch), true);
```

#### Response

```json
{
  "items": [
    {
      "id": "1143117a-9c2b-4e7a-8f1d-2b6a9c4e7f10",
      "name": "Cup Regatta 2026",
      "location": "Datça Marina",
      "startDate": "2026-10-11T09:00:00Z",
      "endDate": "2026-10-12T16:00:00Z",
      "status": "Completed",
      "coverUrl": "https://cdn.sailracing.club/clubs/TRX1001CL/events/cup-regatta-2026/cover.jpg",
      "posterUrl": "https://cdn.sailracing.club/clubs/TRX1001CL/events/cup-regatta-2026/poster.jpg",
      "entryCount": 42
    }
  ],
  "nextPage": null,
  "totalItems": 1
}
```

`200` — `Cache-Control: private, max-age=<n>` · `ETag` · `Last-Modified` · `X-Data-As-Of`. See
[Caching & freshness](/docs/caching). Never 404s or 503s cached.

## Response fields

Full field table: [Data models → Event summary](/docs/data-models#event-summary). Sort: newest `startDate`
first, ties broken by id.

## Errors

| HTTP | Code |
|---|---|
| 400 | [`API_PARAM_INVALID`](/docs/errors#API_PARAM_INVALID) — bad `page`/`pageSize` |
| 401 | [`API_TOKEN_MISSING`](/docs/errors#API_TOKEN_MISSING) / [`API_TOKEN_INVALID`](/docs/errors#API_TOKEN_INVALID) |
| 403 | [`API_SCOPE_MISSING`](/docs/errors#API_SCOPE_MISSING) / [`API_IP_NOT_ALLOWED`](/docs/errors#API_IP_NOT_ALLOWED) |
| 429 | [`RATE_LIMIT_EXCEEDED`](/docs/errors#RATE_LIMIT_EXCEEDED) |
| 503 | [`API_UNAVAILABLE`](/docs/errors#API_UNAVAILABLE) |

## Caching

Cache per `page`/`pageSize` combination you actually call; send `If-None-Match` on repeat calls. See
[Caching & freshness](/docs/caching).

```prompt
Implement listEvents({ page = 1, pageSize = 20 } = {}) for the Sail Club API.

GET https://sail-club-server.cloud.run/api/v1/events?page=<page>&pageSize=<pageSize>
Authorization: Bearer <access_token>  (see the token prompt on /docs/api/token)

Success 200:
  { "items": [ { "id": string, "name": string, "location": string, "startDate": string (ISO 8601),
      "endDate": string, "status": string, "coverUrl": string|null, "posterUrl": string|null,
      "entryCount": number } ], "nextPage": number|null, "totalItems": number }
  Response headers: Cache-Control: private, max-age=<n>; ETag: "<hash>"; Last-Modified; X-Data-As-Of.
  Store the ETag per (page,pageSize) key; send it back as If-None-Match on the next call to the same key.
  A 304 has no body — keep serving your cached items for that key.

Errors: 400 API_PARAM_INVALID (bad page/pageSize) · 401 API_TOKEN_MISSING/API_TOKEN_INVALID (refresh token,
retry once) · 403 API_SCOPE_MISSING/API_IP_NOT_ALLOWED (not retryable — alert a human) · 429
RATE_LIMIT_EXCEEDED / 503 API_UNAVAILABLE (read Retry-After, back off exactly that long).

Requirements:
  - A function that pages through every event (loop while nextPage is not null) and returns the full list.
  - Respect ETag/If-None-Match per page as described above.
  - A minimal test: a mocked 304 response reuses the previously cached items without discarding them.

Adapt to your actual stack — the endpoint, params, response shape and header rules above are language-neutral.
```
