> ## Documentation Index
> Fetch the complete documentation index at: https://teardowns.aero/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Slot documents

> Upload and clear the four named-slot documents on a teardown (harvest list, OCCM, aircraft details, non-incident statement).

Teardowns have four named "slots" alongside the generic `documents[]`
array:

| Slot URL fragment        | DB column on `teardowns` | UI label               |
| ------------------------ | ------------------------ | ---------------------- |
| `harvest-list`           | `harvest_list`           | Harvest List           |
| `occm`                   | `occm`                   | OCCM                   |
| `aircraft-details`       | `aircraft_details_doc`   | Aircraft Details       |
| `non-incident-statement` | `non_incident_statement` | Non-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

```http theme={null}
POST /public/v1/teardown/{doc_type}/{teardown_id}
```

### Path parameters

<ParamField path="doc_type" type="string" required>
  One of `harvest-list`, `occm`, `aircraft-details`,
  `non-incident-statement`. URL-safe hyphens; the DB column has
  underscores (we translate).
</ParamField>

<ParamField path="teardown_id" type="string (UUID)" required />

### Headers

<ParamField header="Authorization" type="string" required>
  `Bearer tdao_live_…`
</ParamField>

<ParamField header="X-Organization-Id" type="string" required />

<ParamField header="Content-Type" type="string" required>
  `multipart/form-data`
</ParamField>

### Form fields

<ParamField body="file" type="file" required>
  The file to upload.
</ParamField>

<ParamField body="audience" type="string (CSV)">
  Optional. Same shape as the generic-document audience field. See
  [audience](/concepts/audience).
</ParamField>

### 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`:

```jsonc theme={null}
{
  "url": "https://.../teardowns-media/teardowns/<id>/harvest-list/abcd_harvest.xlsx",
  "filename": "harvest.xlsx",
  "size": 234567,
  "content_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
```

<RequestExample>
  ```bash harvest-list theme={null}
  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"
  ```

  ```bash occm theme={null}
  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"
  ```

  ```bash aircraft-details theme={null}
  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"
  ```

  ```bash non-incident-statement theme={null}
  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"
  ```

  ```bash with audience theme={null}
  # 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"
  ```

  ```python python theme={null}
  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()
  ```
</RequestExample>

## Clear a slot

```http theme={null}
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

<ParamField path="doc_type" type="string" required>
  Same as upload `harvest-list` / `occm` / `aircraft-details` /
  `non-incident-statement`.
</ParamField>

<ParamField path="teardown_id" type="string (UUID)" required />

### Response

`200 OK`:

```jsonc theme={null}
{ "status": "ok" }
```

<RequestExample>
  ```bash harvest-list theme={null}
  curl -X DELETE "$base_url/public/v1/teardown/harvest-list/$teardown_id" \
    -H "Authorization: Bearer $api_key" \
    -H "X-Organization-Id: $org_id"
  ```

  ```bash occm theme={null}
  curl -X DELETE "$base_url/public/v1/teardown/occm/$teardown_id" \
    -H "Authorization: Bearer $api_key" \
    -H "X-Organization-Id: $org_id"
  ```

  ```bash aircraft-details theme={null}
  curl -X DELETE "$base_url/public/v1/teardown/aircraft-details/$teardown_id" \
    -H "Authorization: Bearer $api_key" \
    -H "X-Organization-Id: $org_id"
  ```

  ```bash non-incident-statement theme={null}
  curl -X DELETE "$base_url/public/v1/teardown/non-incident-statement/$teardown_id" \
    -H "Authorization: Bearer $api_key" \
    -H "X-Organization-Id: $org_id"
  ```

  ```python python theme={null}
  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()
  ```
</RequestExample>

## 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](/api-reference/uploads/teardown-documents) for
  the generic (non-slot) document endpoints.
* [Audience](/concepts/audience) for the visibility behaviour of the
  optional `audience` form field.
