Financial Credentials
Show a new counterparty an agent’s credit, exposure, settlement, premium, and loss record as signed claims it evaluates under its own policy.
On this page
Before a counterparty extends credit or coverage to an agent, it reads five signed claims about the agent’s finances: credit standing, open exposure, settlement reliability, premium quotes, and losses. Each claim travels as a credential its issuer signed over a bounded evidence window, and the receiver relies on it only under a verifier policy it pinned.
The running example is you evaluating an outside buyer’s credit-scorecard credential for a stated 30-day window, before you extend the buyer credit on pricing.quote.
Every imported credential reads as asserted at the receiver
Provenance is graded on the ladder asserted < observed < verified, and a credential holds two positions on it: source_evidence_class, the issuer’s grade for the local records it folded, and presentation_evidence_class, the grade the receiving boundary may treat it as.
Each family has a ceiling at its issuer
source_evidence_class grades the records the issuer folded. Exposure history, premium history, and a scorecard with no imported signal may reach verified. Settlement reliability and loss history stop at observed, because both depend on reconciliation state the issuer watches. Credit Scorecards.
chio.fincred family may claim at its issuer, and the one class every credential carries to a receiver. Thresholds, source proofs, and the verifier policy are left out.Exposure history, premium history, and a scorecard with no accepted imported signal may reach verified at their home issuer. Settlement reliability and loss history cap at observed, because both depend on reconciliation state the issuer watches. A scorecard whose score accepted an imported signal stays at asserted, so imported trust never climbs one hop at a time. Across the boundary all five read as asserted: the signature establishes who made a claim, and the receiver’s policy decides what it is worth.
Five credential families answer five financial questions
FinancialCredentialFamilyV1 names the families. Each maps to one schema id, one Verifiable Credential type name, and one subject type.
- How strong and well supported is the credit assessment? Credit scorecard,
chio.fincred.credit-scorecard.v1: band, confidence, score, and imported signals. - What obligations and losses are recorded? Exposure history,
chio.fincred.exposure-history.v1: positions by currency. - Were obligations settled on time? Settlement reliability,
chio.fincred.settlement-reliability.v1: defined counts and their ratio. - What premiums were quoted? Premium history,
chio.fincred.premium-history.v1: quote count and amounts. - What loss events occurred? Loss history,
chio.fincred.loss-history.v1: the recorded loss evidence.
Monetary values are MonetaryAmount and ratios are integer basis points. The behavioral half of an agent’s record travels separately, as reputation scorecards under chio.agent-passport.v1, and both halves follow the same import rule.
A completeness attestation fixes which records a credential summed
An aggregate means something only when the reader knows which records it summed. Each credential carries FinancialCredentialEvidenceV1: the window, a source disclosure, and the signed completeness attestations behind it.
A disclosure either bundles the canonical source artifacts or names a resolver and references them by digest. Either way the attestation pins the checkpoint authority key and epoch, the store generation, the checkpoint sequence, a range_root and index_root, the committed leaves with their inclusion proofs, and the two window boundaries. A boundary is SourceEdge when the window runs to the end of the indexed range, or Adjacent, carrying the inclusion proof for the leaf immediately outside the window. That pair makes a count checkable: the receiver recomputes the range from the proofs instead of reading a number the issuer typed.
Settlement reliability counts obligations whose signed due time falls in the window [window_start, window_end), joined to their reconciliation records at one cutoff. An obligation is on time only when its terminal settlement is at or before its due time; unresolved and failed obligations stay in the denominator. Missing, stale, or gapped range evidence prevents issuance, and a complete empty window issues no credential.
You accept a 0.80 scorecard against a 0.75 floor
You receive the buyer’s credit-scorecard credential for its 30-day window. The evaluation below assumes the presentation, lifecycle, source proofs, and validity checks pass.
- Issuer and family. Your pinned policy accepts the buyer as an issuer and the credit-scorecard family.
- Covered evidence. The evidence resolver establishes the source proofs and completeness for the declared window; those proofs, separate from the signature, show that no record was omitted.
- Threshold. The credential’s
overallScoreis 0.80 and yourmin_credit_scoreis 0.75, so 0.80 ≥ 0.75 holds. - Binding. With every check passed, the verifier returns the verified set. The presentation is verified, and the imported evidence stays
assertedbeside your locally observed history.
If the required source proof is absent, or you require a score of 0.85, the presentation fails: the evaluator returns an error and no verified set, so a partly accepted result never exists to read.
Underwriting reads only the verified set
A receiver reaches credential subjects only through the evaluator. evaluate_financial_credentials takes the presentation, the receiver’s verified policy, a trust registry, a cross-issuer lifecycle resolver with its generation anchor and high-water store, an evidence source resolver, and a trusted clock. It returns one VerifiedFinancialCredentialSet, or a CredentialError and nothing else.
Underwriting accepts that verified type, never caller counts or a structurally valid passport. It reads imported financial evidence beside the local reputation, certification, and runtime-assurance evidence the control plane derives.
Trust is per issuer: a receiver decides what each accepted credential is worth under its own pinned policy, and no issuer holds bureau-of-record standing. A bundle proves membership and a source class for one window over one source, and a verifier that needs more than that window asks for another credential.
Read more in Underwriting, which runs the decision a receiver makes after it accepts imported evidence.
Credential and verifier reference
Search for credential_id, SourceEdge, presentation_digest, or min_credit_score.
The crate chio-fincred (crates/economy/chio-fincred/src/lib.rs) defines the family: the schema ids, the five subject types, the source-evidence types, and the verifier policy. The crate chio-credentials (crates/trust/chio-credentials/src/financial.rs) issues, decodes, packages, and presents them, and chio-credit projects an issuer’s local signed reports into credential subjects. Reputation scorecards travel under chio.agent-passport.v1 (crates/trust/chio-credentials/src/lib.rs:40); a credential of either kind that crosses an issuer boundary carries presentationEvidenceClass = asserted, and the contract validator refuses any other value.
Credential types
The chio.fincred family in the registry
The signed-artifact registry (spec/schemas/registry.json, bundle 1.0.0) lists these rows under the chio.fincred. prefix. Five are credential families; three carry the source evidence behind them.
| Schema id | Registry kind | What it carries |
|---|---|---|
chio. | financial_ | Band, confidence, overall score in [0, 1], probationary flag, and the imported-signal counts behind the score |
chio. | financial_ | Per-currency positions: governed max, reserved, settled, pending, failed, provisional loss, recovered |
chio. | financial_ | Delinquency, recovery, reserve-release, reserve-slash, and write-off counts, with outstanding amounts |
chio. | financial_ | Quoted premium count and the quoted amounts |
chio. | financial_ | On-time count, obligation count, and their ratio in basis points |
chio. | financial_ | A signed authority checkpoint: range root, index root, and the two window boundaries |
chio. | financial_ | The committed leaves and boundary proofs that fix which source records a window covers |
chio. | financial_ | One signed source artifact, keyed by family, subject, occurrence time, and artifact id |
Two further identifiers are source constants outside the registry. chio.fincred.credential-id.v1 is the domain separator in the credential-id preimage, declared as FINANCIAL_CREDENTIAL_ID_DOMAIN in financial.rs. chio.fincred.verifier-policy.v1 is the schema tag a receiver pins on its own policy record, declared as FINANCIAL_VERIFIER_POLICY_SCHEMA_V1 in chio-fincred.
The five credential families
The subject is an adjacently tagged union: the wire form carries family as the tag and claims as the content, with snake_case family labels and camelCase claim fields.
The Rust family and subject enums
pub enum FinancialCredentialFamilyV1 {
CreditScorecard,
ExposureHistory,
SettlementReliability,
PremiumHistory,
LossHistory,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(
tag = "family",
content = "claims",
rename_all = "snake_case",
deny_unknown_fields
)]
pub enum FinancialCredentialSubjectV1 {
CreditScorecard(CreditScorecardCredentialSubjectV1),
ExposureHistory(ExposureHistoryCredentialSubjectV1),
SettlementReliability(SettlementReliabilityCredentialSubjectV1),
PremiumHistory(PremiumHistoryCredentialSubjectV1),
LossHistory(LossHistoryCredentialSubjectV1),
}One field is floating point: overallScore on the credit-scorecard subject, which the validator requires to be finite and within [0, 1]. Integer fields pass an I-JSON safe-range check on the way in and out (ensure_i_json in crates/economy/chio-credit/src/financial_credentials/); a value above 253 minus one raises IJsonIntegerOutOfRange.
Four families fold a signed issuer-local report that chio-credit projects from. Credit scorecard folds a SignedCreditScorecardReport together with a SignedExposureLedgerReport; exposure history folds the exposure ledger; premium history folds SignedUnderwritingDecision records; loss history folds SignedCreditLossLifecycle events. Each has one entry point named prepare_<family>_financial_source in crates/economy/chio-credit/src/financial_credentials.rs. Settlement reliability folds no report; it is computed from the authenticated obligation and reconciliation ranges described above.
Settlement-reliability issuance and decoding require the store’s due-time and obligation range proofs at one cutoff. Without those proofs, decode_financial_credential returns FinancialReliabilityProofSubstrateUnavailable from its preflight, before any field is read, and chio-credit’s disclosure projection returns ReliabilityProofSubstrateUnavailable. The ratio is derived, never copied from a caller: settlement_reliability_ratio_bps rejects a zero denominator, rejects an on-time count above the obligation count, and computes the ratio in u128 before narrowing.
The ratio derivation in Rust
pub fn settlement_reliability_ratio_bps(
on_time_count: u64,
obligation_count: u64,
) -> Result<u32, FinancialCredentialProjectionError> {
if obligation_count == 0 {
return Err(FinancialCredentialProjectionError::EmptyWindow);
}
if on_time_count > obligation_count {
return Err(FinancialCredentialProjectionError::InvalidReliabilityCounts);
}
ensure_i_json(on_time_count)?;
ensure_i_json(obligation_count)?;
let numerator = u128::from(on_time_count)
.checked_mul(10_000)
.ok_or(FinancialCredentialProjectionError::ReliabilityRatioOverflow)?;
u32::try_from(numerator / u128::from(obligation_count))
.map_err(|_| FinancialCredentialProjectionError::ReliabilityRatioOverflow)
}The credential envelope
FinancialCredentialEnvelope is the signed unit. It serializes camelCase, so a reader sees credentialId, issuerKeyEpoch, credentialSubject, and sourceEvidenceClass on the wire.
The envelope struct in Rust
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FinancialCredentialEnvelope {
pub schema: String,
pub family: FinancialCredentialFamilyV1,
pub credential_id: String,
#[serde(rename = "@context")]
pub context: Vec<String>,
#[serde(rename = "type")]
pub credential_type: Vec<String>,
pub issuer: String,
pub issuer_key_epoch: u64,
pub issuance_date: String,
pub expiration_date: String,
pub credential_subject: FinancialCredentialSubjectV1,
pub evidence: FinancialCredentialEvidenceV1,
pub source_evidence_class: chio_core::capability::governance::ProvenanceEvidenceClass,
pub presentation_evidence_class: chio_core::capability::governance::ProvenanceEvidenceClass,
pub proof: CredentialProof,
}The validator fixes both JSON-LD arrays. @context must equal ["https://www.w3.org/2018/credentials/v1", "https://chio.world/credentials/v1"], and type must equal ["VerifiableCredential", "Chio<Family>Credential"] for the family the schema names, for example ChioLossHistoryCredential. A mismatch between the schema id, the family tag, and the subject variant raises FinancialCredentialSchemaFamilyMismatch.
credential_id is derived. The issuer canonicalizes an id preimage covering the schema, family, context, type, issuer, issuer key epoch, issuance and expiration dates, subject, evidence, and both evidence classes, then takes SHA-256 over the domain separator chio.fincred.credential-id.v1\0 followed by those bytes. The id and the proof stay outside the preimage, so the id is stable across packaging and presentation, and a decoder recomputes it. The signing body is the same set of fields plus the derived id.
Evidence and packaging
Source evidence and window completeness
pub struct FinancialCredentialEvidenceV1 {
pub window: FinancialCredentialWindowV1,
pub source_disclosure: FinancialSourceDisclosureV1,
pub source_completeness_attestations: Vec<SignedFinancialSourceCompletenessAttestationV1>,
}The disclosure and the window boundary are both internally tagged enums, so the wire form carries a kind discriminant and refuses unknown fields.
The disclosure and boundary enums in Rust
#[serde(
tag = "kind",
rename_all = "snake_case",
rename_all_fields = "camelCase",
deny_unknown_fields
)]
pub enum FinancialSourceDisclosureV1 {
Bundled {
artifacts: Vec<FinancialSourceBundleArtifactV1>,
},
Resolver {
resolver_id: String,
references: Vec<FinancialSourceArtifactReferenceV1>,
},
}
// ...
#[serde(
tag = "kind",
rename_all = "snake_case",
rename_all_fields = "camelCase",
deny_unknown_fields
)]
pub enum FinancialSourceCompletenessBoundaryV1 {
SourceEdge,
Adjacent {
leaf_proof: FinancialSourceCommittedLeafProofV1,
},
}The passport carrier
The wire carrier is chio.financial-agent-passport.v1, which the registry files under kind agent_passport_v2. It sits beside the manifest, the presentation, and the challenge in spec/schemas/chio-trust/v1/:
| Schema id | Registry kind | What it carries |
|---|---|---|
chio. | agent_ | A verifier's signed selector list, nonce, and challenge digest |
chio. | presented_ | A disclosed subset with its membership proofs, challenge digest, and presentation digest |
chio. | agent_ | The signed manifest over the packaged credentials: credential root, count, and validity |
chio. | agent_ | The carrier: subject, credential list, Merkle roots, validity window |
A decoder dispatches on the top-level schema string before it deserializes a payload. chio.agent-passport.v1 decodes as the reputation-only passport; chio.financial-agent-passport.v1 decodes as the financial carrier and then runs its contract validator; any other value raises UnsupportedVersionedPassportSchema.
pub enum VersionedAgentPassport {
V1(AgentPassport),
V2(Box<AgentPassportV2>),
}The carrier is a subject, a list of tagged credentials, and the Merkle roots that commit to them.
The carrier types in Rust
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(
tag = "kind",
content = "credential",
rename_all = "snake_case",
deny_unknown_fields
)]
pub enum PassportCredentialV2 {
Reputation(Box<ReputationCredential>),
Financial(Box<FinancialCredentialEnvelope>),
}
// ...
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct AgentPassportV2 {
pub schema: String,
pub subject: String,
pub credentials: Vec<PassportCredentialV2>,
pub merkle_roots: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub enterprise_identity_provenance: Vec<EnterpriseIdentityProvenance>,
pub issued_at: String,
pub valid_until: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trust_tier: Option<TrustTier>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_manifest: Option<SignedPassportSourceManifestV2>,
}Both credential variants are boxed, and the enum is adjacently tagged: the wire form is {"kind": "financial", "credential": { ... }}. Conversion between the two carriers is named and refuses to lose data. upgrade_v1_passport rewrites the schema tag and wraps each reputation credential as Reputation; try_downgrade_v2_passport returns PassportDowngradeWouldLoseData when the passport holds a financial credential or a source manifest.
The source manifest
Packaging a passport issues a signed PassportSourceManifestV2 over sorted leaves of (credential_id, family, credential_ref_digest). The manifest carries two roots, and a presentation is checked against both.
The manifest struct in Rust
pub struct PassportSourceManifestV2 {
pub schema: String,
pub source_passport_id: String,
pub issuer: String,
pub subject: String,
pub issued_at: u64,
pub expires_at: u64,
pub credential_count: u64,
pub credential_root: String,
pub merkle_roots: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub enterprise_identity_provenance: Vec<EnterpriseIdentityProvenance>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trust_tier: Option<TrustTier>,
}credential_root is the Merkle root over the manifest leaves. merkle_roots is the sorted set of source roots derived from the packaged credentials, so a passport whose declared roots disagree with its credentials fails to build. issued_at and expires_at are Unix integers, and the expiry is clamped to the earliest credential expiry in the bundle. source_passport_id is a digest over the rest of the body under the domain separator chio.financial-agent-passport.source-manifest-id.v1\0.
A leaf’s credential_ref_digest is SHA-256 over the domain separator chio.financial-agent-passport.credential-ref.v1\0 and the canonical JSON of the family together with the complete signed credential. For a financial credential the leaf’s credential_id is the credential’s derived id; for a reputation credential it is the reference digest.
Selective disclosure
Each credential is signed on its own, so a holder drops the ones a verifier did not request without disturbing the remaining signatures. A verifier’s challenge selects by exact envelope digest, because one issuer can sign all five families and issuer-level filtering would disclose more than the verifier asked for. Each PassportCredentialSelectorV2 names a family from PassportCredentialFamilyV2 (the five financial families plus Reputation) and the exact credential_ref_digest it accepts.
The disclosed form is its own type: the exact signed manifest, the selected credentials, one membership proof per credential, and the two digests that bind the subset to one challenge.
The presentation types in Rust
pub struct PresentedAgentPassportV2 {
pub schema: String,
pub source_manifest: SignedPassportSourceManifestV2,
pub credentials: Vec<PassportCredentialV2>,
pub membership_proofs: Vec<PassportCredentialMembershipProofV2>,
pub challenge_digest: String,
pub presentation_digest: String,
}
pub struct PassportCredentialSelectorV2 {
pub family: PassportCredentialFamilyV2,
pub credential_ref_digest: String,
}
pub struct PassportPresentationChallengeV2 {
pub schema: String,
pub verifier: String,
pub verifier_key_epoch: u64,
pub challenge_id: String,
pub nonce: String,
pub issued_at: String,
pub expires_at: String,
pub source_passport_id: String,
pub selectors: Vec<PassportCredentialSelectorV2>,
pub challenge_digest: String,
}presentation_digest is SHA-256 over the domain separator chio.financial-agent-passport.presentation-digest.v1\0 and the canonical JSON of three values: the source-manifest digest (SHA-256 over the canonical signed manifest), the challenge digest, and one (credentialId, credentialRefDigest) entry per membership proof, in proof order. Disclosing a different subset changes that digest and leaves source_passport_id unchanged, so a presentation authorized for one subset never replays as another subset of the same passport. Disclosure granularity is one credential; field-level unlinkable disclosure over individual claim fields has no type in the family.
Provenance and receiving policy
Evidence classes
Two checks fix both positions on the provenance ladder.
The evidence-class validator in Rust
pub(super) fn validate_evidence_classes(
credential: &FinancialCredentialEnvelope,
) -> Result<(), CredentialError> {
if credential.presentation_evidence_class != ProvenanceEvidenceClass::Asserted {
return invalid_financial("financial presentation evidence class must be asserted");
}
let maximum = match &credential.credential_subject {
FinancialCredentialSubjectV1::CreditScorecard(subject)
if subject.imported_signals.accepted_imported_signal_count > 0 =>
{
ProvenanceEvidenceClass::Asserted
}
FinancialCredentialSubjectV1::SettlementReliability(_)
| FinancialCredentialSubjectV1::LossHistory(_) => ProvenanceEvidenceClass::Observed,
_ => ProvenanceEvidenceClass::Verified,
};
if evidence_class_rank(credential.source_evidence_class) > evidence_class_rank(maximum) {
return invalid_financial("financial source evidence class exceeds its family ceiling");
}
Ok(())
}A presentation class other than asserted fails with “financial presentation evidence class must be asserted”. A source class above the family ceiling fails with “financial source evidence class exceeds its family ceiling”.
Enterprise identity provenance
A passport can record how an organization’s identity provider verified the agent, in EnterpriseIdentityProvenance entries. The struct is defined in crates/trust/chio-credentials/src/artifact.rs and rides on both the carrier and its source manifest. Each entry names a provider_id, a provider_kind, the verified principal, the bound subject_key, and a federation_method drawn from EnterpriseFederationMethod: Jwt, Introspection, Scim, or Saml (crates/core/chio-core-types/src/session/auth.rs). Tenant, organization, client, object, groups, roles, per-attribute sources, and a trust-material reference are optional. A receiving organization reads that record beside the issuer signature, without reaching into the issuing organization’s directory.
Verifier policy and the verified set
A receiver pins a policy record and evaluates the presentation against it.
The verifier policy structs in Rust
pub struct FinancialVerifierThresholdsV1 {
pub min_credit_score: Option<f64>,
pub max_open_exposure_ratio_bps: Option<u32>,
pub min_settlement_reliability_bps: Option<u32>,
pub max_loss_event_count: Option<u64>,
pub max_premium_units_by_currency: BTreeMap<String, u64>,
}
pub struct FinancialVerifierPolicyV1 {
pub schema: String,
pub policy_id: String,
pub tenant: String,
pub verifier: String,
pub accepted_issuers: BTreeSet<String>,
pub accepted_families: BTreeSet<FinancialCredentialFamilyV1>,
pub thresholds: FinancialVerifierThresholdsV1,
pub max_credential_age_seconds: u64,
pub not_before: u64,
pub expires_at: u64,
pub configuration_generation: u64,
pub body_digest: String,
}evaluate_financial_credentials lives in crates/trust/chio-credentials/src/financial/authority/evaluation.rs. Its VerifiedFinancialCredentialSet carries the source passport id, the manifest and presentation digests, the pinned policy id, body digest and generation, the lifecycle pins, and one VerifiedFinancialCredentialBindingV2 per accepted credential with its id, family, issuer, issuer key epoch, body and envelope digests, both evidence classes, and the source proof digests.
Cross-issuer aggregation stays unmerged. A CrossIssuerPortfolio (schema chio.cross-issuer-portfolio.v1) lists independently verified passports, and a signed SignedCrossIssuerTrustPack (schema chio.cross-issuer-trust-pack.v1) activates issuers, profile families, entry kinds, migrations, and certification references the local verifier already configured. No type in crates/trust/chio-credentials/src/cross_issuer.rs computes a combined score across issuers.