ORBIS.ID
You are on Anyone PUBorbis.id

BUILD · QUICKSTART · WALLET

What a wallet does before it asks anyone for anything.

A wallet does not guess what an issuer offers, and it does not trust a credential it cannot bind to its own key. Five things happen, in order. Two are open reads this page can run for you right now. The other three need a real grant and a real device key — this page describes them from the specification and says plainly that it has not witnessed them for you.

The life of a credential, drawn.

Credential lifecycle State machine for a credential on ORBIS.ID: an offer is created, the credential is issued and accepted into the wallet, where it is held; presenting it produces a verification result and the credential returns to being held rather than being spent; from held it can also be revoked by its issuer or reach its expiry, and both of those end its life. /api/offers POST /credential items/{id}/accept POST /oid4vp/response sig + status pass /api/revoke exp elapsed STILL HELD Offered Issued Held Presented Verified Revoked Expired TRANSITION RETURN PATH — THE CREDENTIAL IS NOT SPENT

The most common wallet bug in this field is trusting an answer the browser produced. Every step below exists to avoid exactly that.

The five steps

  1. 01

    Fetch issuer metadata before asking anyone anything

    An open read. It names the credential format, the claims on offer, and the grant a wallet must use — read before a person is shown a single screen.

    witnessed/.well-known/openid-credential-issuer
    curl -s https://id.orbis.id/.well-known/openid-credential-issuer
    Reached on 2026-08-30. The full schema this issuer publishes is on the credential-types page.
  2. 02

    Fetch authorization-server metadata

    A second open read, naming the grant your wallet must implement — the pre-authorized-code grant, with no client secret a wallet binary could leak.

  3. 03

    Redeem the code a person was handed

    Not witnessed here. A code exists only once a real issuance has started, which is a self-service action for nobody reading a webpage. This step is implemented and tested in the platform's own suite — it is described, not printed as a command that would run for you.

  4. 04

    Store the credential bound to a device key, never a copy

    What comes back names your device's public key in its cnf claim. A wallet's whole job from here is to never let the private key leave the device it was generated on — a copy of the token elsewhere cannot answer a challenge with that key, so it is not a usable copy. The worked schema is on the credential-types page.

  5. 05

    Check the status list before ever showing the credential as good

    A wallet is also a light verifier of its own holdings. This one is an open read — the same list any external verifier reads.

    witnessed/status/1
    curl -s https://id.orbis.id/status/1
    Reached on 2026-08-30.

Reading a wallet's items needs the same key as writing to it

It is tempting to assume a list is lower-stakes than a write and can stay open while only acting on an item is gated — this build's own history says that assumption is wrong. The route that lists an account's held items now requires the same holder JWT as accepting or sharing one, and enforces the identical rule: the account named in the path must match the thumbprint that signed the request, refused with "not your account" otherwise. A list of what someone holds is one of the most identifying documents this platform stores, and the principal entitled to read it is the same one entitled to act on it — nobody else, not even with the account id in hand.

Two refusals, not one: an unsigned or non-holder request never reaches the account check at all, and a validly-signed request naming an account that is not its own is refused before any store lookup runs — so whether an account id names a real holder, an empty one, or nothing ever minted looks identical from outside. Design your wallet's error handling around that: there is no way to probe whether an account exists by naming it.

What is real here.

Discovery and status reads are real and answer today. The redemption step that actually produces a credential is implemented and tested, but not witnessable from a static page — and a wallet a person installs from an app store is the one capability in this list this build still names as missing.

  • PLANNED A wallet a person installs from an app store. wallet-native You cannot hold a credential on a phone you own. Everything a person would do with a proof waits behind this.

The register holds 17 live · 2 partial · 2 planned · 5 not yet.

4 of the 5 capabilities this page depends on have no row in the register yet, so this page will not print a state for them. They are named rather than dropped, because a slice that silently shortens itself is the same defect as a claim with no receipt.

  • vc-issuance
  • oauth-metadata
  • issuance-flow
  • holder-jwt-list-auth

The register route serves, but it carries no row for these yet. List what it does carry:

curl -s https://id.orbis.id/api/site/register | jq -r '.entries[].slug'

Straight answers

Can I follow this page with no backend of my own?
No. A wallet is a client with its own key custody; there is nothing here that runs entirely in a browser tab.
Does the issuer ever see the device's private key?
No. Only the public key travels, inside the credential's cnf claim.
Is there a reference wallet implementation this page ships?
No. This page is the specification a wallet is written against, not a library.
Can I list an account's items without a holder signature?
No — not on this build. The read is gated the same way the writes are, and an unsigned or mismatched request is refused before any lookup runs.

Do not trust us. Check us.