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

# REST Quickstart

> Make your first authenticated calls to the Whistle partner API: the self-describing index, then a read-only list of leagues.

Two copy/paste calls to verify your key and see real data. Both are read-only.

## 1. Set your key

```bash theme={null}
export WHISTLE_API_KEY="whk_your_key_here"   # from tommy@huddleup-sports.com
```

## 2. Call the authenticated index

`GET /api/v1` is the recommended first call — it verifies your key and describes the whole surface:

```bash theme={null}
curl -s https://whistle.huddleup-sports.com/api/v1 \
  -H "Authorization: Bearer $WHISTLE_API_KEY"
```

Expected response (`200`, abridged):

```json theme={null}
{
  "data": {
    "version": "v1",
    "auth": "Authorization: Bearer <WHISTLE_API_KEY>",
    "endpoints": ["GET /api/v1/leagues", "POST /api/v1/leagues", "…"],
    "mcp": "/api/mcp (HTTP MCP transport — same tools, bearer-authed)",
    "webhookEvents": ["game.created", "game.updated", "…"],
    "notes": { "idempotency": "…", "money": "…", "signatures": "…" }
  }
}
```

Without a valid key you get exactly a `401` with this body:

```json theme={null}
{"error": "unauthorized"}
```

## 3. Make a read-only request

```bash theme={null}
curl -s https://whistle.huddleup-sports.com/api/v1/leagues \
  -H "Authorization: Bearer $WHISTLE_API_KEY"
```

This lists the leagues **in your key's scope** — leagues in your `source` namespace plus any granted to your key (see [Authentication](/developers/authentication#what-your-key-can-access)). A brand-new key sees an empty array until you create your first league.

Expected response (`200`):

```json theme={null}
{
  "data": [
    {
      "id": "cmc1a2b3c4d5e6f7g8h9i0j1",
      "name": "Springfield Little League",
      "paymentMode": "offline",
      "currency": "usd",
      "source": "huddleup",
      "externalId": "org_123",
      "createdAt": "2026-06-15T14:03:22.118Z",
      "gameCount": 42,
      "memberCount": 9
    }
  ]
}
```

## The response envelope

Every response uses one of two shapes:

* **Success:** `{"data": …}` — status `200` (reads, updates, deletes) or `201` (creates, including idempotent upserts that updated an existing row).
* **Error:** `{"error": "<code>"}` — a single snake\_case code, statuses `400`, `401`, `404`, or `409` only. See [Errors & agent safety](/developers/errors-and-agent-safety).

## Next steps

* Write something: [import leagues and games](/developers/recipes#import-or-upsert-leagues-and-games) (idempotent — safe to re-run).
* Get notified instead of polling: [webhooks](/developers/webhooks).
* Full endpoint documentation: [API reference](/developers/api-reference).
