Destroy the key for a held document, and certify it on Sui.
const url = 'https://testnet.permafrost.live/v1/api/custody/incinerate/3f2a9c18-5b7e-4d61-9a0c-8e2f1d4b6a37';const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://testnet.permafrost.live/v1/api/custody/incinerate/3f2a9c18-5b7e-4d61-9a0c-8e2f1d4b6a37 \ --header 'Authorization: Bearer <token>'This does not come back. The key is destroyed first, and only then is the certificate minted — so a failure to mint never leaves a key alive behind a response that said it was gone.
The answer is the same shape status returns. Read certificate_status
to know what landed:
| Value | Meaning |
|---|---|
minted |
The key is destroyed and the certificate exists. Its object id and transaction digest are in the body. |
not_minted |
The key is destroyed and no certificate landed. The destruction is no less final. |
Calling it again on an object already deleted is safe: it returns the existing receipt and destroys nothing twice.
This route draws on a separate, tighter allowance than the rest of the surface, because it is irreversible. A short burst is allowed; a runaway client exhausts the budget long before it gets through a meaningful number of objects.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Example
3f2a9c18-5b7e-4d61-9a0c-8e2f1d4b6a37The custody object identifier returned by POST /v1/api/custody/store.
Responses
Section titled “Responses”The key is destroyed. The body says whether a certificate landed.
The custody view of one held document. No key, key identifier, custody backend or owner appears here.
object
Sha256 of the plaintext — the hash the certificate names.
Sha256 of the stored ciphertext — the hash the verify route indexes.
True while the key lives and the document can still be served.
The complement of alive. True once the key has been destroyed.
When the key was destroyed, in UTC. null while it lives.
The on-chain certificate’s object id, once one has been minted.
The transaction that minted the certificate.
minted once the certificate exists. not_minted when the key was
destroyed and no certificate landed — the destruction is no less
final for it.
The claim the certificate makes, recorded on chain verbatim:
auditable_vendor_side. null while the document is alive.
Example
{ "id": "3f2a9c18-5b7e-4d61-9a0c-8e2f1d4b6a37", "content_hash": "7d1a2b3c4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9", "stored_hash": "0c9b8a7d6e5f40312213a4b5c6d7e8f90a1b2c3d4e5f6071829304b5c6d7e8fa", "alive": false, "incinerated": true, "incinerated_at": "2026-09-13T15:02:44Z", "certificate_object_id": "0xb4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3", "certificate_tx_digest": "8xJ2kQ9mVb3TcYw6RfN1sLpA4dZhG7uEoX5nK0iMrQvB", "certificate_status": "minted", "deletion_mode": "auditable_vendor_side"}No tenant on the request. Through the public edge this is the edge’s own refusal of the credential; the custody surface’s own generic refusal has the same status and carries no hint about which header, which surface, or whether the id exists.
The refusal shape. detail is present on a few routes and deliberately
absent from the custody surface, where a detail string could carry an
internal path.
object
The code, or a short fixed sentence.
A human-readable note, where a route carries one.
Example
{ "error": "unauthorized"}No such custody object, an object owned by another tenant, or an object with no owner recorded. One answer for all three.
The refusal shape. detail is present on a few routes and deliberately
absent from the custody surface, where a detail string could carry an
internal path.
object
The code, or a short fixed sentence.
A human-readable note, where a route carries one.
Example
{ "error": "not found"}The tenant is over an allowance. Retry-After carries whole seconds,
rounded up and never zero. The per-tenant refusal also carries
retry_after_ms; the custody surface’s own local limiter carries the
code alone. Both are per tenant, keyed by the tenant address — one
tenant spending its allowance does not consume another’s.
object
How long until one token is available, in milliseconds. Present on the per-tenant refusal.
Example
{ "error": "rate_limited", "retry_after_ms": 240}Headers
Section titled “Headers”Example
1Whole seconds to wait before retrying.
Permafrost runs on Sui testnet and Walrus testnet. Everything here describes a shipped testnet instance, not a production service.