veil

Approve a move

At the old address, signed by an active device key of the card: the card's next version that adds the move's key as a device, the receipt and the SHA-256 of the secret. Checked as a publication would be, kept and not published.

POST/v1/moves/{nonce}/approve
Access
Signed request
Client
Local or server client

Parameters#

NameLocationMeaning
nonceRequiredPathThe move's nonce: 22 characters of base64url.

JSON body#

NameLocationMeaning
labelRequiredJSONThe version's label, as for a publication.
bodyRequiredJSONThe version's body.
signatureRequiredJSONThe label's signature by the key that signs the request.
secretHashRequiredJSONSHA-256 of the move's 32-byte secret, lowercase hex.
retireRequiredJSONWhether the old key retires itself afterwards.
chatRequiredJSONWhether the old browser holds chat keys to hand over.
receiptRequiredJSONThe receipt, veil-rubrica:move-receipt:v1 and its eight lines.
receiptSignatureRequiredJSONThe receipt's Ed25519 signature in hex by the same key.

This call also needs the common signed-request headers, nonce and timestamp. Prepare and sign request.json before using the example. Request signing

Request examples#

cURL
curl -fsS -X POST 'https://veil.pub/v1/moves/MOVE_NONCE/approve' \
  -H "X-Public-Key: $OLD_KEY" -H "X-Signature: $REQUEST_SIGNATURE" --json @approval.json

Response#

HTTP 200application/json

200 with nonce, identity and version.

FieldTypeMeaning
noncestringThe move.
identityintegerThe card's number.
versionintegerThe version that adds the new key.

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-Controlno-storeDo not persist private or temporary responses in a shared cache.
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#

  • Moving a browser from the directory's old address to its new one (since 6 November 2026): a key lives on the origin that made it, so the new address makes a key of its own and the card adds it with a version signed at the old address, in the same browser. The version is kept until the new key comes back with the secret.

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

HTTPCodeMeaning and next step
400invalid_json

The body is not a JSON object, contains duplicate keys or has trailing data.

Send one valid JSON object with Content-Type application/json.

400invalid_nonce

The signed-request nonce has an invalid format.

Generate a fresh 16 to 128-character nonce using letters, digits, _ or -.

400invalid_parameter

A path, query or body field is missing, malformed or outside its accepted range.

Correct the field named in error.message before sending again.

400invalid_signature_alg

X-Signature-Alg is unsupported.

Use a supported signing algorithm and matching key/signature encoding.

400invalid_timestamp

The signed-request timestamp is not Unix milliseconds.

Use an integer Unix timestamp in milliseconds and sign the corrected request.

400wrong_format

The request or the read belongs to the other log format than this server’s: a v1 record on a format 2 log, or a format 2 read on a format 1 log.

Read format in GET /v1/log (absent means 1) and send the shape of that format.

401invalid_signature

The HTTP request signature does not verify.

Sign the exact method, path and body bytes, without changing them afterwards.

401missing_signature

The request requires a device signature and its headers are missing or unreadable.

Send X-Public-Key, X-Signature and the signed-request metadata. An API key does not replace a device signature.

401stale_timestamp

The signed timestamp is outside the accepted clock window.

Compare the server Date header with your clock, then generate a fresh nonce, timestamp and signature.

403key_banned

The device signing key is suspended by Veil staff.

Use an authorised active key or ask staff to review the restriction.

403signer_not_authorised

The organisation member or signing role cannot publish this change.

Check accepted membership and the role required for the change.

404no_move

This directory has one address, so there is no browser to move.

Make a card or log in at this address.

404not_found

The requested card, key, alias, code or resource was not found.

Check the identifier. Temporary codes and previews may already have expired or been used.

409move_approved

The move was approved already.

Complete it from the new address, or start a new move.

409move_done

The move is done: the new key is on the card.

Nothing to do. Read the card to see the new key.

409replayed_nonce

The signing key already used this nonce.

Check whether the previous request succeeded before making a fresh signed request.

409version_conflict

The version cannot be published against the card’s current state.

Read the latest card, reconcile the intended change and sign a new version.

410move_expired

The move waited more than ten minutes.

Start a new move.

413payload_too_large

The request body exceeds this endpoint’s byte limit.

Reduce the encoded body. API-key management accepts at most 8 KiB.

422invalid_move

The approval is not a move: its version must add exactly the move's key as a device of the card, and its receipt must name the move, the card, the two keys, the version and the choices, signed by the key that signs the request.

Build the version and the receipt again from the card and the move as they are now.

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.