GitHub

Docs

PATH ID

Subjects, verified identifiers and portable attestations — the pillar that answers who someone is without moving their documents.

LIVE partially — subjects and identifiers are implemented; signed attestations are DRAFT.

What it is for

Verification is expensive and gets repeated. A customer verified by one institution arrives at another and does it all again — same documents, same wait, same abandonment rate. Not because the first verification was inadequate, but because there is no way to carry it that the second institution can check.

PATH ID moves attestations, never documents. The regulated issuer stays the regulated party; the protocol carries a signed statement about what it established, and nothing more.

Three layers, kept apart

This is the part to get right. Most identity failures in payment systems come from merging two of these.

LayerQuestionWhat goes wrong if merged
AuthenticationIs this session the subject it claims?A signed-in user is treated as having a verified phone number
IdentifiersDoes the subject control this identifier?An unverified number is indexed, and someone else becomes reachable at it
ConsentDid they agree to this disclosure, to this party?Verified silently means findable, and nobody opted in

Three separate records. A disclosure requires all three, and an implementation that stores them in one table will eventually make one of the mistakes in the right-hand column.

The subject

{
  "id": "sub_9f2c41a8",
  "subject_type": "natural_person",
  "created_at": "2026-09-09T10:00:00Z"
}

Carries no personal data. Names, dates of birth and documents stay in the operator's own systems, referenced by an internal key the protocol never sees. A subject is a hook to hang identifiers and addresses on, not a profile.

subject_type is natural_person or legal_entity, and the distinction is load-bearing: a legal entity's identifiers are public by nature, an individual's are not. See discoverability defaults below.

Identifiers

An identifier is something the world already uses to refer to a subject. PATH does not invent new ones.

TypeFormNotes
phoneE.164 — +221771234567Normalisation is part of the protocol
emailLower-cased, trimmed
bank_accountiban:… or bban:…Scheme in the value, never inferred from a country
lei20 characters, ISO 17442The global identifier for a legal entity
regreg:COUNTRY:REGISTRY:VALUEThe registry is always named
taxtax:COUNTRY:VALUEVAT, TIN and equivalents

reg:SN:RCCM:… and reg:SN:NINEA:… are two different identifiers of the same Senegalese company. Encoding only the country would make them indistinguishable, and where two registries in one country use overlapping numeric formats it would collide two different companies onto one entry. Name the registry.

There is deliberately no siret type. A SIRET is a value of the French SIRET registry. A protocol that puts one country's registry at the top level is that country's protocol.

Normalisation is normative

Two implementations that normalise differently produce different hashes for the same person, and the directory silently splits in two — with no error anywhere. +221 77 123 45 67 and +221771234567 must produce the same entry.

Verification

{
  "identifier_type": "phone",
  "verified_at": "2026-09-09T10:02:00Z",
  "verification_method": "otp_sms"
}

verified_at is set only when a method is stated. An unverified identifier may still be registered — it is useful for matching — but a counterparty reading an attestation can tell the difference, which is the only reason to record it.

Reasonable methods per type: a one-time code for phone, a confirmation link for email, a micro-deposit or a payee-name check for bank_account, a registry lookup plus documents for company identifiers.

Discoverability defaults

Per entry, because the threat is not the same per type:

TypeThe actual threatDefault
phoneA small, dense space — someone simply tries every numbernetwork
emailNot enumeration: replay of a breach list, hundreds of millions at oncenetwork, separate budget
bank_accountEnumerable once the bank is known; already printed on invoicesprivate
lei, reg, taxThe value is already public by constructionpublic

A migration must never move an entry towards public. Someone becoming publicly findable without asking is the one error here that cannot be walked back.

Withdrawal

Applies at the subject level and removes every identifier at once.

Someone who opts out expects to disappear everywhere. A per-entry toggle that leaves them findable by email after they removed their phone number is a promise half kept, which is worse than none.

Attestations

DRAFT

A signed statement by an issuer about a subject.

{
  "kind": "attestation",
  "subject": "sub_9f2c41a8",
  "claim": "kyc_level",
  "value": "standard",
  "issuer": "member-slug",
  "issued_at": "2026-09-09T10:00:00Z",
  "expires_at": "2027-09-09T10:00:00Z",
  "revocation_ref": "https://api.example.com/.well-known/path-revocations",
  "kid": "op_example_2026_01",
  "signature": "…"
}

Three rules that matter more than the shape:

Never settle on a cached credential status. Revocation is checked at execution, not at issuance. A credential valid this morning may be revoked now, and "we checked recently" is not a defence.

An attestation is a claim, not a document. It says a level was established, by whom and when. It never carries the underlying evidence.

Expiry is mandatory. An attestation without one is a claim about the past presented as a claim about the present.

Selective disclosure — proving "over 18" without revealing a birth date — is RESERVED. It is a real goal and a poor reason to block a first version.

What PATH ID is not

It is not a KYC provider, an identity wallet, or a replacement for regulated verification. It is the envelope that lets an existing verification travel and be checked by someone who was not there.


On this page