Read the warrant canary
Get the latest signed statement that no authority has asked Veil in secret for user data, with every earlier one.
/v1/canary- Access
- Public; API key optional
- Client
- Browser fetch supported
Request examples#
curl -fsS 'https://veil.rip/v1/canary'const response = await fetch("https://veil.rip/v1/canary");
const { status, current } = await response.json();Try the request#
Response#
status is current, stale or none. current is the latest statement: its signed text and date, the signer’s card and key, the signature and the block. history lists every statement, newest first.
| Field | Type | Meaning |
|---|---|---|
status | string | current, stale (the latest is more than maxAgeDays days old) or none (never signed). |
current | Canary | null | The latest statement, or null when none was ever signed. |
maxAgeDays | integer | Days after its date when a statement turns stale: 35. |
statement | object | The statement in en and it, with {date} where the ISO date goes. |
history | array<Canary> | Every statement, newest date first, the current one included. |
Expand a nested object for its fields. Types ending in null allow a null value; optional fields may be absent. Other fields are present in that object.
Signed statement Canary
| Field | Type | Meaning |
|---|---|---|
id | integer | Statement number on this server. |
date | string | The date the signed text names, YYYY-MM-DD in UTC. |
lang | string | en or it: the language of the signed text. |
text | string | The signed text, exactly: statement.en or statement.it with the date. |
signer | CanarySigner | The owner’s card that signed. |
key | string | The card’s key that made the signature: hex for Ed25519, base64 for a composite key. |
alg | string | ed25519 or mldsa65-ed25519. |
device | string | null | The key’s device name, as the server holds it. |
signature | string | The signature, in the spelling of POST /v1/verify. |
block | string | The signature block as the owner sent it. Check it like any block. |
signedAt | string | When this server took it, ISO 8601 UTC. |
staleAfter | string, optional | On current only: the last date before it is stale, YYYY-MM-DD. |
stale | boolean, optional | On current only: more than maxAgeDays days have passed since its date. |
Signer CanarySigner
| Field | Type | Meaning |
|---|---|---|
n | integer | Permanent card number. |
url | string | Permanent card URL. |
name | string | Current display name; a hidden name becomes Card followed by its number, a closed card an empty string. |
nameHidden | boolean | Whether staff hide the name. |
Response headers#
| Header | Value | Meaning |
|---|---|---|
Content-Type | application/json | Use the declared media type before choosing a parser. |
Date | HTTP date | Server time. Compare it with your clock when signing requests. |
Cache-Control | public, max-age=300 | The answer may be cached for five minutes, as every page’s footer reads it. |
Retry-After | integer seconds, on rate_limited or busy | Wait at least this long before retrying. Other 429/503 codes do not necessarily include it. |
Usage notes#
- This is the server’s copy. To check it, read current.block as a signature block: its text must be statement.en or statement.it with the date, word for word, and a key of the signer’s card must have made the signature. The page /canary does this in the browser, and POST /v1/verify gives the server’s answer.
- A statement is stale once more than maxAgeDays (35) days have passed since its date. Count them from the signed date: stale is the server’s word.
- An owner of the Veil organisation publishes the statement every month with a request signed by a key of their card. That call is for the staff and is not part of this reference.
Errors#
API errors return an error object. Use error.code for program logic; error.message is English text for people and can change. Response and error guide
When using an optional API key
| HTTP | Code | Meaning and next step |
|---|---|---|
| 401 | invalid_api_key | The bearer credential is malformed, unknown, expired or revoked. Use an active key. To use anonymous public access, remove |
| 403 | api_key_scope | The API key lacks read or verify scope, or the endpoint does not accept bearer keys. Use the correct scope. Identity writes and key management still require a device signature. |
| 403 | api_key_suspended | This API key is suspended. Ask staff to restore it; another key cannot lift an account suspension. |
| 403 | developer_suspended | The owner’s API account is suspended or the owner card is unavailable. Check the owner account and any staff restriction. Creating another key does not bypass suspension. |
Shared request errors
| HTTP | Code | Meaning and next step |
|---|---|---|
| 429 | rate_limited | An anonymous, signed-request or API-key allowance was exceeded. Wait at least |
| 500 | internal_error | An unexpected server error occurred. Internal details are not returned. Retry reads with bounded backoff. Check write results before sending a new signed operation. |
| 503 | busy | The application has reached a temporary concurrency or database limit. Wait |