Dismiss a proposed analysis, or send it to the wizard
const url = 'http://localhost:8000/api/agents/intake/example/close/';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"outcome":"edited"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://localhost:8000/api/agents/intake/example/close/ \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "outcome": "edited" }'Dismiss a proposed analysis, or record that the coach took it to the upload wizard instead (issue #1689).
Costs nothing either way. outcome distinguishes the two, and the difference is a pilot metric rather than a detail: edited means the agent read the clip wrong and a human corrected it, declined means the coach did not want the analysis.
Only a still-open proposal can be closed — 400 intake_closed otherwise, because closing a confirmed intake would orphan an analysis that is already running and already paid for.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”Body of POST /api/agents/intake/<id>/close/.
One endpoint for two outcomes because they are one transition with two
meanings, and the difference is the pilot’s whole manual-intervention
number: edited says the agent read the clip wrong and the coach took it to
the wizard, declined says they did not want the analysis at all. Splitting
them into two routes would make that distinction a URL rather than data, and
the funnel would have to reconstruct it from which path was hit.
object
declined- declinededited- edited
Examples
Taken to the wizard
{ "outcome": "edited"}Body of POST /api/agents/intake/<id>/close/.
One endpoint for two outcomes because they are one transition with two
meanings, and the difference is the pilot’s whole manual-intervention
number: edited says the agent read the clip wrong and the coach took it to
the wizard, declined says they did not want the analysis at all. Splitting
them into two routes would make that distinction a URL rather than data, and
the funnel would have to reconstruct it from which path was hit.
object
declined- declinededited- edited
Body of POST /api/agents/intake/<id>/close/.
One endpoint for two outcomes because they are one transition with two
meanings, and the difference is the pilot’s whole manual-intervention
number: edited says the agent read the clip wrong and the coach took it to
the wizard, declined says they did not want the analysis at all. Splitting
them into two routes would make that distinction a URL rather than data, and
the funnel would have to reconstruct it from which path was hit.
object
declined- declinededited- edited
Responses
Section titled “Responses”Body of the intake confirm / close responses.
card is the SAME payload the conversation persisted, rebuilt from the
updated row — so the client swaps the card it is showing for this one rather
than patching a status into a payload it holds, and the two cannot drift.
object
object
Example generated
{ "intake_id": "example", "status": "example", "session_id": "example", "card": { "additionalProperty": "example" }}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}The caller’s tier does not include the coaching agents.
object
One of eight canonical strings. The front-end paywall switches copy + CTA on this value (exact string equality — do not localise). quota_exhausted / seat_limit_reached / client_limit_reached / feature_not_in_plan lead to an upgrade CTA; subscription_suspended leads to a Billing Portal CTA so the buyer can update their payment method; exercise_not_in_plan leads to a contact-us CTA — the movement list is sales-managed, no tier adds to it (#2030). trial_expired / access_ended mean the team is read-only (#2901): everything opens, nothing new is created; they lead to a subscribe CTA and always carry reset_at: null.
quota_exhausted- Session quota for the period reached 0subscription_suspended- Stripe dunning in flight (past_due / unpaid)seat_limit_reached- Adding another team member would exceed plan.max_seatsclient_limit_reached- Adding another Client would exceed plan.max_client_profilesfeature_not_in_plan- The tier does not include this whole feature surfaceexercise_not_in_plan- The (activity, exercise) is not in the team’s exercise grantstrial_expired- The team is read-only: its self-serve trial endedaccess_ended- The team is read-only: its paid plan or granted access ended
ISO-8601 UTC timestamp the team’s current period ends. Null when the team has no live subscription (legacy un-migrated row). On Free + paid this is the renewal moment; quota refreshes to exactly plan.session_quota (NOT additive — leftover sessions don’t roll over).
The active plan’s role string (free, starter, professional, organization, strategic). Same value as current_role — kept as two separate fields for forward-compatibility with a future named-plan split where current_plan could carry an SKU and current_role the tier label.
The active plan’s role string. See current_plan.
Which feature surface is locked. Present ONLY on feature_not_in_plan, so one modal can name what’s gated without a detail string per feature (#773). The only value today is agents (aikynetix/agents/services.py::AGENTS_FEATURE).
Examples
Free team opens an agent conversation
{ "detail": "feature_not_in_plan", "reset_at": null, "current_plan": "free", "current_role": "free", "feature": "agents"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}No such intake for this coach, or the intake capability is off for this deployment.
object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Example generated
{ "detail": "example"}object
429 — rate limit exceeded. Honour the Retry-After response header (seconds to wait) before retrying; it is sent on every 429.
Example generated
{ "detail": "example"}