---
title: "Delete Staged Attachment"
method: DELETE
path: "/attachments/staged"
---

# Delete Staged Attachment

`DELETE /attachments/staged`

## Request

- Base URL: `https://api.projectindi.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.projectindi.com/attachments/staged`
- Auth: none declared

Best-effort cleanup of a staged file. 401 when unauthenticated,
400 on malformed inputs, 204 otherwise (including when the storage
delete itself fails - that's the genuine best-effort case).

Storage RLS gates the actual delete, and for a STAGED key exactly one
actor gets through: the care-team WORKER who uploaded it. ``Workers can
delete own documents`` (``20260523002437``) is the bucket's only DELETE
policy with no ``documents``-row predicate - it keys on
``owner = auth.uid()``, and ``upload_to_staged_storage`` puts through the
caller's client (``src/upload.py``), so the stager owns the object.

Everyone else is denied, because a staged object has no ``documents`` row
by construction - the same premise ``list_orphaned_staged_objects`` relies
on to sweep it. The clinician and family DELETE policies both require
``EXISTS (SELECT 1 FROM documents d WHERE d.file_url = 'documents/' ||
name)``. That includes the PARENT: the path-scoped policy that once let
them through was dropped in ``20260114100000`` and replaced by the
row-scoped ``Family members can delete own documents``.

So a clinician or parent unstaging their own upload gets a 204 that
deleted nothing, on the Supabase backend; R2 has no RLS and does delete.
Closing it means mirroring the worker policy for the other two stagers -
the same shape with its access predicate swapped, not unexplored ground -
which still widens DELETE on a PHI bucket and wants its own review. Filed
as #7943 with the policy in it; until it lands the 24h worker sweep
(#5092) is the backstop.

Inputs are validated to stop `staged_id=../source`-style traversal at the
route layer - RLS would still bound the blast radius, but explicit
format checks keep the intent legible.

## Query parameters

- `staged_id` string, required
- `filename` string, required
- `child_id` string, required

## Response `200`

Successful Response

- unknown

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/projectindi/apis/indi-agent-api-first-principles.md) - [All operations](https://skmtc.dev/projectindi/apis/indi-agent-api-first-principles/llms.txt) - [OpenAPI document](https://skmtc.dev/projectindi/apis/indi-agent-api-first-principles/revisions/25a7813e21fd?raw)
