API reference
Subjects and identifiers
Creating subjects, registering verified identifiers, and withdrawing from the directory.
Requires a member credential.
POST /subjects
{ "subject_type": "natural_person", "external_ref": "cust_10482" }{
"id": "9f2c41a8-6d1e-4b07-9c3a-2e5f81d0a4b7",
"subject_type": "natural_person",
"created_at": "2026-09-09T10:00:00Z"
}subject_type is natural_person or legal_entity. It is recorded for your own use and does not
drive anything: the discoverability defaults below are keyed on identifier type.
external_ref is your own key. The protocol never interprets it and never returns it to anyone
else. No personal data belongs in a subject — names, dates of birth and documents stay in your
systems.
POST /identifiers
{
"subject_id": "9f2c41a8-6d1e-4b07-9c3a-2e5f81d0a4b7",
"identifier_type": "phone",
"identifier": "+12025550123",
"verification_method": "otp_sms",
"discoverability": "network"
}{
"id": "3b71c9e4-8a52-4d16-bf90-71c4e2a6d835",
"identifier_type": "phone",
"discoverability": "network",
"verified_at": "2026-09-09T10:02:00Z"
}The clear identifier is not stored
It is used to compute the hash and gone in the same request — not in a table, not in application logs, not in the search log. The operator keeps the hash.
Verification
verified_at is set only when verification_method is supplied. Register without one and the entry
still indexes, but a counterparty reading an attestation can tell the difference — which is the only
reason to record it.
| Type | Reasonable methods |
|---|---|
phone | otp_sms, otp_voice |
email | link_click |
bank_account | micro_deposit, payee_name_check |
lei, reg, tax | registry_lookup, document_review |
Format rules worth repeating
reg names its registry. reg:US:EIN:12-3456789, not reg:US:…. One country holds
several registers — a US company has both an EIN and a DUNS — and omitting the registry
makes them indistinguishable, or collides two different companies where numeric formats overlap.
bank_account carries its scheme. iban:DE89… or bban:…. Never inferred from a country.
Phone numbers are E.164. Normalisation is normative: two implementations that normalise differently split the directory in half with no error anywhere.
Discoverability defaults
Applied when you omit the field:
| Type | Default |
|---|---|
phone | network |
email | network |
bank_account | private |
lei, reg, tax | public |
Never move an entry towards public in a migration without an explicit request.
POST /subjects/{id}/withdraw
{ "subject_id": "9f2c41a8-6d1e-4b07-9c3a-2e5f81d0a4b7", "withdrawn": true, "entries": 3 }Sets every identifier and every address of the subject to private, and removes each entry from the
directory index.
Applied at the subject level. Withdrawal covers every identifier of that subject.
Withdrawal does not delete the subject, and does not erase settlement history. Ending discoverability and destroying the record of what happened are different operations with different legal consequences.
POST /attestations
Requires the local member credential. expires_at is mandatory.
{
"subject_id": "9f2c41a8-6d1e-4b07-9c3a-2e5f81d0a4b7",
"claim": "kyc_level",
"value": "standard",
"expires_at": "2027-09-09T10:00:00Z"
}Closed claims: kyc_level, kyb_level, aml, sanctions, pep, risk_tier, identity_level.
GET /subjects/{id}/attestations lists this subject's claims for the local member.
GET /attestations/{reference}
Requires a member credential — any member. This is the execution-time check. Revoked →
path.id.attestation_revoked (410). Expired → path.id.attestation_expired (410).
POST /attestations/{reference}/revoke
Local member. Leaves the row; the next read answers 410.
POST /ownership-bindings
Requires the local member credential. target is hashed and forgotten.
{
"subject_id": "9f2c41a8-6d1e-4b07-9c3a-2e5f81d0a4b7",
"binding_type": "identifier",
"target_kind": "phone",
"target": "+12025550123",
"proof_method": "otp_sms"
}GET /ownership-bindings/{reference} is the execution-time check, same 410 rules.