Public Keys API
A public key is a key your organization holds the private half of. A channel’s transmit step encrypts a report to it before delivery, and a brief’s Cloak Mode encrypts a report in the reporter’s browser before it is sent; in both cases only the holder of the private key can read the report. Disclose Bot never holds a private key. This page documents the public key resource. Everything here is also in the Platform API reference.
Authentication and base URL
Section titled “Authentication and base URL”Requests are JSON:API over HTTPS against https://api.disclosebot.io/v1 with a service account
bearer token, as described in the API quickstart.
curl https://api.disclosebot.io/v1/public_keys \ -H "Authorization: Bearer disclosebot_svc_xxxxxxxx"The public key object
Section titled “The public key object”| Attribute | Type | Meaning |
|---|---|---|
name | string | A label for the key. |
short_description | string, nullable | Optional notes. |
public_key | string | The key material (below). Surrounding whitespace is removed on save. |
retired | boolean | true when the key is retired (below). |
retired_at | date-time, nullable | When it was retired. |
created_at, updated_at | date-time | Timestamps. |
Relationship: organization.
Key formats
Section titled “Key formats”Encryption uses an X25519 key (NaCl box, the format of libsodium and tweetnacl), stored as the
base64 encoding of its 32 raw bytes, for example 3FcN9hN1m2yVZs6h5N7C1qfq8Rr2Q1pS5xH0u8wZ2mE=.
Only an X25519 key can be chosen for a transmit step or for Cloak Mode; committing a workflow
whose transmit step names another kind of key is refused.
A key of another kind, such as a PGP public key block, can be stored for reference (Disclose Bot records the PGP key a security page publishes this way). It cannot be used for encryption.
Retire a key
Section titled “Retire a key”When you rotate keys, retire the old one instead of deleting it. A retired key:
- is no longer offered for transmit steps or Cloak Mode, and a workflow commit that names it is refused;
- keeps its link to every report and encrypted body encrypted to it, so deliveries of those bodies and the history of those reports stay intact.
Retiring is refused while the key is in use for new encryption: a brief uses it for Cloak Mode, or an enabled channel’s running workflow has a transmit step that encrypts to it. Move those to the new key first. A retired key can be reinstated.
Why a used key cannot be deleted
Section titled “Why a used key cannot be deleted”Deleting a key that reports or bodies were encrypted to would remove the record of which key opens them, and a brief in Cloak Mode would be left without a key. Deleting is therefore refused while encrypted bodies, cloaked reports, or a brief in Cloak Mode reference the key; retire it instead. For the same reason the key material of a used key cannot be changed: add a new key.
Endpoints
Section titled “Endpoints”List public keys
Section titled “List public keys”GET /v1/public_keys
Newest first. Filters: q[name_cont], q[retired_at_null] (true for keys in use, false for
retired keys), and q[s] to sort (for example name asc). Pagination: page[number] and
page[size] (at most 30); the response carries meta.pagination and links (see
Pagination).
curl "https://api.disclosebot.io/v1/public_keys?q[retired_at_null]=true" \ -H "Authorization: Bearer disclosebot_svc_xxxxxxxx"{ "data": [ { "id": "0b6e…", "type": "public_key", "attributes": { "name": "Mobile key", "short_description": null, "public_key": "3FcN9hN1m2yVZs6h5N7C1qfq8Rr2Q1pS5xH0u8wZ2mE=", "retired": false, "retired_at": null, "created_at": "2026-09-10T16:02:11.000Z", "updated_at": "2026-09-10T16:02:11.000Z" }, "relationships": { "organization": { "data": { "id": "6d4d…", "type": "organization" } } } } ], "links": { "self": "…", "first": "…", "last": "…" }}Create a public key
Section titled “Create a public key”POST /v1/public_keys
curl -X POST https://api.disclosebot.io/v1/public_keys \ -H "Authorization: Bearer disclosebot_svc_xxxxxxxx" \ -H "Content-Type: application/vnd.api+json" \ -d '{ "data": { "type": "public_key", "attributes": { "name": "Mobile key", "public_key": "3FcN9hN1m2yVZs6h5N7C1qfq8Rr2Q1pS5xH0u8wZ2mE=" } } }'201 with the key. A blank name or key answers 422.
Show a public key
Section titled “Show a public key”GET /v1/public_keys/{id}
200 with the key; 404 for an unknown id or another organization’s key.
Update, retire, or reinstate a public key
Section titled “Update, retire, or reinstate a public key”PATCH /v1/public_keys/{id}
Send name, short_description, retired, or any of them. retired: true retires the key and
retired: false reinstates it. The key material cannot be changed over the API.
curl -X PATCH https://api.disclosebot.io/v1/public_keys/0b6e… \ -H "Authorization: Bearer disclosebot_svc_xxxxxxxx" \ -H "Content-Type: application/vnd.api+json" \ -d '{ "data": { "type": "public_key", "attributes": { "retired": true } } }'Retiring a key that is in use answers 422 and names what uses it:
{ "errors": [ { "status": "422", "title": "Unprocessable Entity", "detail": "The key is in use by brief Mobile; change them to another key first", "source": { "pointer": "/data/attributes" } } ]}Delete a public key
Section titled “Delete a public key”DELETE /v1/public_keys/{id}
204 for a key nothing references. A key that encrypted reports, a cloaked report, or a brief in
Cloak Mode uses answers 422 with the detail This key is in use by encrypted reports or a cloaking brief; retire it instead.