Developers
Three endpoints anybody can call, and one you should
Verus publishes a small open surface on purpose. You can ask any deployment what it is and what its database is incapable of holding, and you can check an identity claim against the deployment that issued it, from a browser, on any origin, with no account and no key. That is the whole point: the claims Verus makes about itself are meant to be checked rather than believed.
The base URL for the deployment this site describes is https://api.verusapp.co.uk. A sovereign deployment is a different host answering the same routes, which is why nothing below hardcodes ours.
API reference OpenAPI 3.1 document
The reference is served by the deployment itself and read from it live, field by field. The OpenAPI document covers the open routes and loads into Swagger Editor, Postman or any OpenAPI tool.
Questions, access, or something you want that is not here: developers@verusapp.co.uk. A person reads it.
The open endpoints
All three carry access-control-allow-origin: * and accept GET and OPTIONS, so a page on your domain can call them directly. There is no key to obtain and no registration. Because your browser makes the call, the deployment sees you and this website does not.
GET
/v1/health
Whether the deployment is answering, and its clock.
{ "status": "ok", "time": 1787591603 }
GET
/v1/deployment
What this deployment is, what it holds, and what it declares it never holds. The last two are computed from the live database schema on every request rather than written down, so the answer cannot drift from the thing it describes. Open it in a browser for a readable reference; send Accept: application/json, or add ?format=json, for the raw response.
{
"name": "Verus",
"mode": "standard",
"jurisdiction": "GB",
"deploymentKey": "yDEBxYT4lUNq...",
"confrmoLogin": true,
"push": true,
"subscriptions": true,
"limits": { "maxEnvelopeBytes": 65536, "maxQueuedEnvelopes": 5000, ... },
"holds": { "account": ["address", "identity_key", ...], ... },
"neverHolds": { "account": ["name", "phone", "email", "ip", ...], ... }
}
GET
/v1/claims/:id
60 requests a minute
Everything this deployment will say about one identity claim. The signature is checked against the deployment key on every call, so a forged claim is caught here rather than believed.
{
"id": "...",
"address": "7PDM0F7XND2Y259JFN9XJQTM",
"rpDomain": "verusapp.co.uk",
"method": "confrmo_session_consume",
"issuedAt": 1787500000,
"expiresAt": 1787586400,
"revoked": false,
"expired": false,
"live": true,
"assurance": "confirmed",
"checkedAt": 1780000000,
"signatureValid": true,
"signature": "...",
"issuer": "yDEBxYT4lUNq..."
}
Everything else on the deployment requires a signature, and that is not a paywall: those routes act on somebody's account, and an account here is a key rather than a login, so there is nothing to authenticate with except the key.
Reading a claim properly
If you build one thing against Verus, build this. A verifier that answers yes or no is not much of a verifier: a revoked claim still carries a perfectly valid signature, and the difference between somebody withdrawing their identity and somebody never having had one is the difference between a lapsed customer and a person lying to you.
| Answer | How you read it | What it means |
|---|---|---|
| Live | live: true |
Issued by this deployment, signature checks out, not expired and not withdrawn. |
| Expired | expired: true, signatureValid: true |
Genuine, and past its expiry. Claims are short lived on purpose, so this is ordinary rather than suspicious. |
| Revoked | revoked: true, signatureValid: true |
Genuine, and withdrawn since. The signature still verifies, which is exactly why revocation has to be reported separately. |
| Forged | signatureValid: false |
A record carrying a signature this deployment key did not make. Treat as hostile. |
| Unknown | HTTP 404 unknown_claim |
No such claim here. Not the same as forged: check you are asking the deployment that issued it. |
Assurance is a separate question from validity
live: true tells you the claim is real. It does not tell you what it says. That is assurance, and there are two values:
approved means the holder of a Confrmo account approved a login to this relying party. Somebody with access to that account said yes. confirmed means Confrmo additionally asserts that a live face was matched against an identity document it checked, and checkedAt tells you when.
If your reason for asking is is this person who they say they are, approved is not the answer to that question and treating it as one is the mistake this field exists to prevent. Read both, always.
A claim is a statement about an identity check at a moment in time. It is not a recommendation, a credit decision or a character reference, and Verus is not in a position to offer any of those.
Everything else
How a request is signed
There is no bearer token and no session, because there is no account in the ordinary sense: an address is the fingerprint of a key made on a device, so the key is the only thing there is to authenticate with. Every other route on the deployment expects this header.
Authorization: Verus-Sig v=1,a=<address>,k=<device id or identity>,
t=<unix seconds>,n=<nonce>,s=<base64url signature>
The signature is Ed25519 over these six lines, joined by newlines with no trailing newline:
verus-request-v1
<METHOD>
<path including query>
<t>
<n>
<base64url sha256 of the raw request body>
Three properties fall out of that, and each one is deliberate. The body digest is inside the signature, so a proxy cannot swap the body. The path is inside it, so a signature captured for one route cannot be replayed at another. And the nonce is recorded until the clock skew window closes, so a captured request cannot be replayed at all.
What this page does not give you
Said plainly, because a developer finding out by wasting an afternoon is worse than being told now, and because the rest of this site holds itself to the same rule.
- No SDK and no client library. There is a working reference client in the codebase and it is not published.
- No OpenAPI document for the signed surface. The OpenAPI document covers the open routes above and nothing else; the signed surface is not specified anywhere you can read.
- No published protocol specification. The messaging layer is X3DH and a Double Ratchet with standard primitives, and naming those is not the same as letting you check the composition. Until it is written down and reviewed, treat the cryptography as unaudited by anybody outside this project.
- No third party security audit. What is and is not certified is set out on the security page, including that there is no ISO 27001 certificate of our own, no SOC 2 report and no penetration test yet.
- No versioning promise beyond the three routes above. Those answer
/v1/and will keep answering it.
If you are building something that needs any of the above, say so and it moves up the list. The fastest way to make a specification exist is somebody waiting on it.

