OwlIssuer
Server-side client for issuing Owl ID SD-JWT VC credentials. Imported from @owlid/sdk.
import { OwlIssuer } from '@owlid/sdk'
const issuer = new OwlIssuer({ apiKey: process.env.OWLID_API_KEY! })
Constructor
new OwlIssuer(options: OwlIssuerOptions)
Methods
info()
Read your issuer's public details (display name + signing public key).
const { name, publicKey } = await issuer.info()
// IssuerInfo
// name: string
// publicKey: string // issuer signing public key, hex
listProviders()
List identity providers configured for your account.
const providers = await issuer.listProviders()
// ProviderInfo[]
// id: string
// name: string
// flowType: string
startSession(providerId)
Open an issuance session for a given provider. The returned start payload tells you how to drive the provider flow.
const session = await issuer.startSession('didit')
// IssuanceSession
// id: string
// providerId: string
// status: 'pending' | 'verified' | 'complete' | 'expired'
// flowType: 'form_based' | 'oidc_redirect' | 'saml_redirect' | 'webhook_async' | 'qr_polling'
// expiresAt: string // ISO timestamp
// start: SessionStart
session.start is a discriminated union:
type SessionStart =
| { type: 'form'; fields: FormField[] }
| { type: 'redirect'; url: string; relayState?: string }
| { type: 'qr'; qrData: string; orderRef: string; autoStartUrl?: string }
| { type: 'webhook'; url: string }
submitClaims(sessionId, claims)
Submit verified identity claims for form-based providers. Use SD-JWT VC standard claim names (given_name, family_name, birthdate, nationalities, …) where applicable.
await issuer.submitClaims(session.id, {
given_name: 'Jan',
family_name: 'de Vries',
birthdate: '1985-03-15',
nationalities: ['NL'],
})
getSession(sessionId)
Read the current state of a session. Same shape as startSession.
getClaims(sessionId)
Read verified claims once a session reaches verified.
const claims = await issuer.getClaims(session.id)
// IssuedClaims (provider-specific keys)
// providerId: string
// ...
poll(sessionId)
Polls a session and returns the latest snapshot. Use this for QR or webhook flows where the provider drives the verification asynchronously.
let snapshot = await issuer.poll(session.id)
while (snapshot.status === 'pending') {
await new Promise((r) => setTimeout(r, 1500))
snapshot = await issuer.poll(session.id)
}
issue(sessionId, holder)
Issue a single SD-JWT VC bound to the holder's confirmation key. Throws if the session is not in verified state or if issuance fails.
const issued = await issuer.issue(session.id, {
publicKey: '04abc...', // holder public key, hex
algorithm: 'ed25519', // 'ed25519' (wallet key) or 'p256' (ES256 cnf); defaults to 'p256'
})
// IssuedCredential
// sdJwtVc: string // application/dc+sd-jwt string, issuance form
The wallet derives the stable credentialId and the did:web issuer from the sdJwtVc string itself via SdJwtVc.parse() — they are not separate fields on the response.
issueBatch(sessionId, holder, batchSize)
Issue a batch of one-time-use SD-JWT VCs (OpenID4VCI Batch Credential endpoint). Each has a distinct credential_id and is independently revocable on Midnight — multiple presentations cannot be correlated by a colluding verifier pair.
const batch = await issuer.issueBatch(
session.id,
{ publicKey: '04abc...', algorithm: 'ed25519' },
8, // batchSize, 1..=64
)
// batch: IssuedCredential[]
The platform does not retain unhashed claims past the session TTL.
Types
interface OwlIssuerOptions {
apiKey: string
baseUrl?: string
}
interface IssuanceSession {
id: string
providerId: string
status: string
flowType: string
expiresAt: string
start: SessionStart
}
interface FormField {
name: string
label: string
type: string
required: boolean
}
interface Holder {
/** Holder public key, hex. */
publicKey: string
/** Key algorithm. Defaults to `p256` (WebAuthn). */
algorithm?: 'p256' | 'ed25519'
}
interface IssuedCredential {
sdJwtVc: string
}