API Governance
Private does not mean unimportant: an internal API with forty consumers is harder to change than a public one with four. Ownership, a catalog, the dependency graph, a compatibility matrix, per-consumer usage telemetry and an evidence-gated migration plan are how an organization evolves its contracts on purpose.
API catalog
Owner · version · consumers · SLO · documentation · deprecation status — and the dependency graph every entry sits in.
Projects API
stable- Owner
- Collaboration
- Version
- v1
- Consumers
- Web BFF, Mobile BFF, Partner SDK, CLI
- SLO
- p95 < 250 ms · 99.95%
- Documentation
- Public reference + changelog
- Depends on
- Identity API, Notifications API
- Depended on by
- Web BFF, Mobile BFF, Search API
- Dependency depth
- 2 hops to the bottom of the stack
- Deprecation
- none
Highest consumer count in the company; the `owner_id` field is mid-deprecation in favour of memberships with the owner role.
Every hop is a place a breaking change or an outage can travel. Identity sits under everything, which is why it is the most conservatively evolved API in the company — see Architecture · API Gateway and Service Discovery for the runtime side of this graph.
Compatibility matrix
Which client versions work against which API versions. Plan the columns before you plan the release.
| Client | Projects v1 (owner_id) | Projects v1 (memberships, owner_id kept) | Projects v2 (memberships only) | Why |
|---|---|---|---|---|
| Web app (current) | ✓ works | ✓ works | ✓ works | Reads owner from memberships since release 2026.07. |
| Mobile 5.x | ✓ works | ✓ works | ✓ works | Ships the memberships reader; unknown roles rendered as "member". |
| Mobile 4.x | ✓ works | ✓ works | ✗ breaks | Reads owner_id directly and crashes on an unknown role value. 12 % of mobile traffic. |
| Partner SDK v3 | ✓ works | ✓ works | △ partial | Generated from the v1 schema; tolerates new fields, but its typed role enum rejects new values. |
| CLI | ✓ works | ✓ works | ✓ works | Reads only ids and names; indifferent to ownership shape. |
The middle column is the dual-support state: both shapes served from one source of truth. It is the only column every client passes — which is why it exists, and why it is temporary. Lesson: API Migration: Running the Change End to End →
Consumer telemetry before removal
A field is removable when its usage reads zero per consumer — not when most consumers have migrated.
Can project.owner_id be removed?
memberships[].role == "owner"Not removable. A field is removable when its per-consumer usage reads zero for the migration window — not when most consumers have moved. Mobile 4.x can be nudged (forced-update prompt, Deprecation header, a dated sunset) but not skipped.
Migration planner
Introduce → dual support → measure → deprecate → window → remove. Each step has an exit criterion.
Ship memberships with an owner role alongside owner_id. Nothing is removed; the new shape is additive and documented as the preferred one.
The new shape is in the docs, the SDK, and the changelog; old clients see no difference.
Review modes
Every API in the catalog should survive all four lenses before it is called reviewed.
Run the design through four lenses
Depth lives in Security Engineering →. Each question links to the lesson that teaches it; tick the ones your contract already answers.