API contract standards
The service-owned OpenAPI files define behavior. scripts/compose-specs.mjs combines them and applies shared documentation once: tags, descriptions, examples, standard errors, rate-limit/deprecation headers, idempotency, security schemes, environment servers, links, event webhooks, and schema audits. CI runs Spectral plus scripts/check-contracts.mjs; generated output must stay committed.
Requests and collections
- JSON is the default representation. XML is deliberately unsupported. Uploads use
multipart/form-data; downloads declare their exact media type andContent-Disposition. - POST accepts an optional
Idempotency-Keyof at most 128 characters. The edge retains successful responses for 24 hours and rejects reuse with a different body. Bulk endpoints accept at most 100 unique items, run atomically unless documented otherwise, and return processed/existing or processed/failed sets. - Collections use
limit/offset; large ordered sets may additionally return an opaquenextCursor.metaalways carrieslimit,offset,total, and optionalnext,prev,nextCursor, andestimatedfields. - Sorting is an allow-listed field plus
order=asc|desc. Filtering uses named, typed parameters—no RSQL parser.qis full-text search,fieldsis a sparse fieldset,includeselects documented related data,idsis batch get, andcount=exact|estimate|nonecontrols count cost. - Long-running future operations return
202, aLocationheader, and the sharedAsyncOperationshape. No async endpoint is invented until work is actually queued.
Responses, caching, and compatibility
- Success and errors use the English, machine-stable envelope. Error
messageis one of the centralizedplatform.ErrorCodes; human detail stays inerror. Localization is a product decision and is not inferred fromAccept-Language. - The edge documents and emits
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset; a rejected request also hasRetry-After. Deprecated operations set OpenAPIdeprecated: true,x-deprecated-at, andx-sunset; the edge emits RFC 9745DeprecationandSunsetheaders. /users/mecombines profile, roles, and permissions and supports ETag/304 with a short private cache. Mutations that later require optimistic concurrency will adoptIf-Matchonly after that product decision is made.
Platform and event surface
Every process exposes /healthz, /readyz, and /version from the shared router. healthz?detail=1 adds runtime metadata. /metrics is intentionally excluded from the public OpenAPI document because it is a Prometheus scrape surface protected by network policy.
The aggregate is OpenAPI 3.1 and declares user.created, user.deleted, and audit.entry payloads with a discriminator plus webhook operations. Delivery is at least once; consumers must be idempotent. SDK version equals aggregate info.version; per-tag package subpaths and generated Zod request schemas keep browser imports tree-shakeable.
Run node scripts/api-changelog.mjs <base-sha> to print added, changed, and removed operations. Removal exits nonzero and must follow docs/API_VERSIONING.md.