Agent Identity SDK Quickstart, With the Three Things a Quickstart Usually Hides
Install
npm i @solidus-network/agent-identity @solidus-network/agent-identity-verify
Both are at 0.1.4 on the public registry. The repository declares 0.1.0, so anybody reading our source instead of the package is reading a different thing from the one they installed. This page was written against the installed package.
One: the custody default hands us the key
createAgent defaults to managed custody, in the API and in the adapter core alike. Managed
means we generate the agent's signing key, encrypt it and keep it, and exporting it later returns
the key without deleting our copy.
If you want to hold the key, say so, and pass the public half:
const agent = await solidus.createAgent({ custody: 'byo', publicKey: myPublicKeyHex })
That returns the agent staged for your signature with a nonce and a network name. You then sign the identifier-creation transaction yourself and submit it, and the chain enforces that the signer matches the key you registered.
The framework adapters cannot do this. Their shared options carry an agent identifier and a capability list and no field for a signer you already control, so every adapter path is managed custody. Create the agent explicitly first, then pass its identifier to the adapter.
Issue a capability credential
const issued = await solidus.issueCapability(agent.id, { scopes: ['reports:read'] })
Those scope strings answer to no vocabulary. Nothing defines an allowed set, so whoever checks them is doing string comparison against a convention you and they have to agree out of band.
Two: the bundle comes back once and it is a bearer credential
The response carries a bundle with a signature, a public key, the encoded messages and a version. No other call returns it. Lose it and you reissue.
And there is no holder key binding anywhere in either package. Possession of the bundle is sufficient to present the credential. Store it the way you store a private key, not the way you store a receipt.
Present it
const header = await buildAgentAuthHeader(bundle, { method: 'GET', path: '/reports' }, {
discloseClaims: ['scopes'],
status: { uri: issued.credential.statusListUri, index: issued.credential.statusListIdx },
credentialId: issued.credential.l1CredentialId,
})
The proof is derived offline, freshly per request, and bound to the method, the path and a timestamp.
Pass the status reference. It is optional in the shape, and the next section is why leaving it out matters more than it looks.
Three: a lenient verifier accepts revoked credentials
With no status reference in the envelope, verification returns a valid verdict and an unchecked revocation state. The reference is supplied by the presenting side, so a verifier that reads only the headline field lets the party being checked decide whether it is checked.
Do this instead:
const verifier = createVerifier({ statusIssuerPublicKey: ISSUER_STATUS_KEY })
const result = await verifier.verify({ ...envelope, status: envelope.status })
if (!result.valid || result.revoked !== false) reject()
The second condition is the one that matters. An unchecked revocation state is not good news, and the verifier page covers the rest, including why a revoked verdict from either path should be treated as revoked.
What the clean-room check actually proved, and what it did not
Proved: both packages install from the public registry into an empty directory with no monorepo and no credentials, the exports resolve, and the three disclosures above are true of the published files rather than only of our source.
Not proved: that these snippets run end to end. That needs an operator credential and a live workspace, and this page does not claim to have executed them.
Saying which is which is the difference between a verified quickstart and a plausible one.
What this SDK will not give you
Not settlement. No value moves through us, in any direction. A payment-authorisation surface is exported and is deliberately not shown here.
Not an identity check. This surface ingests a credential issued elsewhere and never performs one.
Keep reading
- How to Issue a Capability Credential, and What the Bundle in the Response Actually Is
- How a Relying Party Verifies an Agent Credential, and Why `valid` Is Not the Field You Want
- How Revocation Works, and the One Case Where the Authoritative Answer Is the Stale One
- Agent Credential Webhook Events, and Why the Timestamp Is Not Where You Will Look For It

