API Standards (Backend Standard)
This document defines the API governance rules for Flow Create Solutions backends.
Goals:
- predictable APIs for clients
- consistent conventions across modules
- reduce improvisation for AI agents and new developers
Base path + versioning
- Base prefix:
/api/v1 - Versioning:
- Non-breaking changes may be added within
v1. - Breaking changes require a new major API version (e.g.,
/api/v2).
- Non-breaking changes may be added within
Resource paths (REST-ish)
- Use plural nouns for resources:
/api/v1/items - Avoid verb-y paths like
/create,/get-by-id,/delete. - Prefer these shapes:
POST /api/v1/items(create)GET /api/v1/items(list)GET /api/v1/items/{item_id}(get)PATCH /api/v1/items/{item_id}(update)DELETE /api/v1/items/{item_id}(delete)
Tenant scoping (multi-tenant)
Tenant scope is selected either via header switching or derived from the authenticated session.
- Header-selected tenant switching:
- Clients send
X-Tenant-Id(exact casing). - Used when the client can switch tenants explicitly.
- Clients send
- Derived-tenant mode (active tenant sessions):
- Tenant comes from
active_tenant_idin the JWT/session. - In this mode,
X-Tenant-Idmust be omitted (reject if present).
- Tenant comes from
- No tenant in URL:
- Do not include
tenant_id/company_idin URL path params. - If a project accidentally supports tenant in both URL and header, the API must reject such requests (client error) to avoid ambiguity.
- Do not include
Pagination (list endpoints)
Standard query params:
page(1-indexed, minimum 1)page_size(minimum 1, maximum 200; default 50)
Example:
GET /api/v1/items?page=1&page_size=50
Filtering + sorting (list endpoints)
Sorting
Standard query params:
sort=<field>order=asc|desc(defaultasc)
Example:
GET /api/v1/items?sort=created_at&order=desc
Filtering
Standard query param shape:
filter[<field>]=<value>
Example:
GET /api/v1/items?filter[status]=active
Rules:
- Only allow filtering/sorting on documented fields. Reject unknown fields with
400(fail fast; do not silently ignore). - Do not allow filtering/sorting by high-cardinality or sensitive fields unless explicitly required and reviewed.
Idempotency (side-effect endpoints)
When required
Support idempotency for endpoints that can create duplicate side effects if retried, including:
- payments/charges
- sending email/SMS
- provisioning resources
- “create” endpoints where duplicates are harmful
Header standard
- Client sends
Idempotency-Key: <string> - The server treats
(tenant scope + authenticated user + method + route + idempotency-key)as the idempotency identity.
Server behavior
- First request with a new key:
- perform the operation
- store the resulting response (status + body) under that key for a TTL (recommended default: 24 hours)
- return the response
- Subsequent requests with the same key:
- do not repeat the side effect
- return the stored response
Notes:
- Projects may choose a different TTL per endpoint based on risk/cost/storage tradeoffs (e.g., shorter for low-risk actions, longer for payments), but must document the deviation in the project repo.
Conflicts
If the same Idempotency-Key is reused with a different request payload (or different authenticated identity/tenant scope), the API should reject with 409 Conflict (or 400) and a clear message.
Response envelopes (required)
All API responses (success and errors) must be shaped consistently using:
StandardResponse(single-object payloads and error responses)StandardListResponse(list payloads)
Error responses
Policy:
- Errors should return
success=falseand use a consistent envelope. - Prefer returning
StandardResponsefor errors, even for list endpoints (FastAPI does not require error responses to match the successresponse_model).
The envelope fields should be used consistently:
title: short, user-facing summarydescription: more detail (safe for clients)errorException: optional debug summary (do not leak secrets/PII)
Backwards compatibility + deprecation
Non-breaking changes allowed in a version
- Adding new optional response fields
- Adding new optional request fields
- Adding new endpoints
Breaking changes (require new version)
- Renaming/removing fields
- Changing field types or semantics
- Changing auth/tenant scoping behavior in a way that breaks clients
Deprecation policy (within a version)
When deprecating an endpoint or field:
- keep it working for an explicit window (project-defined)
- document the replacement and migration path in project docs
- optionally emit deprecation metadata headers (e.g.,
Deprecation,Sunset) if the project supports them