Skip to main content
The generic document endpoints for a teardown your org owns. For slot-specific documents (harvest list / OCCM / aircraft-details / non-incident-statement), see the slot endpoints.

Upload

POST /public/v1/teardown/documents/{teardown_id}
Attach a document to one of your teardowns. The URL is also appended to the teardown’s documents[] array so it shows up in detail responses.

Headers

Authorization
string
required
Bearer tdao_live_…
X-Organization-Id
string
required
Content-Type
string
required
multipart/form-data (curl’s -F does this automatically).

Form fields

file
file
required
The file to upload.
audience
string (CSV)
Optional. Comma-separated list of company types to restrict who can see documents on this teardown. Allowed: Airline / Lessor / OEM / MRO / Distributor / Others. Case-insensitive. See audience.

File rules

  • Max size: 50 MB per file.
  • Allowed types: PDF, XLSX, XLS, DOCX, DOC, CSV, JPEG, PNG, WEBP, GIF.
  • One file per call. Loop client-side for batch uploads.

Storage path

Files land at:
{SUPABASE_URL}/storage/v1/object/public/teardowns-media/teardowns/<teardown_id>/documents/<8-hex>_<filename>
The 8-character prefix randomises the path so naming collisions are impossible.

Response

200 OK:
{
  "url": "https://.../teardowns-media/teardowns/<id>/documents/abcd1234_specs.pdf",
  "filename": "specs.pdf",
  "size": 123456,
  "content_type": "application/pdf"
}
The URL is also appended to teardown.documents[] automatically no separate PATCH needed.
curl -X POST "$base_url/public/v1/teardown/documents/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/specs.pdf"
curl -X POST "$base_url/public/v1/teardown/documents/$teardown_id" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id" \
  -F "file=@/absolute/path/to/specs.pdf" \
  -F "audience=Airline, MRO, Others"
import requests
with open("specs.pdf", "rb") as f:
    resp = requests.post(
        f"{base_url}/public/v1/teardown/documents/{teardown_id}",
        headers={"Authorization": f"Bearer {api_key}", "X-Organization-Id": org_id},
        files={"file": f},
        data={"audience": "Airline, MRO, Others"},
    )
resp.raise_for_status()
print(resp.json()["url"])
import { readFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("specs.pdf")]), "specs.pdf");
form.append("audience", "Airline, MRO, Others");

const resp = await fetch(
  `${baseUrl}/public/v1/teardown/documents/${teardownId}`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "X-Organization-Id": orgId,
    },
    body: form,
  },
);
const { url } = await resp.json();

Audience write happens BEFORE the upload

If you send an invalid audience value, you get 422 invalid_audience before the file is uploaded. No orphan storage paths.
{
  "detail": {
    "error_code": "invalid_audience",
    "message": "Unknown audience value(s): ['BogusCo']. Allowed (case-insensitive): ['Airline','Lessor','OEM','MRO','Distributor','Others']",
    "got": ["BogusCo"],
    "allowed": ["Airline","Lessor","OEM","MRO","Distributor","Others"]
  }
}
Sending the same audience the teardown already has is a no-op no audit row written.

Delete by URL

DELETE /public/v1/teardown/documents/{teardown_id}/by-url?url=<encoded-url>
Removes a single document URL from the teardown’s documents[]. Best-effort deletes the underlying storage file.

Query parameters

url
string
required
The full document URL (URL-encoded).

Response

200 OK:
{ "status": "ok" }
Idempotent deleting a URL that isn’t present returns 200 too. The storage delete is best-effort; failures are logged but never fail the call.
encoded_url=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1]))" "$DOC_URL")

curl -X DELETE "$base_url/public/v1/teardown/documents/$teardown_id/by-url?url=$encoded_url" \
  -H "Authorization: Bearer $api_key" \
  -H "X-Organization-Id: $org_id"
import requests
resp = requests.delete(
    f"{base_url}/public/v1/teardown/documents/{teardown_id}/by-url",
    headers={"Authorization": f"Bearer {api_key}", "X-Organization-Id": org_id},
    params={"url": doc_url},
)
resp.raise_for_status()

See also