# onboarding agent provisioned accounts for a candidate who rejected the offer - the acceptance webhook never fired

## TL;DR

The agent provisioned accounts when the offer stage changed, but the candidate rejected and the acceptance webhook never fired. Gate provisioning on the explicit acceptance event (signed offer), not on stage movement. Stage changes are intentions; the signature is the fact.

```text
onboarding agent provisioned accounts for a candidate who rejected the offer
```

## Steps

1. Confirm the trigger: check what event started provisioning (stage change vs signed offer).
   Expected: It was the stage change.

2. Switch the trigger to the signed-offer/acceptance event from the ATS or HRIS.
   Expected: Provisioning waits for the signature.

3. Deprovision the orphaned accounts: revoke access, remove licenses, close the tickets.
   Expected: No ghost accounts remain.

4. Add a reconciliation check: every provisioned account must map to an accepted offer; orphans get flagged daily.
   Expected: Orphans are caught automatically.

5. Handle the race: if acceptance and provisioning race, make provisioning idempotent and keyed on the candidate.
   Expected: Double-runs are harmless.

## When to use

- accounts were provisioned for someone who did not join
- provisioning triggers on stage changes
- the acceptance event is separate from the stage

## When not to use

- provisioning correctly waits for acceptance (working as intended)
- the accounts were for a contractor with a different flow (check that flow's trigger)
- the candidate accepted then rescinded (that is a deprovisioning case)

## Tool compatibility

- any onboarding/provisioning agent
- ATS/HRIS webhooks

## Variant phrasings

- "onboarded candidate who rejected offer"
- "provisioned accounts no acceptance"
- "onboarding triggered without signed offer"

## Why it happens

ATS stages are workflow conveniences; recruiters move candidates between them loosely. The signed offer is the legal fact of acceptance. An agent that provisions on stage movement acts on intentions, and intentions change. The acceptance event is the only safe trigger.

## Edge cases

- some ATS setups fire acceptance webhooks unreliably; add a poll fallback
- deprovisioning needs the same care as provisioning; orphaned accounts are a security issue
- start-date changes after provisioning need a hold/suspend path, not just create/delete

## Provenance

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