Short product slug — swap, identity, withdraw. Becomes the plan name
(<slug>-<stack>), its description, and the apiStage tag.
Deliberately NOT derived from the component name or the base path: it does
not always match either. withdrawal-api meters as withdraw, and that
name is the join key for usage reporting, so deriving it would silently
rename a plan and split its metering history.
Every REST API the plan meters — the whole surface a customer buys when they are granted
slug.A list, not a single API, because a service is sometimes split across several REST APIs: a custom-domain base-path mapping binds one API, so serving
v1/redemptionandv1/ledger-accountsoff one Lambda takes two. When this took a singleapi, the sibling silently keptapiKeyRequired: truewith no plan behind it, and every key issued through the API-access dashboard got a 403INVALID_API_KEYon it — undetectable from the grant grid, which shows the stage as granted.Rule: every API whose methods set
apiKeyRequiredbelongs in exactly one plan'sapis. An API in none is unreachable by any dashboard-issued key.