veil

Read the warrant canary

Get the latest signed statement that no authority has asked Veil in secret for user data, with every earlier one.

GET/v1/canary
Access
Public; API key optional
Client
Browser fetch supported

Request examples#

cURL
curl -fsS 'https://veil.rip/v1/canary'
javascript
const response = await fetch("https://veil.rip/v1/canary");
const { status, current } = await response.json();

Try the request#

Response#

HTTP 200application/json

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.

FieldTypeMeaning
statusstringcurrent, stale (the latest is more than maxAgeDays days old) or none (never signed).
currentCanary | nullThe latest statement, or null when none was ever signed.
maxAgeDaysintegerDays after its date when a statement turns stale: 35.
statementobjectThe statement in en and it, with {date} where the ISO date goes.
historyarray<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
FieldTypeMeaning
idintegerStatement number on this server.
datestringThe date the signed text names, YYYY-MM-DD in UTC.
langstringen or it: the language of the signed text.
textstringThe signed text, exactly: statement.en or statement.it with the date.
signerCanarySignerThe owner’s card that signed.
keystringThe card’s key that made the signature: hex for Ed25519, base64 for a composite key.
algstringed25519 or mldsa65-ed25519.
devicestring | nullThe key’s device name, as the server holds it.
signaturestringThe signature, in the spelling of POST /v1/verify.
blockstringThe signature block as the owner sent it. Check it like any block.
signedAtstringWhen this server took it, ISO 8601 UTC.
staleAfterstring, optionalOn current only: the last date before it is stale, YYYY-MM-DD.
staleboolean, optionalOn current only: more than maxAgeDays days have passed since its date.
Signer CanarySigner
FieldTypeMeaning
nintegerPermanent card number.
urlstringPermanent card URL.
namestringCurrent display name; a hidden name becomes Card followed by its number, a closed card an empty string.
nameHiddenbooleanWhether staff hide the name.

Response headers#

HeaderValueMeaning
Content-Typeapplication/jsonUse the declared media type before choosing a parser.
DateHTTP dateServer time. Compare it with your clock when signing requests.
Cache-Controlpublic, max-age=300The answer may be cached for five minutes, as every page’s footer reads it.
Retry-Afterinteger seconds, on rate_limited or busyWait 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
HTTPCodeMeaning and next step
401invalid_api_key

The bearer credential is malformed, unknown, expired or revoked.

Use an active key. To use anonymous public access, remove Authorization entirely. Invalid credentials never fall back automatically.

403api_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.

403api_key_suspended

This API key is suspended.

Ask staff to restore it; another key cannot lift an account suspension.

403developer_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
HTTPCodeMeaning and next step
429rate_limited

An anonymous, signed-request or API-key allowance was exceeded.

Wait at least Retry-After seconds. Share a queue and retry budget across your workers.

500internal_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.

503busy

The application has reached a temporary concurrency or database limit.

Wait Retry-After seconds and retry with bounded backoff.