|
| 1 | +# Bridge-Watch API Documentation |
| 2 | + |
| 3 | +## Interactive Documentation |
| 4 | + |
| 5 | +Start the backend and open **http://localhost:3000/docs** to access the Swagger UI. |
| 6 | + |
| 7 | +The raw OpenAPI 3.0 JSON spec is served at: |
| 8 | +- **http://localhost:3000/api-docs.json** (live, always in sync with code) |
| 9 | +- **[backend/docs/openapi.json](./openapi.json)** (checked-in snapshot) |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## Authentication |
| 14 | + |
| 15 | +Protected endpoints (all `/api/v1/alerts/*` routes and some admin routes) require an API key: |
| 16 | + |
| 17 | +``` |
| 18 | +x-api-key: <your-api-key> |
| 19 | +``` |
| 20 | + |
| 21 | +The middleware in `src/api/middleware/auth.ts` validates the key. Without a valid key the server returns `401 Unauthorized`. |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Rate Limiting |
| 26 | + |
| 27 | +All endpoints are rate-limited per IP address using a Redis-backed sliding-window algorithm (`src/api/middleware/rateLimit.middleware.ts`). When a limit is exceeded the server responds with: |
| 28 | + |
| 29 | +``` |
| 30 | +HTTP 429 Too Many Requests |
| 31 | +Retry-After: <seconds> |
| 32 | +``` |
| 33 | + |
| 34 | +Current metrics are available at `GET /api/v1/metrics/rate-limits`. |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## API Versioning |
| 39 | + |
| 40 | +All REST endpoints are prefixed with `/api/v1/`. When a breaking change is introduced a new version prefix (`/api/v2/`) is added and the previous version is maintained for **at least 90 days** before deprecation. |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +## Error Format |
| 45 | + |
| 46 | +All errors follow a consistent JSON structure: |
| 47 | + |
| 48 | +```json |
| 49 | +{ |
| 50 | + "error": "Short machine-readable label", |
| 51 | + "message": "Human-readable description" |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +Common HTTP status codes: |
| 56 | + |
| 57 | +| Code | Meaning | |
| 58 | +|------|---------| |
| 59 | +| 400 | Bad Request — invalid parameters or body | |
| 60 | +| 401 | Unauthorized — missing or invalid API key | |
| 61 | +| 404 | Not Found | |
| 62 | +| 409 | Conflict — e.g. optimistic-lock version mismatch | |
| 63 | +| 429 | Too Many Requests | |
| 64 | +| 500 | Internal Server Error | |
| 65 | +| 501 | Not Implemented | |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +## Endpoint Groups |
| 70 | + |
| 71 | +### Health |
| 72 | +| Method | Path | Description | |
| 73 | +|--------|------|-------------| |
| 74 | +| GET | `/health` | Service health check | |
| 75 | + |
| 76 | +### Assets `/api/v1/assets` |
| 77 | +| Method | Path | Description | |
| 78 | +|--------|------|-------------| |
| 79 | +| GET | `/` | List all monitored assets | |
| 80 | +| GET | `/:symbol` | Asset details | |
| 81 | +| GET | `/:symbol/health` | Current health score | |
| 82 | +| GET | `/:symbol/health/history` | Historical health scores (`period=24h|7d|30d`) | |
| 83 | +| GET | `/:symbol/liquidity` | Aggregated liquidity | |
| 84 | +| GET | `/:symbol/price` | Aggregated price from all sources | |
| 85 | + |
| 86 | +### Bridges `/api/v1/bridges` |
| 87 | +| Method | Path | Description | |
| 88 | +|--------|------|-------------| |
| 89 | +| GET | `/` | All bridge statuses | |
| 90 | +| GET | `/:bridge/stats` | Per-bridge statistics | |
| 91 | + |
| 92 | +### Alerts `/api/v1/alerts` _(requires x-api-key)_ |
| 93 | +| Method | Path | Description | |
| 94 | +|--------|------|-------------| |
| 95 | +| GET | `/rules` | List rules for an owner | |
| 96 | +| POST | `/rules` | Create a rule | |
| 97 | +| GET | `/rules/:ruleId` | Get a single rule | |
| 98 | +| PATCH | `/rules/:ruleId` | Update a rule | |
| 99 | +| DELETE | `/rules/:ruleId` | Delete a rule | |
| 100 | +| PATCH | `/rules/:ruleId/active` | Pause/resume a rule | |
| 101 | +| GET | `/rules/:ruleId/events` | Events fired by rule | |
| 102 | +| POST | `/rules/bulk` | Bulk create | |
| 103 | +| PATCH | `/rules/bulk` | Bulk update | |
| 104 | +| DELETE | `/rules/bulk` | Bulk delete | |
| 105 | +| GET | `/history` | Paginated alert history | |
| 106 | +| GET | `/history/:assetCode` | Asset-scoped history | |
| 107 | +| GET | `/stats` | Owner alert statistics | |
| 108 | +| GET | `/recent` | Most recent events | |
| 109 | +| POST | `/test` | Dry-run a rule | |
| 110 | + |
| 111 | +### Analytics `/api/v1/analytics` |
| 112 | +| Method | Path | Description | |
| 113 | +|--------|------|-------------| |
| 114 | +| GET | `/protocol` | Protocol-wide statistics | |
| 115 | +| GET | `/bridges/comparison` | Bridge comparison metrics | |
| 116 | +| GET | `/assets/rankings` | Asset rankings | |
| 117 | +| GET | `/volume` | Volume aggregations | |
| 118 | +| GET | `/trends/:metric` | Metric trend calculation | |
| 119 | +| GET | `/top-performers` | Top assets or bridges | |
| 120 | +| GET | `/historical/:metric` | Historical comparison | |
| 121 | +| GET | `/summary` | Combined analytics summary | |
| 122 | +| GET | `/custom-metrics` | List custom metrics | |
| 123 | +| GET | `/custom-metrics/:metricId` | Execute a custom metric | |
| 124 | +| POST | `/cache/invalidate` | Invalidate analytics cache | |
| 125 | + |
| 126 | +### Aggregation `/api/v1/aggregation` |
| 127 | +| Method | Path | Description | |
| 128 | +|--------|------|-------------| |
| 129 | +| GET | `/:symbol/prices` | OHLCV price aggregation | |
| 130 | +| GET | `/:symbol/health` | Health score aggregation | |
| 131 | +| GET | `/:symbol/volume` | Volume aggregation | |
| 132 | +| GET | `/stats` | Aggregation statistics | |
| 133 | +| POST | `/precompute` | Pre-compute for an interval | |
| 134 | +| POST | `/rebuild` | Rebuild historical data | |
| 135 | +| POST | `/multi-asset` | Multi-asset aggregation | |
| 136 | +| POST | `/cache/cleanup` | Remove old cache entries | |
| 137 | + |
| 138 | +### Metadata `/api/v1/metadata` |
| 139 | +| Method | Path | Description | |
| 140 | +|--------|------|-------------| |
| 141 | +| GET | `/` | All asset metadata | |
| 142 | +| GET | `/search` | Search metadata | |
| 143 | +| GET | `/symbol/:symbol` | By symbol | |
| 144 | +| GET | `/category/:category` | By category | |
| 145 | +| GET | `/:assetId` | By asset ID | |
| 146 | +| GET | `/:assetId/history` | Version history | |
| 147 | +| POST | `/` | Create or update | |
| 148 | +| PATCH | `/:assetId/logo` | Update logo | |
| 149 | +| DELETE | `/:assetId` | Delete | |
| 150 | + |
| 151 | +### Watchlists `/api/v1/watchlists` |
| 152 | +| Method | Path | Description | |
| 153 | +|--------|------|-------------| |
| 154 | +| GET | `/:userId` | User's watchlists | |
| 155 | +| POST | `/:userId` | Create watchlist | |
| 156 | +| PATCH | `/:userId/:id` | Update watchlist | |
| 157 | +| DELETE | `/:userId/:id` | Delete watchlist | |
| 158 | + |
| 159 | +### Preferences `/api/v1/preferences` |
| 160 | +| Method | Path | Description | |
| 161 | +|--------|------|-------------| |
| 162 | +| GET | `/:userId` | All preferences | |
| 163 | +| GET | `/:userId/:category/:key` | Single value | |
| 164 | +| PUT | `/:userId/:category/:key` | Set single value | |
| 165 | +| PATCH | `/:userId/bulk` | Bulk update (optimistic lock) | |
| 166 | +| DELETE | `/:userId/:category/:key` | Reset key | |
| 167 | +| GET | `/:userId/export` | Export preferences | |
| 168 | +| POST | `/:userId/import` | Import preferences | |
| 169 | +| GET | `/:userId/stream` | SSE change stream | |
| 170 | + |
| 171 | +### Jobs `/api/v1/jobs` |
| 172 | +| Method | Path | Description | |
| 173 | +|--------|------|-------------| |
| 174 | +| GET | `/monitor` | Queue status and failed jobs | |
| 175 | +| POST | `/:jobName/trigger` | Manually enqueue a job | |
| 176 | + |
| 177 | +### Config `/api/v1/config` |
| 178 | +| Method | Path | Description | |
| 179 | +|--------|------|-------------| |
| 180 | +| GET | `/` | All config entries | |
| 181 | +| GET | `/:key` | Single entry | |
| 182 | +| POST | `/` | Set value | |
| 183 | +| DELETE | `/:key` | Delete entry | |
| 184 | +| GET | `/features/:name` | Feature flag status | |
| 185 | +| POST | `/features` | Set feature flag | |
| 186 | +| GET | `/export` | Export config | |
| 187 | +| POST | `/import` | Import config | |
| 188 | +| GET | `/audit` | Audit trail | |
| 189 | +| POST | `/cache/clear` | Clear config cache | |
| 190 | + |
| 191 | +### Cache `/api/v1/cache` |
| 192 | +| Method | Path | Description | |
| 193 | +|--------|------|-------------| |
| 194 | +| GET | `/stats` | Redis cache statistics | |
| 195 | +| POST | `/invalidate` | Invalidate by key or tag | |
| 196 | +| GET | `/metrics/rate-limits` | Rate-limit metrics | |
| 197 | + |
| 198 | +### Circuit Breaker `/api/v1/circuit-breaker` |
| 199 | +| Method | Path | Description | |
| 200 | +|--------|------|-------------| |
| 201 | +| GET | `/status` | Pause status for a scope | |
| 202 | +| GET | `/whitelist` | Whitelist check | |
| 203 | +| POST | `/pause` | Pause a scope _(not yet implemented)_ | |
| 204 | +| POST | `/recovery` | Recover from pause _(not yet implemented)_ | |
| 205 | + |
| 206 | +--- |
| 207 | + |
| 208 | +## Maintenance Guide |
| 209 | + |
| 210 | +### Adding a new endpoint |
| 211 | + |
| 212 | +1. Add the route to the relevant file in `backend/src/api/routes/`. |
| 213 | +2. Include a `schema` block with `tags`, `summary`, `params`/`querystring`/`body`, and `response`. |
| 214 | +3. If this is a new route file, register it in `backend/src/api/routes/index.ts`. |
| 215 | +4. Regenerate the static spec: |
| 216 | + ```bash |
| 217 | + npm run docs:generate |
| 218 | + ``` |
| 219 | +5. Commit both the route file and the updated `backend/docs/openapi.json`. |
| 220 | + |
| 221 | +### Updating an existing endpoint |
| 222 | + |
| 223 | +1. Edit the route handler and its inline `schema`. |
| 224 | +2. Run `npm run docs:generate` to refresh the static spec. |
| 225 | + |
| 226 | +### Adding a reusable schema component |
| 227 | + |
| 228 | +Add it to the `components.schemas` map in `backend/src/config/openapi.ts`. Reference it in route schemas using `$ref: "SchemaName#"`. |
| 229 | + |
| 230 | +### Validating the spec |
| 231 | + |
| 232 | +Paste `backend/docs/openapi.json` into [https://editor.swagger.io](https://editor.swagger.io) or run: |
| 233 | +```bash |
| 234 | +npx @stoplight/spectral-cli lint backend/docs/openapi.json |
| 235 | +``` |
| 236 | + |
| 237 | +### CI integration |
| 238 | + |
| 239 | +The GitHub Actions workflow validates TypeScript compilation (`npm run build`) on every PR. Add a spec-lint step by including: |
| 240 | +```yaml |
| 241 | +- run: npx @stoplight/spectral-cli lint backend/docs/openapi.json |
| 242 | +``` |
0 commit comments