# Stop the onboarding agent provisioning seats before payment is confirmed

## TL;DR
Assign seats only after the payment or subscription reaches a confirmed state - payment succeeded, subscription active, invoice paid. Check the billing state at the moment of provisioning, not at the moment of signup. If billing is uncertain, the seat waits.

## The problem
```text
14:02 agent: assigned 25 pro seats to acme-corp
14:05 stripe: payment_intent pi_xxx failed (card declined)
14:06 acme-corp: 25 users active on pro, $0 collected
```

## Use this skill
Agent? Search Vectle for this error:
```bash
curl -s "https://vectle.com/api/v1/search?q=onboarding agent provisioned seats before payment confirmed"
```

## Fix it

### Step 1: Read the live billing state right before provisioning

Query the subscription or payment intent status for the account at provisioning time. Accept only confirmed states: payment succeeded, subscription active or trialing.

Expected: you have a fresh billing verdict stamped within the last few minutes for every seat assignment.

### Step 2: Gate the seat assignment on that verdict

Make the provisioning step conditional: no confirmed payment, no seats. The agent should park the account in a pending-payment state with a clear next step for the buyer.

Expected: a failed or pending payment leaves zero provisioned seats.

### Step 3: Handle the in-between states explicitly

Map every billing state to an action: succeeded provisions, requires_action notifies the buyer, failed or canceled parks the account, processing waits with a timeout. No state should fall through to "provision anyway".

Expected: a state machine, not a guess, decides every seat.

### Step 4: Reconcile on payment webhooks

When a later payment succeeds, the webhook handler should pick up parked accounts and provision. When a payment fails after provisioning, revoke or downgrade the seats.

Expected: the seat inventory always matches the money, even when payment resolves after the run.

### Step 5: Prove the gate with a declined card

Run onboarding in staging with a card that declines.

Expected: zero seats assigned, the account sits in pending-payment, and the buyer gets a payment-fix link.

## When this applies

- Users are active on paid plans with no successful payment behind them
- The agent provisions seats immediately at signup before billing settles
- Async payment methods (bank transfer, invoicing) create a gap between signup and money

## When it doesn't

- Free trials and freemium seats (no payment expected yet)
- The billing failure is a webhook delay you already handle
- Seat counts are wrong for reasons unrelated to payment timing

## Compatibility

Stripe, Chargebee, Paddle, and Braintree for billing state; any seat or license assignment path (Okta, Entra, or your own licensing service).

## Variant phrasings

### onboarding agent assigned licenses before checkout completed

Same fix. Checkout completion and payment confirmation are different events; gate on the second.

### users provisioned on paid plan with failed payment

Add the revoke path from Step 4. The gate prevents new cases; reconciliation cleans up the existing ones.

## Why it happens

Onboarding flows are built signup-first: the user finishes the form, the agent races to make the product feel instant, and billing settles later. The agent has no step that says "wait for the money," so seats go out on optimism. Async payment methods make the gap minutes or days long, and every gap is a free-rider window.

## Edge cases

- Trial-to-paid conversion: the trial seat policy and the paid seat policy must hand off cleanly
- Manual invoicing and enterprise POs: "confirmed" may mean a signed order form, not a charge
- Partial payments: decide whether 10 of 25 paid seats means 10 seats or zero

## If it still fails

- Capture the billing state at provisioning time, the seat assignment log, and the webhook history before changing anything else.
- Reproduce with a single declined test payment so you are not debugging a crowd.
- Check the billing provider status page; webhook outages look exactly like gate bugs.

## Prevention

- The payment gate lives in the provisioning path itself, not in documentation.
- Run a daily reconciliation job that matches seats to paid subscriptions and flags drift.
- Alert on any seat assigned while billing state was pending or unknown.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_aSOtn8j5l_f8rYrW5JF5WA
