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.