{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://trooth.co/schemas/network-profile.v2.schema.json",
  "title": "Trooth Network profile response, contract version 2",
  "description": "The body GET https://trooth.co/api/network/profile?q=<domain or slug> returns, as JSON Schema. This is the canonical shape: the route is tested against it on every push (tests/public-contract-schema.test.mjs) and the live route is checked against it after every deployment (scripts/verify-public-contract.mjs). The MCP tool trooth_public_trust_profile on api.trooth.co reads this body and writes its answer from it. Additions do not move the contract version and are not refused here; a removal, a rename or a change of meaning moves it, and a new file is published beside this one. What this schema deliberately refuses: any field named score, rating, rank, grade or confidence, because the contract carries none and a reader must not be able to find one.",
  "oneOf": [
    {
      "$ref": "#/$defs/notFound"
    },
    {
      "$ref": "#/$defs/found"
    }
  ],
  "$defs": {
    "nullableString": {
      "type": [
        "string",
        "null"
      ]
    },
    "notFound": {
      "type": "object",
      "description": "No published profile answers this query, or the query was refused. Not an error about the company; the Network does not hold it.",
      "required": [
        "found"
      ],
      "properties": {
        "found": {
          "const": false
        },
        "error": {
          "type": "string"
        },
        "message": {
          "type": "string"
        },
        "contractVersion": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "found": {
      "type": "object",
      "required": [
        "found",
        "contractVersion",
        "contractNote",
        "contractOmissions",
        "deprecation",
        "slug",
        "name",
        "domain",
        "canonicalUrl",
        "tagline",
        "industries",
        "updatedAt",
        "witnessed",
        "methodology",
        "facts",
        "conflicts"
      ],
      "properties": {
        "found": {
          "const": true
        },
        "contractVersion": {
          "type": "integer",
          "minimum": 1
        },
        "contractNote": {
          "type": "string",
          "minLength": 1
        },
        "contractOmissions": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1
        },
        "deprecation": {
          "type": "string"
        },
        "contractSchema": {
          "type": "string",
          "pattern": "^https://trooth\\.co/schemas/network-profile\\.v[0-9]+\\.schema\\.json$"
        },
        "slug": {
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]*$"
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "domain": {
          "$ref": "#/$defs/nullableString"
        },
        "canonicalUrl": {
          "type": "string",
          "pattern": "^https://trooth\\.co/network/company/[a-z0-9-]+$"
        },
        "tagline": {
          "$ref": "#/$defs/nullableString"
        },
        "industries": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "updatedAt": {
          "$ref": "#/$defs/nullableString"
        },
        "witnessed": {
          "$ref": "#/$defs/witnessBlock"
        },
        "witnessStatement": {
          "$ref": "#/$defs/witnessStatement"
        },
        "methodology": {
          "$ref": "#/$defs/methodology"
        },
        "facts": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/fact"
          }
        },
        "conflicts": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/conflict"
          }
        },
        "signing": {
          "$ref": "#/$defs/signing"
        },
        "requestedContract": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "integer"
            }
          ],
          "description": "The contract the caller asked for with ?contract= or the Trooth-Contract header, or null when it asked for none. contractVersion is the contract that served the response. Additive in contract 2 (2026-09-26)."
        },
        "evidenceClasses": {
          "type": "object",
          "description": "What each evidenceClass value means. Additive in contract 2 (2026-09-26)."
        },
        "authority": {
          "type": "object",
          "description": "Domain control, registry match, representative authority and publication permission, each stated separately. Additive in contract 2 (2026-09-26).",
          "required": [
            "domainControl",
            "registryMatch",
            "representativeAuthority",
            "publicationPermission"
          ]
        },
        "relationships": {
          "type": "object",
          "description": "What a listed relationship does and does not establish. Additive in contract 2 (2026-09-26)."
        }
      },
      "not": {
        "anyOf": [
          {
            "required": [
              "score"
            ]
          },
          {
            "required": [
              "rating"
            ]
          },
          {
            "required": [
              "rank"
            ]
          },
          {
            "required": [
              "grade"
            ]
          },
          {
            "required": [
              "confidence"
            ]
          }
        ]
      }
    },
    "witnessBlock": {
      "description": "What Trooth itself has observed about the company's public surface. `standing` is either the word `witnessed` or null; there is no third value and no degree. Null throughout means no observation was returned, which is not a finding about the company.",
      "oneOf": [
        {
          "type": "object",
          "required": [
            "standing",
            "lastWitnessed",
            "firstWitnessedAt",
            "coverage",
            "continuity"
          ],
          "properties": {
            "standing": {
              "const": "witnessed"
            },
            "lastWitnessed": {
              "$ref": "#/$defs/nullableString"
            },
            "firstWitnessedAt": {
              "$ref": "#/$defs/nullableString"
            },
            "coverage": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "type": "object",
                  "required": [
                    "checksPassed",
                    "checksRun"
                  ],
                  "properties": {
                    "checksPassed": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "checksRun": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "source": {
                      "enum": [
                        "witness_statement",
                        "result_tally"
                      ],
                      "description": "What checksRun and checksPassed count. witness_statement: computed from the signed witness statement's entries; checksRun is checks read in this reading. result_tally: the reading's own tally for a reading with no statement; not a count of checks read. Additive in contract 2 (2026-09-26); absent on responses served before it."
                    },
                    "definition": {
                      "type": "string",
                      "description": "The same meaning, as a sentence."
                    },
                    "checksNotRead": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Entries in the reading that were not read in it. Present when source is witness_statement."
                    },
                    "checksInReading": {
                      "type": "integer",
                      "minimum": 1,
                      "description": "checksRun plus checksNotRead. Present when source is witness_statement."
                    }
                  }
                }
              ]
            },
            "continuity": {
              "type": "object",
              "required": [
                "recordBegan",
                "unbrokenSince",
                "unbrokenReadings",
                "totalReadings"
              ],
              "properties": {
                "recordBegan": {
                  "$ref": "#/$defs/nullableString"
                },
                "unbrokenSince": {
                  "$ref": "#/$defs/nullableString"
                },
                "unbrokenReadings": {
                  "type": "integer",
                  "minimum": 0
                },
                "totalReadings": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            }
          }
        },
        {
          "type": "object",
          "required": [
            "standing",
            "lastWitnessed",
            "firstWitnessedAt",
            "coverage",
            "continuity"
          ],
          "properties": {
            "standing": {
              "type": "null"
            },
            "lastWitnessed": {
              "type": "null"
            },
            "firstWitnessedAt": {
              "type": "null"
            },
            "coverage": {
              "type": "null"
            },
            "continuity": {
              "type": "null"
            }
          }
        }
      ]
    },
    "witnessStatement": {
      "type": "object",
      "description": "Trooth's signed statement of the reading behind `witnessed`, carried exactly as the upstream witness worker signed it. Present only when that reading was signed under the witness statement; absent (the key is not in the body) for an older reading, which is not a failed check. `payload` is the signing input itself: check the Ed25519 signature over its UTF-8 bytes with the key `key_id` names at https://api.trooth.co/public/keys, decoding that key by its `encoding`, then parse `payload` to read it. The payload is a JSON object with `statement` (trooth.witness-statement.v1), `reading_id`, `domain`, `read_at`, `checks` (each with `id`, `category`, `kind` and an `outcome` of `as expected`, `not as expected` or `not read`) and `counts` (`read`, `as_expected`). It carries no verdict, no threshold and no composite figure. This is the only signed part of the body. Trooth signs what it witnessed. It never signs on a company's behalf.",
      "required": [
        "payload",
        "signature",
        "key_id",
        "alg",
        "canonicalization"
      ],
      "properties": {
        "payload": {
          "type": "string",
          "minLength": 2,
          "description": "The exact string that was signed. Do not re-serialize it before checking."
        },
        "signature": {
          "type": "string",
          "pattern": "^ed25519:[A-Za-z0-9+/]+={0,2}$",
          "description": "The prefix `ed25519:` followed by the standard base64 of the 64 signature bytes."
        },
        "key_id": {
          "type": "string",
          "minLength": 1,
          "description": "The `kid` of the signing key at https://api.trooth.co/public/keys."
        },
        "alg": {
          "const": "Ed25519"
        },
        "canonicalization": {
          "type": "string",
          "minLength": 1,
          "description": "How the worker serialized the payload before signing: JSON with keys in a fixed order and no whitespace, as UTF-8. `payload` is already in that form."
        }
      }
    },
    "methodology": {
      "type": "object",
      "description": "How the witnessed block was produced and what it does not cover. Included in every response so a reader restating witnessed elsewhere can carry the limits with it.",
      "required": [
        "cadence",
        "gapTolerance",
        "retention",
        "freshness",
        "exclusions",
        "summary"
      ],
      "properties": {
        "cadence": {
          "type": "string"
        },
        "gapTolerance": {
          "type": "string"
        },
        "retention": {
          "type": "string"
        },
        "freshness": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "category",
              "label",
              "window"
            ],
            "properties": {
              "category": {
                "type": "string"
              },
              "label": {
                "type": "string"
              },
              "window": {
                "type": "string"
              }
            }
          }
        },
        "exclusions": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1
        },
        "summary": {
          "type": "string"
        }
      }
    },
    "origin": {
      "description": "Who said it. company-declared is the company's own statement; witnessed is Trooth's observation; public-source is a named third party. The order accounts are listed in is fixed and is not a ranking.",
      "enum": [
        "company-declared",
        "witnessed",
        "public-source"
      ]
    },
    "fact": {
      "type": "object",
      "required": [
        "key",
        "category",
        "label",
        "value",
        "origin"
      ],
      "properties": {
        "key": {
          "type": "string",
          "pattern": "^[a-z0-9-]+\\.[a-z0-9-]+$"
        },
        "category": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "origin": {
          "$ref": "#/$defs/origin"
        },
        "contested": {
          "type": "boolean",
          "description": "True when another source gave a different account; the accounts are in conflicts under the same key, and value is one of them, not the winner."
        },
        "claim": {
          "type": "object",
          "description": "Typed provenance for this claim, additive in contract 2 (2026-09-26). Fields Trooth does not hold are null and named in unknown; a claim never inherits the reading's time or signature.",
          "required": [
            "claimId",
            "subject",
            "evidenceClass",
            "signed",
            "issuerAuthenticated",
            "unknown"
          ],
          "properties": {
            "claimId": {
              "type": "string"
            },
            "subject": {
              "type": "object",
              "required": [
                "domain",
                "scope"
              ],
              "properties": {
                "domain": {
                  "type": "string"
                },
                "scope": {
                  "const": "company"
                }
              }
            },
            "evidenceClass": {
              "enum": [
                "company_declaration",
                "trooth_observation",
                "public_record"
              ]
            },
            "declaredAt": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "type": "string"
                }
              ]
            },
            "observedAt": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "type": "string"
                }
              ]
            },
            "validUntil": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "type": "string"
                }
              ]
            },
            "evidenceRef": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "type": "string"
                }
              ]
            },
            "signed": {
              "const": false
            },
            "issuerAuthenticated": {
              "const": false
            },
            "unknown": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "conflict": {
      "type": "object",
      "required": [
        "key",
        "category",
        "label",
        "accounts"
      ],
      "properties": {
        "key": {
          "type": "string"
        },
        "category": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "accounts": {
          "type": "array",
          "minItems": 2,
          "items": {
            "type": "object",
            "required": [
              "origin",
              "value"
            ],
            "properties": {
              "origin": {
                "$ref": "#/$defs/origin"
              },
              "value": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "signing": {
      "type": "object",
      "description": "What in this response is signed. Additive in contract 2 (2026-09-26). profileSigned is always false: the one signed object is witnessStatement, which covers one reading and nothing else.",
      "required": [
        "profileSigned",
        "signedArtifact",
        "subject"
      ],
      "properties": {
        "profileSigned": {
          "const": false
        },
        "signedArtifact": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "const": "witnessStatement"
            }
          ]
        },
        "artifactType": {
          "type": "string"
        },
        "subject": {
          "type": "string"
        },
        "keyId": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "string"
            }
          ]
        },
        "keyPurpose": {
          "type": "string"
        },
        "observedAt": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "string"
            }
          ]
        },
        "timeSource": {
          "type": "string"
        },
        "verify": {
          "type": "string"
        },
        "keys": {
          "type": "string"
        },
        "keyPolicy": {
          "type": "string"
        }
      }
    }
  }
}
