Skip to content

feat: gate self-service API key creation on an active billing plan (gap #9) - #81

Merged
man4ish merged 1 commit into
mainfrom
feature/m17-plan-gated-api-key-creation
Oct 4, 2026
Merged

man4ish merged 1 commit into
mainfrom
feature/m17-plan-gated-api-key-creation

Conversation

@man4ish

@man4ish man4ish commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • POST /me/api-keys now checks, before issuing a new key, that the caller's organization has an active (or trialing) subscription — via a new billing_client.organization_has_active_plan(org_id).
  • The check calls omnibioai-billing's existing GET /organizations/{id}/subscription endpoint, authenticated with a short-lived synthetic JWT minted by this service's own create_access_token. No new shared secret: it reuses the platform-wide JWT signing key both services already trust, the same way any other validly-signed platform JWT with a matching org_id claim would be accepted.
  • Explicit fail-open/fail-closed split: network errors, timeouts, non-2xx-non-404 responses, and malformed JSON all fail open (key creation proceeds) since these are infra failures, not business state; a 404 (no subscription at all) fails closed. See app/services/billing_client.py's module docstring/comments.

Test plan

  • pytest tests/test_billing_client.py tests/test_me_api_keys.py -q — 27 passed
  • Full background suite on this branch (post-rebase onto current main) — 1506 passed / 2 skipped / 1 pre-existing unrelated flake (test_mfa_recovery_code_atomicity.py::test_concurrent_requests_different_challenge_tokens_same_code_exactly_one_success, a timing-sensitive concurrency test unrelated to this change)

🤖 Generated with Claude Code

#9)

POST /me/api-keys now calls omnibioai-billing's existing
GET /organizations/{id}/subscription endpoint before issuing a new
key, via a short-lived synthetic JWT minted with this service's own
create_access_token -- no new shared secret, reusing the
platform-wide signing key both services already trust.

Infra failures (network error, timeout, 5xx, malformed JSON) fail
open; a genuine "no subscription at all" (404) fails closed. See
billing_client.py for the full rationale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@man4ish
man4ish merged commit b784d67 into main Oct 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant