The receipt format for licensed human identity, and the tool that checks it.
Every authorised AI use of a human identity on SocialGravity carries a cryptographic receipt linking the person, their permission, the licence, the generation and the output. This repository is the public half of that promise, so that you can check any receipt yourself, on your machine, without trusting us.
Verifier CI Spec Code Docs Deps
Spec · Verification spec · Log audit guide · API · Verifier · Offline verifier · Descriptor SDK · Keys · Live docs
git clone https://github.com/socialgravity/receipts && cd receipts deno run --allow-net verifier/verify.ts --license LDNAEEDY5UB
Or without cloning anything:
deno run --allow-net https://socialgravity.ai/docs/verify.js --license LDNAEEDY5UB
Real output, trimmed to four of its checks:
SocialGravity receipt verification: licence LDNAEEDY5UB
base: https://id.socialgravity.ai/functions/v1
document and log
PASS external anchor
head timestamped by rfc3161 at 2026年07月31日T20:07:02+00:00, covering
ledger seq 59 and so this entry at seq 45, which is what rules out
back-dating
PASS witnessed head
today's tree of 60 is a pure append of the publicly witnessed head of
59: nothing witnessed has been altered or removed
link 1: person
NOT CHECKABLE identity method
'document': a government ID was verified. Signed, but the check itself
is the issuer's. NO LIVENESS: a document check establishes that a valid
ID exists, never that the person holding it was present
link 4: generation event
PASS licence chain
1 row(s) rehashed from their published preimages and linked
VERDICT: INCOMPLETE. 17 passed, 0 failed, 3 not checkable. Nothing contradicted the
receipt, but the lines above marked NOT CHECKABLE are assertions or unavailable data,
not proofs.
LDNAEEDY5UB is a real licence: a document-verified person, a voice asset fingerprint, a signed
platform agreement, Ed25519-signed and logged. The verifier fetches only public endpoints and
does every check locally against a key pinned in verifier/lib/keys.ts.
Three outcomes per check: PASS, FAIL, or NOT CHECKABLE. Anything that would require taking our word for it is reported as NOT CHECKABLE rather than dressed up as proof, which is why our own showcase licence returns INCOMPLETE rather than a green tick. See verifier/README.md for the full design and the tampering test suite.
| Path | What it is |
|---|---|
docs/receipt-spec-v1.md |
The receipt format, normative. Section 4 has the canonicalization rules a third party needs to write an independent verifier. Section 8 is the honest status of the live register |
docs/schemas/receipt-v1.schema.json |
JSON Schema 2020-12 for the receipt document |
docs/transparency-log-audit.md |
How to audit the RFC 6962 transparency log, including what is deliberately outside it |
openapi.yaml |
The API surface, including the public verification endpoints |
verifier/ |
The zero-dependency Deno verifier CLI, with its tampering test suite |
packages/verify/ |
The OFFLINE verifier. Hand it a receipt bundle and it checks every kind with no network at all, against keys pinned in the package. See below |
docs/verification-spec-v1.md |
How to check a receipt without trusting us, normative. The contract packages/verify implements, written so you can implement it too |
packages/permission-schema/ |
The permission vocabulary: the axis space a licence grants in, its validators and canonical byte rules, JSON Schemas for other languages, and the nuance conformance corpus. See below |
packages/descriptor-sdk/ |
The TypeScript SDK for writing and validating a descriptor before you submit it, with a worked example per corpus fixture |
keys/company-keys.json |
The signing keys, published here so you can obtain them from somewhere other than the record you are checking |
journal/ |
Short notes on what has shipped. Every post ends in a command or a URL that returns a real result |
Related public repository:
socialgravity/ledger-anchors, the head
hashes of our ledger mirrored where we cannot quietly rewrite them. The verifier's
witnessed head check reads it.
verifier/ above asks our API and reports. packages/verify/ answers a
different question: can you hold a receipt and check it later, on a machine with no network,
without asking us anything.
# once, with a network. This step judges nothing; it collects the signed instruments. deno run --allow-net packages/verify/cli.ts fetch LDNAEEDY5UB > receipt.json # any time afterwards, anywhere. No network. Keep receipt.json for as long as you like. deno run --allow-read packages/verify/cli.ts check receipt.json
That second command can run with no permissions whatsoever if you feed it on stdin:
deno run packages/verify/cli.ts check - --no-anchors < receipt.jsonThat is not a promise it does not phone home. The runtime will not let it, and you can watch it
work. The only network the check will ever ask for is fetching publicly anchored ledger heads
from ledger-anchors, and that is opt-out
(--no-anchors) and injectable (--anchors <file>), so an air-gapped machine can carry the
anchors in and still reach the strongest verdict available to it.
Get those anchors from somewhere other than us. Their whole value is that they were published where we cannot quietly rewrite them, and a copy you fetched last month is stronger evidence than one you fetch now.
Run its tests on your own clone. Real production receipts verifying, and thirteen ways a flipped byte fails, each with a named reason:
deno test --allow-read --allow-net packages/verify/_tests/A receipt records that a use was authorised. The question that produced it is a descriptor: one intended use, graded on every axis of a pinned vocabulary version. Both halves of writing one are published here.
packages/permission-schema/ is the vocabulary itself: the finite
axis space a permission lives in, the document validators, the canonical byte rules, and JSON
Schemas so an implementation in any language can pin the same shape. Everything a licence grants
is said in this vocabulary, so reading it is how you find out what a licence can and cannot say.
packages/descriptor-sdk/ is the ordinary way to use it from
TypeScript. The axis ids and their legal values are types derived from the vocabulary, so a
misspelled axis or an illegal value is a compile error rather than a rejected submission:
import { descriptor } from "./packages/descriptor-sdk/mod.ts"; const use = descriptor("1.0.0") // the version pin is explicit, always .set("media.type", "still_image") .set("wardrobe.type", "swimwear_bikini") .set("geography", ["ES", "FR"]) .set("term.date", "2026-07-15") // ... every axis. Descriptors are total: a hole is a validation error, because // a decision made on an axis nobody filled in is one nobody agreed to. .build();
deno test packages/descriptor-sdk/_tests/ # no permissions needed at all
packages/permission-schema/fixtures/ is the conformance
corpus: three contract nuances that are awkward to express (an exception with no negation
operator, a refusal that has to hold in every market, a territory that is not a value), each with
the probes and the PERMIT or DENY each one must receive.
packages/descriptor-sdk/examples/ works all three through
the SDK, and every case is replayed through the real decision engine on each upstream CI run.
What is NOT here is the engine that turns a descriptor plus a licence into that verdict. It is gating logic, and gating logic stays closed for the reason given below. So the corpus is a record of the answers our engine must produce, not something you can rerun locally: if you port the vocabulary, that corpus is what your port has to reproduce, and a disagreement is worth an issue.
That is the point of publishing this, and it is the most useful thing you can do with it.
- Read section 4 for the canonical byte rules. If your bytes match ours, your signature check will agree with ours.
- Fetch a receipt:
GET https://id.socialgravity.ai/functions/v1/idl-license-receipt?license_id=LDNAEEDY5UB - Fetch the signed tree head and an inclusion proof:
GET .../idl-log-sth?include=LDNAEEDY5UB - Pin the key from
keys/company-keys.json. Do not trust a key the server hands you at check time: whoever can alter a record can alter the key beside it.
docs/verification-spec-v1.md is the fuller contract if you want
it: every instrument kind and what it must contain, the three-outcome reporting rule, the reason
codes, and section 10, which is the list of things this format deliberately CANNOT prove.
If your implementation disagrees with ours anywhere, one of us has a bug and we want to know which. Open an issue.
The proof layer is open: the format, the schema, the log construction, the permission vocabulary a licence grants in, and the tool that checks it all. Anyone can verify what we claim, and anyone can implement this format independently.
The custody and enforcement layer is closed and stays closed: biometric template extraction and matching, matching thresholds, watermarking, and the gating logic that enforces deals. Opening those would help exactly one audience, the people trying to defeat them.
- The register is young. Section 8 of the spec says which records are
real and which are synthetic test data, and every synthetic one reports
demo: truewhen you fetch it. Never read ademo: truerecord as a deal. - External anchoring of the ledger began 2026年07月30日, and the public mirror was seeded at head 30. Nothing before that has third-party proof of time.
- Per-licence hash chains are publicly recomputable from chain version 5 (generation) and 3 (registration) on: those rows publish their whole preimage, with a small number of commercial fields replaced by a salted commitment. Rows written under earlier versions carry no preimage, because the old formula held private fields in the clear and no honest public preimage exists for them. The verifier and the API say which case a row is in rather than implying more.
- Some internal documents referenced by the spec are not published. Those references resolve inside our platform repository, not here.
This repository mirrors the public artifacts of SocialGravity's platform repository, which is private. Issues and pull requests are welcome here; accepted changes land upstream first and flow back in the next sync. See CONTRIBUTING and SECURITY.
- Code (
verifier/): Apache License 2.0 - Documentation and specifications (
docs/,openapi.yaml): CC BY 4.0