PR #5447 (+ review fixes) added a billing-verification wire contract on PRO/API-gated REST operations: retryable 503 with Retry-After (1-60s) + X-Billing-Verification + {error, code} body (renewal_verification_pending / renewal_verification_failed / entitlement_verification_unavailable), and a 403 variant whose body now carries code: subscription_lapsed.
The prose docs are updated (docs/usage-errors.mdx, docs/mcp-error-catalog.mdx), but the generated OpenAPI specs are not:
docs/api/*.openapi.{json,yaml} gated operations enumerate 200/400/401/403/429/default only — no 503 response object.
- The
ForbiddenError schema has no code property (currentTier, error, planKey, requiredTier only).
Per the established pattern (sebuf protoc-gen-openapiv3 has no option for this), the fix is a post-generation injector wired into make generate (see scripts/openapi-inject-security.mjs siblings + scripts/lib/openapi-codegen.mjs):
- Inject a
503 response (schema with error, code enum, Retry-After header) on every op behind ENDPOINT_ENTITLEMENTS / PREMIUM_RPC_PATHS / wm_-key auth (reuse the fail-closed source parsers in openapi-codegen.mjs).
- Add
code to the ForbiddenError schema (optional string enum incl. subscription_lapsed).
- Byte-faithful JSON serializer + surgical YAML insertion; add the injector to
make generate order and its own --check; keep it order-independent vs the security/examples/jmespath injectors.
- Guard test mirroring
mcp-api-parity so the enum stays in sync with server/_shared/usage.ts / entitlement-check.ts.
Deliberately split out of #5447: the regenerated diff spans all 34 service specs and would have drowned the payments PR.
PR #5447 (+ review fixes) added a billing-verification wire contract on PRO/API-gated REST operations: retryable 503 with
Retry-After(1-60s) +X-Billing-Verification+{error, code}body (renewal_verification_pending/renewal_verification_failed/entitlement_verification_unavailable), and a 403 variant whose body now carriescode: subscription_lapsed.The prose docs are updated (
docs/usage-errors.mdx,docs/mcp-error-catalog.mdx), but the generated OpenAPI specs are not:docs/api/*.openapi.{json,yaml}gated operations enumerate200/400/401/403/429/defaultonly — no 503 response object.ForbiddenErrorschema has nocodeproperty (currentTier,error,planKey,requiredTieronly).Per the established pattern (sebuf
protoc-gen-openapiv3has no option for this), the fix is a post-generation injector wired intomake generate(seescripts/openapi-inject-security.mjssiblings +scripts/lib/openapi-codegen.mjs):503response (schema witherror,codeenum,Retry-Afterheader) on every op behindENDPOINT_ENTITLEMENTS/PREMIUM_RPC_PATHS/ wm_-key auth (reuse the fail-closed source parsers inopenapi-codegen.mjs).codeto theForbiddenErrorschema (optional string enum incl.subscription_lapsed).make generateorder and its own--check; keep it order-independent vs the security/examples/jmespath injectors.mcp-api-parityso the enum stays in sync withserver/_shared/usage.ts/entitlement-check.ts.Deliberately split out of #5447: the regenerated diff spans all 34 service specs and would have drowned the payments PR.