All resources
// Resources

How to Build an API Inventory and Find Shadow Endpoints

Published June 13, 2026

Inventory reconciliation and retirement proof

Build inventory from route code, OpenAPI contracts, gateway and load-balancer configuration, deployment manifests, DNS, client telemetry, and webhook registrations. Each source catches different omissions: a legacy mobile build may call an undocumented v1 route, while a manifest-only health handler can bypass gateway authentication. Record host, path, method, environment, consumer, authentication, data class, owner, release source, and retirement date.

When sources disagree, preserve discrepancy. An unused /debug/config route is not removed from inventory because traffic is quiet; its platform owner must restrict or disable it. For partner callbacks, collect signature configuration and sender identity instead of assuming TLS makes input trusted. Compare external scan results only within approved scope and reconcile them with deployment evidence before declaring a host unknown.

Retirement closes when new clients are blocked, owners approve migration, gateway route and deployment handler are removed, and a controlled request returns the intended non-business result. Keep that check with change record so rollback cannot silently restore endpoint. A temporary exception needs a named interface, private exposure boundary, consumer migration milestone, and review date; no owner means containment or removal.

Ownership includes a reachable contact path inside engineering, not a public claim. Tie every asset to repository, deployment unit, change pipeline, and consumer evidence. Versioned APIs need a date and migration decision rather than an indefinitely supported label. Test inventory accuracy by disabling a controlled staging route and ensuring route export, monitoring, and register update together. A webhook receiver counts as exposed even when no browser links to it.

Reconcile independent evidence

Inventory work compares sources that fail differently: OpenAPI and protobuf contracts, gateway routes, ingress and load-balancer configuration, deployment manifests, DNS, client telemetry, mobile builds, webhook registrations, and observed traffic. Build a register with host, port, protocol, method, version, environment, consumer, authentication, data class, repository, deployment unit, owner, and retirement decision. A health endpoint in a manifest, a gRPC service on a nonstandard port, and a partner callback are interfaces even if no public navigation links to them.

Reconciliation produces discrepancies, not automatic deletion. A route in traffic but absent from contract may be an old mobile client; a contract route absent from gateway may be an unfinished feature; a DNS name with no deployment may be stale or a takeover concern. Preserve source, timestamp, and request method for each discrepancy. Owner must classify it as intended, migrate, restrict, or remove. Quiet traffic is not proof an interface is safe or unused.

Version and deprecation case

Take an observed /v1/device/token request from a synthetic legacy client and compare it to current /v2/devices/token contract. Identify authentication method, fields, response data, consuming build, and migration owner. Block new v1 consumers first, offer a time-bounded migration path, then restrict v1 scope while telemetry measures remaining use. When retirement date arrives, remove gateway mapping and handler deployment, then call old route from fixture. Expected result is deliberate non-business response; it must not return tokens, debug data, or a fallback v2 result.

Test rollback as well. A deployment rollback must not restore endpoint without inventory record and owner notification. Retire DNS entries or direct them to controlled sink behavior. For webhook endpoints, validate sender signature and destination ownership before calling them documented.

Acceptance record

Pass requires each reachable interface to have owner, lifecycle state, authentication description, and evidence source. Record gateway export, manifest revision, DNS result, traffic sample with sensitive fields redacted, and retirement probe. Unknown interface fails until disabled, network-restricted, or documented. An exception identifies exact host and route, permitted consumer, private exposure boundary, migration milestone, review date, and removal test. Inventory is a living engineering artifact, not a claim of public service availability.

Ownership handoff check

An inventory row needs more than a team label. Name the repository and deployment owner who can remove route, plus product owner who can approve consumer migration. Test handoff by selecting one staging endpoint and asking each owner to locate its contract, configuration, and logs from register fields alone. If either cannot do so, inventory lacks usable accountability.

Include authentication failures and old-version telemetry in review. Repeated 401 calls can identify a forgotten automation client; repeated 404 calls can identify documentation drift. Neither signal proves intent, so investigate before blocking consumer. Keep captured samples redacted and retain only operational identifiers necessary for follow-up. A version retirement closes only after route, handler, DNS, and monitoring rule agree on retirement state.

Interface disposition register

Interface and lifecycleOwnerEvidenceExpected resultObserved result / statusExceptionClosure
api-stg.example.test/v1/device/token; retiredAPI platform owner; mobile migration ownerGateway export gw-20260613; manifest rev-441; legacy-client probeRoute and handler absent; deliberate non-business response410; gateway mapping absent; handler absent — closedNoneDNS, monitoring, register, and rollback test agree on retired state; change API-902 closed

Sources

Have a system that needs testing?