Errors & retries
RFC 7807 problem+json responses + idempotency safety
Error format (RFC 7807)
All non-2xx responses follow application/problem+json:
{
"type": "https://docs.buildcalcapi.dev/errors/422",
"title": "Validation Error",
"status": 422,
"detail": "One or more request parameters failed validation.",
"errors": [
{"type": "missing", "loc": ["body", "length_ft"], "msg": "Field required"}
],
"instance": "/v1/calc/concrete/yards",
"request_id": "req_..."
}| Status | Meaning | When to retry |
|---|---|---|
| 400 | Bad request (malformed JSON, mutually-exclusive fields) | No |
| 401 | Missing / invalid / revoked API key | No — rotate key |
| 403 | Insufficient tier (e.g., calling admin from free tier) | No — upgrade |
| 404 | Unknown calc kind or resource | No |
| 409 | Conflict (duplicate signup, idempotency-key collision) | No |
| 422 | Validation error (Pydantic) | No — fix payload |
| 429 | Rate limit exceeded — check Retry-After header | Yes, after delay |
| 500 | Server error | Yes, with backoff |
| 502/503/504 | Upstream / dependency error | Yes, with backoff |
Idempotency
Mutating endpoints (signup, key rotation, billing actions) accept
Idempotency-Key: <uuid-or-random-string> per the IETF Idempotency-Key
HTTP header draft.
- First request with a fresh key executes normally and the response is cached
- Subsequent retries with the same key return the cached response (same status, same body) for 24 hours
- Different request body with same key returns
409 Conflict(catch bugs)
Safe to retry on network drop, 5xx, or client crash without double-charging or double-creating.
Rate limiting
Every response (success and error) includes forward-looking rate limit headers per the IETF draft-ietf-httpapi-ratelimit-headers:
RateLimit-Limit: 60
RateLimit-Remaining: 47
RateLimit-Reset: 60
RateLimit-Policy: 60;w=60RateLimit-Limit— current window limit (per-minute, matches your tier)RateLimit-Remaining— calls remaining in current windowRateLimit-Reset— seconds until the window resets (token-bucket is continuous refill; this reports the full window duration)RateLimit-Policy— full policy descriptor (<limit>;w=<seconds>)
429 Too Many Requests adds the standard backoff hint:
Retry-After: 60Token-bucket algorithm — burst capacity = 2× the RPM limit. Refill is
continuous (not on minute boundaries). Cleanest retry strategy: trust
RateLimit-Remaining to self-throttle BEFORE hitting 429; on 429, use
exponential backoff respecting Retry-After.
request_id
Every response (including errors) returns a request_id field in the
RFC 7807 body. Include it in any support ticket / GitHub issue for fast
diagnosis. Logs are queryable by request_id for 90 days.
Costs vertical
Federal-data price and labor metrics — BLS PPI for 15 construction-material categories, OEWS+QCEW hourly wages for 11 trades at MSA/county/ZIP granularity, and Census BPS building permits for ~3,100 counties + ~930 CBSAs.
MCP integration
Hook up Claude Desktop, Cursor, or any MCP client to BuildCalc API