Assert Deal
PUT /deals/assert
Create or update a deal. Matches by name + company_id.
Deliberately NOT wired into the closed-stage gates or the completeness rule: assert is the sync-shaped surface (external systems pushing state, no human to answer a 400), the same category the internal router excludes for POST /v1/deals/webhook/sync and the CRM pull worker (#15530 “Out of scope”). Only input hygiene applies here: ids must exist and close_date must parse.
#16060: a stage move made here now emits deal.stage_changed and writes
cb_deal_stage_history, like every other stage writer. background_tasks
is injected (not a body field, so the request schema is unchanged) and the
publish is queued only after the session context has exited — a rolled-back
assert publishes nothing. Because assert is the sync-shaped surface, the
SAME stage arrives on every tick of the caller’s poll loop: the event fires
only on an actual transition, never on a re-assert of the current stage.
Authorizations
Parameters
Header Parameters
Request Body required
object
Deal name (match key)
Responses
200
Successful Response
object
object
‘created’ or ‘updated’
422
Validation Error