# active_starting -> active_in_process
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "start_processing"}'
# active_in_process -> active_completed
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "complete"}'
# any active_* -> draft
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "unpublish"}'
# any -> archived (soft delete)
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "archive"}'
# archived -> draft
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "restore"}'
# draft -> active_starting
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "submit"}'
import requests
def transition(teardown_id: str, action: str) -> dict:
resp = requests.post(
f"{base_url}/public/v1/teardowns/transition/{teardown_id}",
headers={
"Authorization": f"Bearer {api_key}",
"X-Organization-Id": org_id,
},
json={"action": action},
)
resp.raise_for_status()
return resp.json()
# Drive a teardown through the full lifecycle
transition(teardown_id, "start_processing") # -> active_in_process
transition(teardown_id, "complete") # -> active_completed
transition(teardown_id, "archive") # -> archived
transition(teardown_id, "restore") # -> draft
transition(teardown_id, "submit") # -> active_starting
transition(teardown_id, "unpublish") # -> draft
{
"id": "3c707051-021d-4d04-a8e7-4eb254e80858",
"status": "active_in_process",
"previous_status": null
}
{
"detail": "Cannot perform 'complete' from status 'active_starting'"
}
{
"detail": "Action 'approve' requires admin role"
}
{
"detail": "Reason required for rejection"
}
Teardowns
Transition a teardown
Move a teardown through the lifecycle state machine.
POST
/
public
/
v1
/
teardowns
/
transition
/
{teardown_id}
# active_starting -> active_in_process
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "start_processing"}'
# active_in_process -> active_completed
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "complete"}'
# any active_* -> draft
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "unpublish"}'
# any -> archived (soft delete)
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "archive"}'
# archived -> draft
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "restore"}'
# draft -> active_starting
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "submit"}'
import requests
def transition(teardown_id: str, action: str) -> dict:
resp = requests.post(
f"{base_url}/public/v1/teardowns/transition/{teardown_id}",
headers={
"Authorization": f"Bearer {api_key}",
"X-Organization-Id": org_id,
},
json={"action": action},
)
resp.raise_for_status()
return resp.json()
# Drive a teardown through the full lifecycle
transition(teardown_id, "start_processing") # -> active_in_process
transition(teardown_id, "complete") # -> active_completed
transition(teardown_id, "archive") # -> archived
transition(teardown_id, "restore") # -> draft
transition(teardown_id, "submit") # -> active_starting
transition(teardown_id, "unpublish") # -> draft
{
"id": "3c707051-021d-4d04-a8e7-4eb254e80858",
"status": "active_in_process",
"previous_status": null
}
{
"detail": "Cannot perform 'complete' from status 'active_starting'"
}
{
"detail": "Action 'approve' requires admin role"
}
{
"detail": "Reason required for rejection"
}
Drives a teardown between lifecycle states. Use this not PATCH to
change a teardown’s
status. Each action is validated against the
state machine; trying an invalid transition returns 400 with a clear
message.
See status lifecycle for the full state
diagram.
Headers
string
required
Bearer tdao_live_…string
required
Your organization’s UUID.
string
required
application/jsonPath parameters
string (UUID)
required
Body
string
required
The transition action to perform. See the table below.
string
Required when
action="reject". Optional otherwise. Stored in the
audit row’s metadata.Actions
| Action | Valid from | Result | Requires |
|---|---|---|---|
start_processing | active_starting | active_in_process | seller |
complete | active_in_process | active_completed | seller |
unpublish | any active_* | draft (UI-only state) | seller |
archive | any | archived | seller |
restore | archived | draft | seller |
submit | draft | active_starting | seller |
Response
200 OK. A small transition response:
string (UUID)
The teardown’s id.
string
The new status after the transition.
string | null
The prior status. Populated for admin-only transitions; usually
null for the seller-facing actions listed above.The transition endpoint currently returns the internal field names
(
id, status). The other teardown endpoints have moved to the
partner-facing names (teardown_id, etc.). We’ll align this in a
future release.# active_starting -> active_in_process
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "start_processing"}'
# active_in_process -> active_completed
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "complete"}'
# any active_* -> draft
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "unpublish"}'
# any -> archived (soft delete)
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "archive"}'
# archived -> draft
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "restore"}'
# draft -> active_starting
curl -X POST "$base_url/public/v1/teardowns/transition/$teardown_id" \
-H "Authorization: Bearer $api_key" \
-H "X-Organization-Id: $org_id" \
-H "Content-Type: application/json" \
-d '{"action": "submit"}'
import requests
def transition(teardown_id: str, action: str) -> dict:
resp = requests.post(
f"{base_url}/public/v1/teardowns/transition/{teardown_id}",
headers={
"Authorization": f"Bearer {api_key}",
"X-Organization-Id": org_id,
},
json={"action": action},
)
resp.raise_for_status()
return resp.json()
# Drive a teardown through the full lifecycle
transition(teardown_id, "start_processing") # -> active_in_process
transition(teardown_id, "complete") # -> active_completed
transition(teardown_id, "archive") # -> archived
transition(teardown_id, "restore") # -> draft
transition(teardown_id, "submit") # -> active_starting
transition(teardown_id, "unpublish") # -> draft
{
"id": "3c707051-021d-4d04-a8e7-4eb254e80858",
"status": "active_in_process",
"previous_status": null
}
{
"detail": "Cannot perform 'complete' from status 'active_starting'"
}
{
"detail": "Action 'approve' requires admin role"
}
{
"detail": "Reason required for rejection"
}
Audit trail
Every transition writes one audit row:action=teardown.<your-action>(e.g.,teardown.complete,teardown.archive).previous_state={ "status": "<old-status>" }new_state={ "status": "<new-status>" }metadata.via_api = trueplus the standard API-key tags.- For
reject:metadata.reasoncarries your reason string.
See also
- Status lifecycle for the full state diagram and the conceptual model.
- Delete a teardown for hard delete vs. archive trade-offs.
- Update a teardown for changing
fields other than
status.

