Docs · TN Fishing

# TN Fishing developer docs

Product: **TN Fishing** at https://fishing.calvinllc.net

## Base URL

https://fishing.calvinllc.net

## Machine-readable entry points

| Resource | URL |
| --- | --- |
| OpenAPI 3 (JSON) | /openapi.json |
| OpenAPI 3 (YAML) | /api/openapi.yaml |
| llms.txt | /llms.txt |
| Sitemap | /sitemap.xml |
| Health | /healthz |
| Official CLI | see repository `cli/tn_fishing` |

## Auth

- **Public reads (no login):** `GET /api/spots`, `GET /api/v1/spots`, `GET /api/today`, `GET /api/v1/today`, `GET /api/access-points`, `GET /api/catch-density`, `GET /api/map/timeline`, `GET /api/stats/community`, `GET /api/bathymetry/{slug}`, `/healthz`, `/openapi.json`, `/llms.txt`, `/docs`.
- **Login required:** personal catches, email alerts, push subscriptions, favorites mutations, account/settings, and other write routes.
- Session cookie `fishd_session` is set after `/login`. CSRF cookie protects browser form POSTs; JSON API clients calling mutation endpoints should use the same-origin session flow.

## Versioning and Sunset

- Current public surface is **v1**. Prefer `/api/v1/...` for new integrations.
- Unversioned `/api/...` paths are **aliases of v1** and remain supported.
- Breaking changes ship as `/api/v2/...` with at least **90 days** overlap.
- Deprecated operations advertise HTTP `Deprecation` and `Sunset` headers (RFC 8594) pointing at the replacement path. Removal happens on or after the Sunset date published in OpenAPI `info` / path extensions.
- Version may also be selected with request header `X-API-Version: 1` (optional; path version wins when both are present).

## Rate limits

fishd applies a per-client request budget (default **120 requests/minute**, override with `RATE_LIMIT_RPM`).

Public unauthenticated responses include:

- `RateLimit-Limit`
- `RateLimit-Remaining`
- `RateLimit-Reset` (unix timestamp)

HTTP **429** includes `Retry-After`.

## Error shape

Unknown `/api/*` paths and API error cases return JSON:

```json
{"error":{"code":"not_found","message":"Unknown API path: /api/nope","hint":"See /docs and /openapi.json"}}
```

Fields: `error.code` (stable string), `error.message` (human), optional `error.hint`.

## Examples

List spots (unauthenticated):

```bash
curl -sS -H 'Accept: application/json' https://fishing.calvinllc.net/api/v1/spots | head -c 400
```

OpenAPI:

```bash
curl -sS https://fishing.calvinllc.net/openapi.json | jq '.info'
```

CLI (from repo):

```bash
pip install -e cli/
tn-fishing spots --limit 5
tn-fishing openapi
```

Markdown homepage:

```bash
curl -sS -H 'Accept: text/markdown' https://fishing.calvinllc.net/
```

## Content negotiation

Send `Accept: text/markdown` on `/`, `/docs`, or unknown non-API paths for Markdown bodies (`Content-Type: text/markdown`, `Vary: Accept`). API paths always prefer JSON errors.

## Public JSON endpoints

- `GET /api/v1/spots` — scored spot catalog
- `GET /api/v1/today` — daily best bites
- `GET /api/v1/access-points` — ramps and access
- `GET /api/v1/catch-density` — aggregated density
- `GET /api/v1/map/timeline` — map timeline frames
- `GET /api/v1/stats/community` — community stats
- `GET /api/v1/bathymetry/{slug}` — bathymetry when available

Unversioned `/api/...` mirrors the same handlers.

## Agent crawlers

`robots.txt` allows major AI crawlers (ChatGPT-User, ClaudeBot, Google-Extended, ora-agent, DeepSeekBot) on the public homepage and docs. Private account routes remain disallowed.

Docs · OpenAPI · llms.txt · Sitemap · Dashboard