{"revision":"0ed62d2c742f8e20","language":"en","entry":{"id":"lookup","kind":"endpoint","group":"cards","title":"Look up a card","method":"GET","path":"/v1/lookup","paths":[],"summary":"Find the card that holds one exact account, key or fingerprint.","response":"identity is the short card. match gives the normalised query. takeover describes a pending account transfer when present. Fetch the full card for its proof.","parameters":[{"name":"discord","description":"Stable numeric Discord user ID, 17 to 20 digits.","in":"query","required":false},{"name":"github","description":"Numeric GitHub account ID, not its login name.","in":"query","required":false},{"name":"email","description":"The complete email address.","in":"query","required":false},{"name":"domain","description":"Exact domain, without a final dot. International domains use their ASCII A-label.","in":"query","required":false},{"name":"fediverse","description":"The complete @user@server account.","in":"query","required":false},{"name":"key","description":"An Ed25519 public key in hex or the full composite public key in base64. Also a public key from elsewhere as you would paste it: an OpenSSH line with or without comment, an armoured OpenPGP public key, a minisign public key, an ML-DSA key in base64. URL-encode the value.","in":"query","required":false},{"name":"fingerprint","description":"The 12 words in English or Italian, or the 60 digits. Also the fingerprint of a public key from elsewhere: SHA256:… as ssh-keygen -l prints it, a minisign key ID in 16 hex digits, or the 40 hex digits of an OpenPGP fingerprint, in either case, with or without spaces or 0x. An OpenPGP key ID is not enough.","in":"query","required":false}],"sample":"/v1/lookup?key=73ad6159583a43f8ad230a215b758db680efcd3ce32ab8e83c622eeca883e68a","access":"public","base":"directory","notes":["Supply exactly one query parameter. Display names are not unique."],"errors":["400 invalid_parameter","401 invalid_api_key","403 api_key_scope","403 api_key_suspended","403 developer_suspended","404 not_found","429 rate_limited","500 internal_error","503 busy"],"related":[],"sections":[{"kind":"code","language":"shell","code":"curl -fsS 'https://veil.rip/v1/lookup?key=73ad6159583a43f8ad230a215b758db680efcd3ce32ab8e83c622eeca883e68a'"},{"kind":"code","language":"javascript","code":"const response = await fetch(\"https://veil.rip/v1/lookup?key=73ad6159583a43f8ad230a215b758db680efcd3ce32ab8e83c622eeca883e68a\");\nconst result = await response.json();"}],"verify":"Resolve the number, then verify the full card and the matched account in its signed record.","live":true,"responses":[{"status":200,"contentType":"application/json","description":"identity is the short card. match gives the normalised query. takeover describes a pending account transfer when present. Fetch the full card for its proof.","fields":[{"name":"identity","type":"CardLite","description":"Matching short card, without an inclusion proof."},{"name":"match","type":"object","description":"by names the lookup parameter; value is its normalised value. For a public key from elsewhere, value is its fingerprint and external gives type, fp, label and addedIn."},{"name":"takeover","type":"object | null","description":"Pending transfer with toIdentity, openedAt and resolvesAt. Null if none."},{"name":"alert","type":"object | optional","description":"When the card’s owner declared the account looked up stolen, abandoned or moved and has not declared it regained: platform, subject, display, state, since, to, logIndex, publishedAt. Show it before anything else. The server’s word: the card’s page checks it."}]}],"responseObjects":[{"id":"card-lite","title":"Short card","fields":[{"name":"n","type":"integer","description":"Permanent card number."},{"name":"url","type":"string","description":"Permanent URL using the card number."},{"name":"name","type":"string","description":"Current display name; a hidden name becomes Card followed by its number."},{"name":"initials","type":"string","description":"Initials for an image fallback."},{"name":"since","type":"string","description":"Version-one date in YYYY-MM-DD UTC."},{"name":"id","type":"string","description":"Version-one commitment in hex; the source of the fingerprint."},{"name":"version","type":"integer","description":"Current published version."},{"name":"keys","type":"array<CardKey>","description":"All device and recovery keys, including revoked keys."},{"name":"links","type":"array<CardLink>","description":"Linked accounts and pending takeovers."},{"name":"fingerprint","type":"Fingerprint","description":"Twelve words in each language and twelve five-digit groups."},{"name":"type","type":"string","description":"person or organization."},{"name":"nameHidden","type":"boolean","description":"Whether staff hide the name."},{"name":"logo","type":"object, optional","description":"Image type and URL; omitted without a visible image."},{"name":"alias","type":"string | null","description":"Current alias; it can change."},{"name":"aliasUrl","type":"string | null","description":"Current alias address. Use n as the permanent identifier."}],"typeName":"CardLite"},{"id":"card-key","title":"Device key","fields":[{"name":"id","type":"string","description":"Device label shown on the card."},{"name":"alg","type":"string","description":"Readable algorithm name."},{"name":"fp","type":"string","description":"Full public key as stored in the signed record."},{"name":"ed25519","type":"string","description":"Ed25519 key or composite-key half, in hex."},{"name":"since","type":"string","description":"Date the key was added."},{"name":"state","type":"string","description":"active, offline or revoked. Offline denotes a recovery key."},{"name":"revoked","type":"string | null","description":"Revocation date, when revoked."},{"name":"role","type":"string","description":"Signing role assigned to the key."},{"name":"addedIn","type":"integer","description":"Version that added the key."},{"name":"revokedIn","type":"integer | null","description":"Version that revoked the key."}],"typeName":"CardKey"},{"id":"card-link","title":"Linked account","fields":[{"name":"service","type":"string","description":"Platform identifier."},{"name":"handle","type":"string","description":"Display handle or normalised account."},{"name":"id","type":"string | null","description":"Stable provider ID, when separate from the handle."},{"name":"how","type":"string","description":"Proof method, such as oauth, dns_txt, well_known, emailCode or backlink."},{"name":"at","type":"string","description":"Time the link was established."},{"name":"state","type":"string","description":"active or pending."},{"name":"until","type":"string | null","description":"Pending takeover deadline."},{"name":"takeover","type":"integer | null","description":"Pending takeover ID."},{"name":"unicode","type":"string, optional","description":"Unicode spelling of an international domain. Keep the ASCII handle as the identifier."},{"name":"addedIn","type":"integer | null","description":"Version that added the link."},{"name":"logIndex","type":"integer | null","description":"Zero-based log index of that version."},{"name":"check","type":"CardLinkCheck, optional","description":"The server’s periodic re-check of the proof (since 30 October 2026), for an active domain, Fediverse or GitHub link it has checked at least once. Its word, not part of the signed card."}],"typeName":"CardLink"},{"id":"card-link-check","title":"Re-check of a proof","fields":[{"name":"state","type":"string","description":"ok, failing (the place answered and the proof is not there) or unreachable (no answer)."},{"name":"at","type":"string","description":"Time of the last check that got an answer."},{"name":"since","type":"string, optional","description":"Since when the proof has not confirmed. Absent while ok."},{"name":"reported","type":"boolean","description":"True once 30 days passed without a confirmation and the owner was told. The link stays."}],"typeName":"CardLinkCheck"},{"id":"fingerprint","title":"Card fingerprint","fields":[{"name":"words","type":"object","description":"en and it each contain the same twelve word-list positions in their language."},{"name":"digits","type":"array<string>","description":"Twelve groups of five decimal digits."}],"typeName":"Fingerprint"}],"errorFormat":"json","errorDetails":[{"status":400,"code":"invalid_parameter","description":"A path, query or body field is missing, malformed or outside its accepted range.","action":"Correct the field named in `error.message` before sending again.","scope":"endpoint"},{"status":401,"code":"invalid_api_key","description":"The bearer credential is malformed, unknown, expired or revoked.","action":"Use an active key. To use anonymous public access, remove `Authorization` entirely. Invalid credentials never fall back automatically.","scope":"optional-api-key"},{"status":403,"code":"api_key_scope","description":"The API key lacks read or verify scope, or the endpoint does not accept bearer keys.","action":"Use the correct scope. Identity writes and key management still require a device signature.","scope":"optional-api-key"},{"status":403,"code":"api_key_suspended","description":"This API key is suspended.","action":"Ask staff to restore it; another key cannot lift an account suspension.","scope":"optional-api-key"},{"status":403,"code":"developer_suspended","description":"The owner’s API account is suspended or the owner card is unavailable.","action":"Check the owner account and any staff restriction. Creating another key does not bypass suspension.","scope":"optional-api-key"},{"status":404,"code":"not_found","description":"The requested card, key, alias, code or resource was not found.","action":"Check the identifier. Temporary codes and previews may already have expired or been used.","scope":"endpoint"},{"status":429,"code":"rate_limited","description":"An anonymous, signed-request or API-key allowance was exceeded.","action":"Wait at least `Retry-After` seconds. Share a queue and retry budget across your workers.","scope":"common"},{"status":500,"code":"internal_error","description":"An unexpected server error occurred. Internal details are not returned.","action":"Retry reads with bounded backoff. Check write results before sending a new signed operation.","scope":"common"},{"status":503,"code":"busy","description":"The application has reached a temporary concurrency or database limit.","action":"Wait `Retry-After` seconds and retry with bounded backoff.","scope":"common"}],"responseHeaders":[{"name":"Content-Type","value":"application/json","description":"Use the declared media type before choosing a parser."},{"name":"Date","value":"HTTP date","description":"Server time. Compare it with your clock when signing requests."},{"name":"Retry-After","value":"integer seconds, on rate_limited or busy","description":"Wait at least this long before retrying. Other 429/503 codes do not necessarily include it."}],"documentationUrl":"https://veil.rip/docs/lookup","supportsBrowserFetch":true,"browserMode":"fetch"}}