## Changes - Add narrative API documentation in docs/api-content/ (introduction, quickstart, authentication, conventions, errors, rate limiting) - Scaffold Astro Starlight site at docs/api/ that consumes prose from the sibling api-content folder and auto-generates the endpoint reference from server/openapi.json via starlight-openapi - Wire Checkmate brand color (#13715B) into Starlight via custom CSS - Add vercel.json so the docs site deploys cleanly as an Astro project with root directory docs/api/ ## Benefits - Public API docs ready to publish at checkmate.so/docs - Endpoint reference stays in sync with the OpenAPI spec automatically - Zero third-party SaaS dependency: site is fully self-hosted on Vercel - Contributors edit plain markdown; no Astro knowledge needed for prose
3.5 KiB
3.5 KiB
title, description
| title | description |
|---|---|
| Errors | HTTP status codes Checkmate returns, what they mean, and how to handle them. |
Errors
Failure responses share the same envelope as successful ones, with success: false and data omitted (or null):
{
"success": false,
"msg": "Validation failed: email must be a valid email"
}
Always treat the HTTP status code as the source of truth for handling logic, and surface msg to humans.
Status codes
| Status | Meaning | When you'll see it |
|---|---|---|
200 OK |
Request succeeded with a body | Most GETs, successful mutations that return the new resource |
204 No Content |
Request succeeded with no body | DELETEs, successful actions like /status-page/:url/unlock |
400 Bad Request |
Malformed request | Missing required path param, malformed JSON, invalid file upload |
401 Unauthorized |
Missing or invalid JWT | Token expired, token missing, token signed with a different secret |
403 Forbidden |
Authenticated, but not allowed | Accessing a resource that belongs to a different team, or insufficient role |
404 Not Found |
Resource doesn't exist | Wrong ID, deleted resource, mistyped path |
409 Conflict |
Operation would violate a constraint | Duplicate email on register, slug already taken on status page |
413 Payload Too Large |
File upload exceeded limit | Logo or profile image too big |
422 Unprocessable Entity |
Request was well-formed but failed validation | Zod / Joi schema rejected the body |
429 Too Many Requests |
Rate limit exceeded | See Rate limiting |
500 Internal Server Error |
Unexpected server error | A bug — report it with the request ID |
Common shapes
401 — missing or invalid token
{
"success": false,
"msg": "No auth token provided"
}
Re-authenticate by calling POST /auth/login.
422 — validation error
{
"success": false,
"msg": "\"email\" must be a valid email"
}
The msg describes the first failing field. Re-send the request with the fix.
403 — forbidden
{
"success": false,
"msg": "Forbidden"
}
You're authenticated but the resource isn't visible to you. Common cause: passing a teamId that isn't your team's.
429 — rate limited
{
"success": false,
"msg": "Too many requests"
}
Inspect RateLimit-* response headers and back off. See Rate limiting.
Error handling pattern
Client code should branch on status code, not on msg:
const res = await fetch(url, opts);
const body = await res.json().catch(() => ({}));
switch (res.status) {
case 200:
case 204:
return body.data;
case 401:
// Token expired or missing — re-authenticate, then retry once.
await reauthenticate();
return retry();
case 422:
// Surface the validation error to the user.
throw new ValidationError(body.msg);
case 429:
// Back off using Retry-After if present.
const retryAfter = Number(res.headers.get("Retry-After") ?? 60);
await sleep(retryAfter * 1000);
return retry();
default:
throw new Error(`Checkmate API ${res.status}: ${body.msg ?? res.statusText}`);
}
Reporting bugs
If you see a 500, capture:
- The exact request (method, path, body — redact secrets)
- The full response body and headers
- A timestamp in UTC
Open an issue at https://github.com/bluewave-labs/Checkmate/issues with that information.
Next: Rate limiting.