# GDPR Article 17 — Right to Erasure Endpoint **Flagship:** a11oy **Endpoint:** `POST /api/a11oy/v2/erase` **Doctrine v11 — 749 / 14 / 163 — replay hash c7c0ba17** **Updated:** 2026-06-02 --- ## Summary Public flagships do not store end-user PII. All HF Spaces are unauthenticated and public. This endpoint exists as the GDPR Article 17 minimum viable surface: it accepts an erasure request, signs a receipt (whether or not any data exists to erase), and returns that signed receipt to the caller. --- ## Request ```http POST /api/a11oy/v2/erase Content-Type: application/json { "caller_id": "", "confirmation": "DELETE-MY-DATA" } ``` **Fields:** | Field | Type | Required | Description | |---|---|---|---| | `caller_id` | string | yes | Caller-supplied identifier (not stored, used only in the receipt label) | | `confirmation` | string | yes | Must be the literal string `DELETE-MY-DATA` | --- ## Response ```json { "status": "acknowledged", "message": "Public flagships don't store user PII. Khipu chain receipts are auditable, not PII. Personal data deletion via rosie /api/rosie/v2/unay/erase (separate handler for operator session memory). Audit-trail receipt of this deletion request signed and returned.", "receipt": { "payload": { "type": "gdpr_erase_request", "flagship": "a11oy", "caller_id_label": "", "ts": "", "doctrine": { "declarations": 749, "axioms": 14, "sorries": 163, "replay_hash": "c7c0ba17" } }, "signature": "", "prev_hash": "" } } ``` --- ## What data is and is not held | Data class | Held by a11oy? | Notes | |---|---|---| | PII from HF Space callers | **No** | HF Spaces are unauthenticated; no accounts, no cookies | | Khipu chain receipts | Yes (audit trail) | Receipts are cryptographic audit records, not PII; deletion would break chain integrity | | Operator session memory (rosie only) | rosie only | Route to `POST /api/rosie/v2/unay/erase` for operator session data | | GitHub interaction data | GitHub (not us) | Contact GitHub directly for their data deletion | --- ## Implementation Reference The endpoint handler (`serve.py`) must: 1. Validate `confirmation == "DELETE-MY-DATA"` — return 400 if not. 2. Build a receipt payload with `type: "gdpr_erase_request"`, `flagship`, `caller_id_label`, `ts`, and `doctrine` numbers. 3. Sign via `szl_dsse.sign(payload, WIRE_D_SIGNING_KEY)` — return 500 if signing fails. 4. Return 200 with `status: "acknowledged"` and the signed receipt. 5. **Do not log** `caller_id` beyond the signed receipt. 6. **Do not store** the request (the signed receipt itself is the audit trail). ```python # Reference implementation (docs/reference; do not copy verbatim into serve.py without review) from fastapi import APIRouter, HTTPException from pydantic import BaseModel import szl_dsse, datetime, os router = APIRouter() class EraseRequest(BaseModel): caller_id: str confirmation: str @router.post("/api/a11oy/v2/erase") async def gdpr_erase(body: EraseRequest): if body.confirmation != "DELETE-MY-DATA": raise HTTPException(400, "confirmation must be 'DELETE-MY-DATA'") payload = { "type": "gdpr_erase_request", "flagship": "a11oy", "caller_id_label": body.caller_id, "ts": datetime.datetime.utcnow().isoformat() + "Z", "doctrine": {"declarations": 749, "axioms": 14, "sorries": 163, "replay_hash": "c7c0ba17"}, } key = os.environ.get("WIRE_D_SIGNING_KEY") if not key: raise HTTPException(500, "Signing key not configured") receipt = szl_dsse.sign(payload, key) return { "status": "acknowledged", "message": ( "Public flagships don't store user PII; Khipu chain receipts are auditable not PII. " "Personal data deletion via rosie /api/rosie/v2/unay/erase (separate handler). " "Audit-trail receipt of deletion request signed." ), "receipt": receipt, } ``` --- ## Routing to rosie For operator session memory (if applicable), route the request to rosie: ```http POST https://SZLHOLDINGS-rosie.hf.space/api/rosie/v2/unay/erase Content-Type: application/json { "caller_id": "", "confirmation": "DELETE-MY-DATA" } ``` --- *Co-Authored-By: Perplexity Computer Agent* *Doctrine v11 — 749/14/163 — c7c0ba17*