veil

Create an organisation

Publish an organisation’s first record, signed by its founder’s active person key.

POST/v1/organizations
Access
Signed request
Client
Local or server client

JSON body#

NameLocationMeaning
recordRequiredJSONThe complete canonical identity or organisation record, including its history fields.
signatureRequiredJSONThe record signature, separate from the request signature header.
logoDataJSONThe image that record.logo names by hash, in standard padded base64 on one line. Required when the version brings a new image. With an unchanged image it can be left out, and if sent it must match.
nonceRequiredJSONA fresh 16 to 128 character nonce using letters, digits, underscore or hyphen.
timestampRequiredJSONUnix milliseconds within two minutes of the server clock.
clientSalt, saltTicketJSONOptional pair for the first version. Request the ticket before drawing the client salt.
labelJSONFormat 2: the label as a JSON object; the server encodes it canonically and checks the signature on those bytes.
bodyJSONFormat 2: the body as a JSON object, its hash in label.body.
pictureDataJSONFormat 2: the bytes of a new picture the body names by hash, in standard padded base64.

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 \
  -H "X-Public-Key: $PUBLIC_KEY" \
  -H "X-Signature: $REQUEST_SIGNATURE" --json @request.json \
  "https://veil.rip/v1/organizations"

Response#

HTTP 201application/json

201 with n, id, url, token, version, commitment, logIndex, publishedAt and checkpoint. The response follows witnessed publication.

FieldTypeMeaning
nintegerPermanent card number.
idstringVersion-one commitment in hex.
urlstringPermanent card URL.
tokenstringStable log pseudonym in base64url.
versionintegerPublished version number.
commitmentstringThis version’s commitment in hex.
logIndexintegerZero-based log index.
publishedAtstringEarliest cosignature time at publication.
checkpointCheckpointFirst checkpoint covering the version.

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.

Checkpoint Checkpoint
FieldTypeMeaning
sizeintegerNumber of leaves in the signed tree.
rootstringRoot hash in base64.
notestringFull signed note, including log and witness signatures.

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.
Locationrelative URLPublished card/proof address, or permanent widget redirect target.
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#

  • On a log in format 2 the body is {label, body, signature, pictureData?}, with clientSalt and saltTicket required for version 1; a record is refused with wrong_format.

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_alias

The alias does not meet the ASCII name rules.

Use 3 to 32 lowercase ASCII letters, digits, hyphens or underscores; start with a letter and end with a letter or digit.

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_name

A name contains invisible, direction-control or unsupported format characters.

Use a visible name in the accepted Unicode form and sign the corrected request.

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.

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.

403identity_banned

The acting identity is suspended by Veil staff.

Wait for the restriction to end or ask staff to review it.

403key_mismatch

The signing key does not have authority over this card or operation.

Use an active device key with the required owner or member role.

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.

409account_locked

Moderation prevents this account from being claimed.

Check the current card’s public moderation state.

409alias_quarantined

The alias is in its 30-day release quarantine.

Inspect reusableAt and the previous holder through the alias endpoint.

409alias_reserved

The chosen alias is reserved for the service.

Choose another alias.

409alias_taken

The alias is claimed or a publication has reserved it.

Choose another alias or check availability again after the publication finishes.

409already_member

This membership already exists.

Read current memberships before publishing another invitation.

409grant_used

A verification or membership grant has already been consumed.

Check the resulting card version, then obtain a fresh grant if still needed.

409identity_exists

An identity already uses this token.

Check the existing publication. Generate a new identity only when a different card is intended.

409invitation_withdrawn

The organisation no longer offers the invitation.

Ask for a new invitation.

409key_already_used

A device key already belongs to an identity and cannot be reused by another.

Use the existing card or generate a fresh device key.

409salt_ticket_invalid

The salt ticket is unknown, expired or already consumed.

Request a fresh ticket and rebuild and sign version one with it.

409takeover_already_open

A takeover for this linked account is already open.

Read the pending takeover instead of opening another.

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.

410erased

The card existed and was erased or removed. The response also carries its public erasure receipt.

Stop using this card as current authority. Retain only the public receipt if needed.

413payload_too_large

The request body exceeds this endpoint’s byte limit.

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

422grant_expired

The verification or membership grant expired.

Obtain a fresh grant before publishing the version.

422invalid_grant

The verification or membership grant is invalid or belongs to another operation.

Use the grant issued for this exact card, account or membership.

422invalid_op

An operation is unknown, malformed, not one of this card’s type or version, or changes nothing.

Correct the operation named in error.message.

422invalid_record

The identity version violates the signed-record rules.

Correct the validation issue, canonicalise the record and sign it again.

422invalid_record_signature

The identity-version signature does not verify.

Sign the exact canonical record with its identity-version prefix and declared key.

422label_mismatch

The label’s prev, body, auth or state is not what the chain, the body and the operations give.

Read the card again, plan the operations on its current state and sign the new label.

422last_owner

The change would leave an organisation without an accepted owner.

Add or accept another owner before removing the last one.

422membership_needs_grant

An organisation membership lacks its acceptance grant.

Accept the invitation and include its grant in the next signed version.

422not_an_organization

The card is a person where an organisation is required.

Use the person endpoint or an organisation card.

502log_mismatch

The log response did not match the expected signed entry or proof.

Do not accept the publication as verified. Check the card and log before retrying.

503log_unavailable

The public log cannot currently be read, verified or used for publication.

For reads, keep the result unverified and try later. Before retrying a write, read the card to check whether publication completed.

Shared request errors
HTTPCodeMeaning and next step
400invalid_nonce

The signed-request nonce has an invalid format.

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

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.

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.

409replayed_nonce

The signing key already used this nonce.

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

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.