{"revision":"0ed62d2c742f8e20","language":"en","entry":{"id":"request-erasure","kind":"endpoint","group":"manage","title":"Request card erasure","method":"POST","path":"/v1/identities/{n}/erase","paths":[],"summary":"An active person key or an organisation owner signs the erasure request. There is a 24-hour cancellation window.","response":"202 with n, requestedAt, executesAt and key. Erasure removes record openings after the cancellation window while keeping the public log’s commitments.","parameters":[{"name":"n","description":"Permanent positive card number.","in":"path","required":true}],"sample":"/v1/identities/1/erase","access":"signed","base":"directory","notes":["On a log in format 2 signer of the closing is the card itself for a person, and the requesting owner’s own card for an organisation. The server writes the closing to the log when the erasure runs, and the closed card then answers 410 with closed."],"errors":["400 invalid_json","400 invalid_nonce","400 invalid_parameter","400 invalid_signature_alg","400 invalid_timestamp","401 invalid_signature","401 missing_signature","401 stale_timestamp","403 key_banned","403 key_mismatch","404 not_found","409 erase_already_requested","409 replayed_nonce","409 signer_stale","409 version_conflict","410 erased","413 payload_too_large","422 bad_entry","422 closing_required","422 invalid_statement_signature","422 last_owner","422 staff_org_target","429 rate_limited","500 internal_error","503 busy"],"related":["signed-requests"],"sections":[{"kind":"code","language":"shell","code":"curl -fsS -X POST \\\n  -H \"X-Public-Key: $PUBLIC_KEY\" \\\n  -H \"X-Signature: $REQUEST_SIGNATURE\" --json @request.json \\\n  \"https://veil.rip/v1/identities/1/erase\""},{"kind":"code","language":"text","code":"veil-rubrica:erase:v1\n<CARD_TOKEN>\n<TIME_UNIX_SECONDS>"},{"kind":"code","language":"text","code":"veil-rubrica:close-entry:v2\n{\"key\":\"<PUBLIC_KEY>\",\"kind\":\"closed\",\"latest\":\"<CURRENT_LABEL_HASH>\",\"signer\":{\"identity\":\"<SIGNER_TOKEN>\",\"n\":<SIGNER_VERSION>},\"time\":<TIME_UNIX_SECONDS>,\"token\":\"<CARD_TOKEN>\",\"v\":2}"}],"bodyFields":[{"name":"time","description":"Unix seconds within five minutes of the server clock. This is also part of the erasure statement.","in":"body","required":true},{"name":"signature","description":"The erasure-statement signature using the same key as X-Public-Key.","in":"body","required":true},{"name":"closing","description":"Format 2, and required there: the closing entry {text, signature} signed with the same key. text is the canonical entry without its signature, with key, kind closed, latest (the hash of the card’s current label), signer, time, token and v. signature covers veil-rubrica:close-entry:v2 and a line break followed by text.","in":"body","required":false}],"live":false,"responses":[{"status":202,"contentType":"application/json","description":"202 with n, requestedAt, executesAt and key. Erasure removes record openings after the cancellation window while keeping the public log’s commitments.","fields":[{"name":"n","type":"integer","description":"Card scheduled for erasure."},{"name":"requestedAt","type":"string","description":"Request time."},{"name":"executesAt","type":"string","description":"Scheduled execution time after the cooling period."},{"name":"key","type":"string","description":"Public key that signed the erasure request."}]}],"responseObjects":[],"errorFormat":"json","errorDetails":[{"status":400,"code":"invalid_json","description":"The body is not a JSON object, contains duplicate keys or has trailing data.","action":"Send one valid JSON object with `Content-Type` application/json.","scope":"endpoint"},{"status":400,"code":"invalid_nonce","description":"The signed-request nonce has an invalid format.","action":"Generate a fresh 16 to 128-character nonce using letters, digits, _ or -.","scope":"common"},{"status":400,"code":"invalid_parameter","description":"A path, query or body field is missing, malformed or outside its accepted range.","action":"Correct the field named in `error.message` before sending again.","scope":"endpoint"},{"status":400,"code":"invalid_signature_alg","description":"`X-Signature-Alg` is unsupported.","action":"Use a supported signing algorithm and matching key/signature encoding.","scope":"common"},{"status":400,"code":"invalid_timestamp","description":"The signed-request timestamp is not Unix milliseconds.","action":"Use an integer Unix timestamp in milliseconds and sign the corrected request.","scope":"common"},{"status":401,"code":"invalid_signature","description":"The HTTP request signature does not verify.","action":"Sign the exact method, path and body bytes, without changing them afterwards.","scope":"common"},{"status":401,"code":"missing_signature","description":"The request requires a device signature and its headers are missing or unreadable.","action":"Send `X-Public-Key`, `X-Signature` and the signed-request metadata. An API key does not replace a device signature.","scope":"common"},{"status":401,"code":"stale_timestamp","description":"The signed timestamp is outside the accepted clock window.","action":"Compare the server Date header with your clock, then generate a fresh nonce, timestamp and signature.","scope":"common"},{"status":403,"code":"key_banned","description":"The device signing key is suspended by Veil staff.","action":"Use an authorised active key or ask staff to review the restriction.","scope":"common"},{"status":403,"code":"key_mismatch","description":"The signing key does not have authority over this card or operation.","action":"Use an active device key with the required owner or member role.","scope":"endpoint"},{"status":404,"code":"not_found","description":"The requested card, key, alias, code or resource was not found.","action":"Check the identifier. Temporary codes and previews may already have expired or been used.","scope":"endpoint"},{"status":409,"code":"erase_already_requested","description":"An erasure is already waiting.","action":"Read its scheduled execution time from the card.","scope":"endpoint"},{"status":409,"code":"replayed_nonce","description":"The signing key already used this nonce.","action":"Check whether the previous request succeeded before making a fresh signed request.","scope":"common"},{"status":409,"code":"signer_stale","description":"On a format 2 log, `signer.n` of a signed entry is behind the current version of the card that signs.","action":"Read the signing card again and sign the entry with its current version in `signer.n`.","scope":"endpoint"},{"status":409,"code":"version_conflict","description":"On a format 2 log, a version of this card is still on its way to the log. The closing must name the card’s current version.","action":"Wait until the version is in the log, read the card again and sign a new closing.","scope":"endpoint"},{"status":410,"code":"erased","description":"The card existed and was erased or removed. The response also carries its public erasure receipt.","action":"Stop using this card as current authority. Retain only the public receipt if needed.","scope":"endpoint"},{"status":413,"code":"payload_too_large","description":"The request body exceeds this endpoint’s byte limit.","action":"Reduce the encoded body. API-key management accepts at most 8 KiB.","scope":"endpoint"},{"status":422,"code":"bad_entry","description":"On a format 2 log, the `salt`, `entry` or `closing` of a request is wrong. `error.message` names the field.","action":"Correct the named field, sign the entry again with the request key and send a new signed request.","scope":"endpoint"},{"status":422,"code":"closing_required","description":"On a format 2 log, an erasure arrived without its signed closing entry in `closing`.","action":"Sign the closing entry with the same key and send it as `closing`, with `text` and `signature`.","scope":"endpoint"},{"status":422,"code":"invalid_statement_signature","description":"The signed erasure statement does not verify.","action":"Sign the exact statement bytes with the required prefix and key.","scope":"endpoint"},{"status":422,"code":"last_owner","description":"The change would leave an organisation without an accepted owner.","action":"Add or accept another owner before removing the last one.","scope":"endpoint"},{"status":422,"code":"staff_org_target","description":"This operation cannot target Veil’s staff organisation.","action":"Choose an eligible target.","scope":"endpoint"},{"status":429,"code":"rate_limited","description":"An anonymous, signed-request or API-key allowance was exceeded.","action":"Wait at least `Retry-After` seconds. Share a queue and retry budget across your workers.","scope":"common"},{"status":500,"code":"internal_error","description":"An unexpected server error occurred. Internal details are not returned.","action":"Retry reads with bounded backoff. Check write results before sending a new signed operation.","scope":"common"},{"status":503,"code":"busy","description":"The application has reached a temporary concurrency or database limit.","action":"Wait `Retry-After` seconds and retry with bounded backoff.","scope":"common"}],"responseHeaders":[{"name":"Content-Type","value":"application/json","description":"Use the declared media type before choosing a parser."},{"name":"Date","value":"HTTP date","description":"Server time. Compare it with your clock when signing requests."},{"name":"Retry-After","value":"integer seconds, on rate_limited or busy","description":"Wait at least this long before retrying. Other 429/503 codes do not necessarily include it."}],"documentationUrl":"https://veil.rip/docs/request-erasure","supportsBrowserFetch":false,"browserMode":"local-or-server"}}