Skip to main content
A primitive is one verification verb. Every step in a session’s steps[] names exactly one primitive plus optional params. This is the per-primitive parameter reference; for the design philosophy see Primitives. Every primitive verifies against the government credential in the user’s wallet. You’re billed only for steps that successfully verify, and results arrive by webhook (one step.completed per step) — never in the create response.
PrimitiveVerifiesPrice
identifyGovernment-attested identity attributes$0.01
age_verifyAn age threshold, without revealing the birth date$0.01
light_signA signature over short inline terms$0.02
signA signature over one or more uploaded documents$0.03

identify

Returns selected, government-signed identity attributes. The wallet shows the user exactly which fields are requested, and only those signed fields come back — no document upload, no OCR.

Params

blocks
string[]
The attributes to request. Omit to request the default set (first_name, last_name, dob, country). A block the credential lacks is returned as "unavailable"/null rather than erroring.
Supported blocks:
BlockReturns
first_nameGiven name
last_nameFamily name
dobDate of birth (ISO 8601)
genderSex/gender, when present (nullable)
portraitPortrait image, when the wallet exposes it (nullable)
document_numberCredential / document number
issue_dateDate the credential was issued
expiry_dateDate the credential expires
issuing_authorityAuthority that issued the credential
countryIssuing country (always "US")
stateIssuing jurisdiction, e.g. US-CA
addressResidence address (nullable)
resident_stateResidence state (nullable)
country and state describe where the credential was issued (always US; e.g. US-CA). address and resident_state describe the holder’s residence. Nullable fields (gender, portrait, address, resident_state) return null/unavailable when the credential doesn’t carry them.
ISO mDL has no single full-name element — request first_name + last_name and compose. full_name and personal_number are intentionally unmapped for US mDL (no single full-name element; no national identification number) and return unavailable.

Result

claims — an object of the disclosed blocks, on the step.completed webhook and via GET /v1/sessions/{id}.
step
{ "primitive": "identify", "params": { "blocks": ["first_name", "last_name", "country"] } }

age_verify

Proves the holder meets an age threshold without disclosing their birth date. UIP reads the DOB from the verified credential, computes age ≥ min_age, and returns only the boolean. The full identity is sealed in the audit (flagged redacted) and never sent to you.

Params

min_age
integer
default:"18"
The age threshold to check (age ≥ min_age). A whole number, 1–120.

Result

satisfied — a boolean. No claims, ever — not even the age.
step
{ "primitive": "age_verify", "params": { "min_age": 21 } }

sign

Produces a government-attested signature over one or more documents you upload. UIP hashes each file server-side (you never supply a hash — WYSIWYS), and the wallet signs the manifest. The durable proof (hash + signature) lives in the audit; the uploaded file bytes are retained briefly, then purged after the session ends. Because it carries files, a session containing a sign step must be created as multipart/form-data: a steps JSON part plus one file part per document. The file field name is the document id the step references.

Params

document_ids
string[]
required
The ids of the documents to sign. Each must match a multipart file field name in the same request. 1–50 ids; combined upload ≤ 50 MiB.

Result

document_hash (the signed manifest digest) + signature. For a multi-file sign, the audit also keeps a per-file { id, hash } manifest, so any single file stays provable after the bytes are purged.
multipart
curl https://api.uip.digital/v1/sessions \
  -H "Authorization: Bearer $UIP_API_KEY" \
  -F 'steps=[{"primitive":"sign","params":{"document_ids":["contract"]}}]' \
  -F 'contract=@contract.pdf'

light_sign

A lightweight signature over short inline terms — no file upload. Use it for consent, terms acceptance, or a disclosure you want to prove later. The exact terms text is retained in the audit (it’s your content, not user PII), so “they signed THESE terms” needs nothing else.

Params

terms
string
required
The exact terms to sign. Up to 1000 words (~5 minutes of reading); shown to the user verbatim on the hosted page.

Result

document_hash (hash of the canonicalized terms) + signature.
step
{ "primitive": "light_sign", "params": { "terms": "I authorize a one-time charge of $49.00." } }

Composition & reserved

  • Chaining: to verify several things in one flow, list multiple steps in steps[] — the user completes them in one session and you get one webhook per step. Add a gate to a step to pause for your continue / stop decision. See Create a session.
  • envelope (multi-party signing — N signers across N wallets) is a reserved primitive: named in the model but not yet available.