KYA verification profile 1.0

How KYA verifies – not how evidence is issued. The profile defines rules, its own container formats and the report, and binds other vendors' formats such as Verifiable Intent to the same ten checks. Licensed under CC BY 4.0.

In short

The KYA verification profile 1.0 defines how verification works: claims profile, receipt chain kya-chain/1, evidence pack kya-pack/1, timestamp binding, report – and the mapping of other formats such as Verifiable Intent onto the ten checks.

Scope

This specification defines a claims profile for mandates and decisions, two container formats and the verification report. For signatures, selective disclosure, status lists and timestamps it refers to existing standards: JWS, SD-JWT VC, IETF Token Status List and RFC 3161. Canonical JSON follows RFC 8785 in the subset described here.

The normative source is the engine @knowyouragent/verify-core; this page is reconciled against it on every build.

Claims profile 1.0

Mandates and decisions are mapped onto a normalized view. The aliases let existing implementations keep their field names. New aliases are only added with a test vector.

Normalized fieldAccepted claims
Agentsub, agent, agent_id, agentId
Principalprincipal, principal_id, mandant, on_behalf_of
Scope (action types)scope, actions, allowed_actions, action_types, actionTypes
Amount limit per actionmax_amount, amount_max, limits.amount_max, limits.max_amount, amount_limit, maxAmount
Currencycurrency, limits.currency
Counterpartiescounterparties, allowed_counterparties, merchants, counterparty
Period limit (reported only)amountLimitPerMonth, limits.amount_per_period, limits.per_month, frequency_limit, frequencyLimit
Mandate reference in decisionmandate_id, mandateId, mid, mandate
Decisiondecision, dec, result
Actionaction, act
Receipt referencereceipt_id, receiptId

Action types in the scope may end in .*, for example purchase.*. Period limits cannot be checked offline and are reported as present, not as complied with.

Receipt chain kya-chain/1

{
  "kind": "kya-chain/1",
  "entries": [{
    "seq": 1,
    "ts": "2026-10-01T08:00:02Z",
    "receipt_id": "rcpt-0001",
    "decision_jti": "dec-2026-10-01-0001",
    "mandate_id": "urn:uuid:…",
    "agent": "did:key:z6Mk…",
    "action": { "type": "purchase.goods", "amount": 4, "currency": "CHF" },
    "result": "executed",
    "prev_hash": null,
    "entry_hash": "9f2c…",
    "timestamp": "MIIL…"
  }]
}
  • entry_hash is the hexadecimal SHA-256 over the entry's canonical JSON without entry_hash and without timestamp.
  • prev_hash is null or 64 zeros for the first entry, then the predecessor's entry_hash.
  • seq is optional and, if present, gapless.
  • timestamp is optional: an RFC 3161 token in Base64 whose messageImprint is the 32 bytes of entry_hash.

Evidence pack kya-pack/1

{
  "kind": "kya-pack/1",
  "created": "2026-10-12T10:00:00Z",
  "parts": {
    "mandate": "<SD-JWT VC>",
    "passport": "<SD-JWT VC, optional>",
    "decision": "<JWS>",
    "chain": { "kind": "kya-chain/1", "entries": [ … ] },
    "status_lists": [ "<status list JWT>" ],
    "keys": [ { "kty": "EC", "kid": "…" } ]
  },
  "manifest": { "alg": "sha-256", "digest": "<hex>" },
  "timestamps": [ { "target": "manifest", "token": "<Base64>" } ]
}
  • manifest.digest is the SHA-256 over the canonical JSON of parts.
  • Bundled keys count as self-asserted. They prove integrity, never the issuer.
  • timestamps[].target is manifest, chain-head, entry:N or decision.

Timestamp binding

  • The messageImprint must use SHA-256 and contain exactly the bytes of the target: manifest digest, chain head, entry hash or the SHA-256 of the decision token.
  • The timestamp authority's certificate must carry the extended key usage timeStamping and be valid at the time of the stamp.
  • Trust only arises through an anchor of the verifying party. Certificates in the token serve as intermediates, not as anchors.

Status lists

Mandates reference a status list per IETF Token Status List through status.status_list.idx and .uri. The list must be signed by the mandate's issuer. Values: 0 valid, 1 revoked, 2 suspended; anything else is unknown. Verification does not fetch lists; the verifying party provides them.

Verification report kya-report/1

{
  "kind": "kya-report/1",
  "verifier": { "name": "@knowyouragent/verify-core", "version": "1.2.0" },
  "policy": "kya-policy/1.0",
  "checkedAt": "2026-10-12T10:00:00.000Z",
  "input": { "sha256": "…", "bytes": 5321, "format": "kya-pack/1" },
  "verdict": "VALID",
  "assurance": "KYA-A4",
  "checks": [ { "id": "parse_schema", "status": "VALID" }, … ],
  "facts": [ { "k": "agent", "v": "did:key:z6Mk…" }, … ],
  "options": { "trustedKeys": 0, "statusLists": 0, "tsaAnchors": 1, "digest": "…" },
  "reportDigest": "…"
}

Versioning

Formats carry their version in the kind field. The policy version sets the rules for verdict and levels. Backwards-incompatible changes get a new major version; older reports keep their version.