Bug
ActivateSignupOrg (first-activation webhook path) preserved tier + key_limit from the free-signup row instead of writing the tier the buyer actually paid. A free-signup org that pays a checkout for a different tier ends up with signup-tier entitlements at the paid tier's price.
Production evidence (2026-09-18)
Org SUSE Software Solutions Germany GmbH (3e5b8734-5e29-436a-bffe-b1b120322de5):
- Free signup 2026-09-16 chose growth (3 expired growth checkout sessions).
- Paid a starter checkout (EUR 399) on 2026-09-17 09:54 UTC (
sub_1UGc3VBF7qtPjBKwYWeVR9Yl).
- DB kept
tier=growth, key_limit=15 -> dashboard advertised Growth EUR 1,299 while Stripe billed Starter EUR 399; LiteLLM caps + 15-key limit granted at starter price.
- Sweep of all 23 orgs with subscriptions: SUSE was the only affected row.
- Data fix applied on prod 2026-09-18 09:49 UTC (tier->starter, key_limit->5).
Root cause
internal/db/queries/organizations.sql ActivateSignupOrg comment: "preserves tier + key_limit (set on signup row insert)".
provisionAndWelcomeOrg receives the paid tier but only used it for the welcome email.
- The SEPA settle path (
onInvoicePaymentSucceeded -> provisionAndWelcomeOrg(..., org.Tier, ...)) had the same flaw.
Fix
ActivateSignupOrg writes tier + key_limit; callers derive the paid tier from the checkout session metadata (card path) or the settled invoice's price metadata (tierFromInvoice, SEPA settle path), falling back to the org's existing values when absent.
- Branch:
fix/signup-activation-tier-reconciliation (enterprise-api), VERSION 0.4.89.
Bug
ActivateSignupOrg(first-activation webhook path) preservedtier+key_limitfrom the free-signup row instead of writing the tier the buyer actually paid. A free-signup org that pays a checkout for a different tier ends up with signup-tier entitlements at the paid tier's price.Production evidence (2026-09-18)
Org SUSE Software Solutions Germany GmbH (
3e5b8734-5e29-436a-bffe-b1b120322de5):sub_1UGc3VBF7qtPjBKwYWeVR9Yl).tier=growth, key_limit=15-> dashboard advertised Growth EUR 1,299 while Stripe billed Starter EUR 399; LiteLLM caps + 15-key limit granted at starter price.Root cause
internal/db/queries/organizations.sqlActivateSignupOrgcomment: "preserves tier + key_limit (set on signup row insert)".provisionAndWelcomeOrgreceives the paidtierbut only used it for the welcome email.onInvoicePaymentSucceeded->provisionAndWelcomeOrg(..., org.Tier, ...)) had the same flaw.Fix
ActivateSignupOrgwritestier+key_limit; callers derive the paid tier from the checkout session metadata (card path) or the settled invoice's price metadata (tierFromInvoice, SEPA settle path), falling back to the org's existing values when absent.fix/signup-activation-tier-reconciliation(enterprise-api), VERSION 0.4.89.