Skip to main content
Teardowns have four named “slots” alongside the generic documents[] array:
Slot URL fragmentDB column on teardownsUI label
harvest-listharvest_listHarvest List
occmoccmOCCM
aircraft-detailsaircraft_details_docAircraft Details
non-incident-statementnon_incident_statementNon-Incident Statement
These are dedicated tiles on the teardown detail page. Uploading to a slot also appends the URL to the generic documents[] array so it appears both in the slot card AND in the “Documents” section.

Upload to a slot

POST /public/v1/teardown/{doc_type}/{teardown_id}

Path parameters

doc_type
string
required
One of harvest-list, occm, aircraft-details, non-incident-statement. URL-safe hyphens; the DB column has underscores (we translate).
teardown_id
string (UUID)
required

Headers

Authorization
string
required
Bearer tdao_live_…
X-Organization-Id
string
required
Content-Type
string
required
multipart/form-data

Form fields

file
file
required
The file to upload.
audience
string (CSV)
Optional. Same shape as the generic-document audience field. See audience.

File rules

Same as the generic document upload max 50 MB, PDF / XLSX / XLS / DOCX / DOC / CSV / images.

What it writes

  1. The matching column on the teardown row is set to the new URL (overwriting any previous slot value).
  2. The URL is also appended to teardowns.documents[].
  3. If audience was sent and is different from the teardown’s current audience, it’s applied + audited.
  4. The file lands in storage at teardowns/<teardown_id>/<doc_type>/<8-hex>_<filename>.
Replacing a slot does NOT delete the previous slot’s storage file the previous URL remains in documents[] until you delete it explicitly. (Most partners run a Clear → Upload sequence.)

Response

200 OK:
{
  "url": "https://.../teardowns-media/teardowns/<id>/harvest-list/abcd_harvest.xlsx",
  "filename": "harvest.xlsx",
  "size": 234567,
  "content_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
curl -X POST "$base_url/public/v1/teardown/harvest-list/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/harvest.xlsx"
curl -X POST "$base_url/public/v1/teardown/occm/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/occm.pdf"
curl -X POST "$base_url/public/v1/teardown/aircraft-details/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/aircraft-details.pdf"
curl -X POST "$base_url/public/v1/teardown/non-incident-statement/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/non-incident-statement.pdf"
# Any slot can take an optional audience CSV in the same call
curl -X POST "$base_url/public/v1/teardown/occm/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/occm.pdf" \
  -F "audience=Airline, MRO"
import requests

for doc_type, path in [
    ("harvest-list", "harvest.xlsx"),
    ("occm", "occm.pdf"),
    ("aircraft-details", "aircraft-details.pdf"),
    ("non-incident-statement", "non-incident-statement.pdf"),
]:
    with open(path, "rb") as f:
        resp = requests.post(
            f"{base_url}/public/v1/teardown/{doc_type}/{teardown_id}",
            headers={"Authorization": f"Bearer {api_key}", "X-Organization-Id": org_id},
            files={"file": f},
        )
    resp.raise_for_status()

Clear a slot

DELETE /public/v1/teardown/{doc_type}/{teardown_id}
Single call that, in one transaction:
  1. Sets the named column on the teardown to NULL (the UI slot card becomes blank).
  2. Removes the URL from teardowns.documents[].
  3. Best-effort deletes the underlying storage file.
Idempotent calling against an already-empty slot returns 200 {"status": "ok"} without writing anything.

Path parameters

doc_type
string
required
Same as upload harvest-list / occm / aircraft-details / non-incident-statement.
teardown_id
string (UUID)
required

Response

200 OK:
{ "status": "ok" }
curl -X DELETE "$base_url/public/v1/teardown/harvest-list/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id"
curl -X DELETE "$base_url/public/v1/teardown/occm/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id"
curl -X DELETE "$base_url/public/v1/teardown/aircraft-details/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id"
curl -X DELETE "$base_url/public/v1/teardown/non-incident-statement/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id"
import requests

for doc_type in ("harvest-list", "occm", "aircraft-details", "non-incident-statement"):
    resp = requests.delete(
        f"{base_url}/public/v1/teardown/{doc_type}/{teardown_id}",
        headers={"Authorization": f"Bearer {api_key}", "X-Organization-Id": org_id},
    )
    resp.raise_for_status()

Audit trail

Each slot upload writes one audit row:
  • teardown.harvest_list.uploaded (or the matching field name) with metadata containing filename, size, URL.
Each slot delete writes:
  • teardown.harvest_list.removed (or the matching field name) with metadata containing the removed URL.

See also

  • Teardown documents for the generic (non-slot) document endpoints.
  • Audience for the visibility behaviour of the optional audience form field.