{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/jid-com/json-schema/jid-com-qualification-schema.json",
  "title": "Qualification",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/jid-com-openapi.json#/components/schemas/Qualification",
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "assessment": {
      "type": "string",
      "enum": [
        "business",
        "individual_or_unverified"
      ]
    },
    "entity": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "confidence": {
          "type": "string",
          "enum": [
            "high",
            "medium",
            "low"
          ]
        },
        "method": {
          "type": "string"
        },
        "relied_on": {
          "type": "boolean"
        },
        "url": {
          "type": "string"
        }
      }
    },
    "signals": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "value": {},
          "effect": {
            "type": "string",
            "enum": [
              "+",
              "-",
              "neutral",
              "review"
            ]
          },
          "detail": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "verified_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    },
    "legitimacy": {
      "$ref": "#/$defs/SubScore"
    },
    "capacity": {
      "$ref": "#/$defs/SubScore"
    },
    "consistency": {
      "$ref": "#/$defs/SubScore"
    },
    "recommendation": {
      "type": "string",
      "enum": [
        "fast_track",
        "standard",
        "verify_first",
        "low_priority"
      ]
    },
    "engage": {
      "type": "boolean",
      "description": "Binary answer from the shared screen rules (same as /v1/screen) under `policy`. Advisory."
    },
    "risk": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high",
        "unknown"
      ]
    },
    "mitigations": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "text": {
            "type": "string"
          }
        }
      }
    },
    "engage_policy": {
      "type": "string",
      "enum": [
        "strict",
        "balanced",
        "permissive"
      ]
    },
    "suggested_next_step": {
      "type": "string"
    },
    "questions_to_ask": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "minItems": 2,
      "maxItems": 4
    },
    "checks": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Check"
      }
    },
    "read": {
      "$ref": "#/$defs/Read"
    },
    "website_declared": {
      "oneOf": [
        {
          "$ref": "#/$defs/WebsiteDeclared"
        },
        {
          "type": "null"
        }
      ]
    },
    "outcome_links": {
      "$ref": "#/$defs/OutcomeLinks"
    },
    "affiliation": {
      "type": [
        "object",
        "null"
      ],
      "description": "Claims only: does the address's domain match the claimed business (same domain, a registry domain of the business, or a link between the two websites)? A mismatch means manual review, never rejection.",
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "matched",
            "mismatched",
            "unknown"
          ]
        },
        "email_domain": {
          "type": [
            "string",
            "null"
          ]
        },
        "claimed_domain": {
          "type": [
            "string",
            "null"
          ]
        },
        "evidence": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string"
              },
              "source": {
                "type": "string"
              },
              "source_url": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      }
    },
    "location": {
      "type": [
        "object",
        "null"
      ],
      "description": "Present when location inputs were given: the same block as /v1/screen. A mismatch, Tor exit or hosting/VPN network adds risk only alongside another negative signal and never sets engage=false on its own. Jid keeps only ip_country, ip_region, network type and consistent.",
      "properties": {
        "consistent": {
          "type": [
            "boolean",
            "string"
          ],
          "description": "true, false or \"unknown\""
        },
        "reference": {
          "type": [
            "object",
            "null"
          ]
        },
        "signals": {
          "type": "array",
          "items": {
            "type": "object"
          }
        },
        "network": {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "enum": [
                "tor",
                "hosting_or_vpn",
                "other",
                "unknown"
              ]
            },
            "asn": {
              "type": [
                "integer",
                "null"
              ]
            },
            "source": {
              "type": "string"
            }
          }
        },
        "detail": {
          "type": "string"
        }
      }
    },
    "summary": {
      "type": [
        "string",
        "null"
      ]
    },
    "rules_version": {
      "type": "string"
    },
    "receipt": {
      "$ref": "#/$defs/Receipt"
    },
    "retention": {
      "type": "object",
      "properties": {
        "result_until": {
          "type": "string"
        },
        "message_stored": {
          "type": "boolean"
        }
      }
    },
    "checks_used": {
      "type": "integer"
    }
  },
  "$defs": {
    "Check": {
      "type": "object",
      "description": "One check from the registry. New checks add rows, never fields.",
      "properties": {
        "id": {
          "type": "string",
          "description": "Stable id: registered, sanctions, threat_feeds, email_address, mail_domain, domain_age, website, affiliation, adverse_records, licence, phone, location, enquiry, funding, complaints, lookalike_domain, email_auth, history"
        },
        "label": {
          "type": "string"
        },
        "group": {
          "type": "string",
          "enum": [
            "identity",
            "legitimacy",
            "safety",
            "location",
            "capacity",
            "history"
          ]
        },
        "status": {
          "type": "string",
          "enum": [
            "pass",
            "fail",
            "unknown",
            "na"
          ]
        },
        "severity": {
          "type": "string",
          "enum": [
            "block",
            "warn",
            "info"
          ],
          "description": "What a fail means: block = do not engage, warn = verify first, info = never changes the recommendation"
        },
        "evidence": {
          "type": "string"
        },
        "lookup": {
          "type": "object",
          "properties": {
            "label": {
              "type": "string"
            },
            "url": {
              "type": "string"
            }
          }
        },
        "phrase": {
          "type": "string"
        }
      }
    },
    "OutcomeLinks": {
      "type": "object",
      "description": "Keyed calls only: signed one-click URLs that record an outcome (POST /v1/outcomes) without a login.",
      "properties": {
        "legit": {
          "type": "string"
        },
        "sales_pitch": {
          "type": "string"
        },
        "spam": {
          "type": "string"
        },
        "scam": {
          "type": "string"
        },
        "closed": {
          "type": "string"
        },
        "good": {
          "type": "string",
          "description": "2026-10-05 button, still accepted"
        },
        "junk": {
          "type": "string",
          "description": "2026-10-05 button, still accepted"
        }
      }
    },
    "Read": {
      "type": "object",
      "description": "What to show a human: render this and nothing else.",
      "properties": {
        "headline": {
          "type": "string"
        },
        "recommendation": {
          "type": "string",
          "enum": [
            "engage",
            "verify_first",
            "do_not_engage"
          ]
        },
        "passed": {
          "type": "integer"
        },
        "total": {
          "type": "integer",
          "description": "Checks that ran (status pass or fail) and decide (severity block or warn), plus location consistency, which is counted but never decides"
        },
        "reason": {
          "type": "string",
          "description": "Why a read with no registry match is not engage, e.g. \"Not found on the registers Jid checks for Indonesia (LEI records only)\". Also in the headline, followed by \", so: verify first\"."
        },
        "not_checked": {
          "type": "array",
          "maxItems": 4,
          "items": {
            "type": "string"
          },
          "description": "Labels of deciding checks that did not run or did not finish"
        },
        "sender": {
          "type": "string",
          "description": "Qualify only, response only (never stored): the Jid Signals location next to the stated place and the company domain's age"
        },
        "failed": {
          "type": "array",
          "maxItems": 3,
          "items": {
            "type": "object",
            "properties": {
              "label": {
                "type": "string"
              },
              "evidence": {
                "type": "string"
              },
              "lookup": {
                "type": "object"
              }
            }
          }
        },
        "lookups": {
          "type": "array",
          "maxItems": 4,
          "items": {
            "type": "object",
            "properties": {
              "label": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            }
          }
        },
        "file_url": {
          "type": "string"
        },
        "subject": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "Receipt": {
      "type": "object",
      "properties": {
        "receipt_id": {
          "type": "string"
        },
        "url": {
          "type": "string"
        },
        "statement": {
          "type": "object",
          "description": "Exactly what was signed: type, version, receipt_id, issued_at, issuer, entity, inputs, decision, rules_version, reasons (code, met, effect, fact_ids, source, verified_at, fresh_until), facts (id, predicate, source, value_sha256, verified_at), terms."
        },
        "signature": {
          "type": "object",
          "properties": {
            "alg": {
              "const": "Ed25519"
            },
            "kid": {
              "type": "string"
            },
            "canonicalization": {
              "const": "sorted-keys-json"
            },
            "sig": {
              "type": "string",
              "description": "base64url"
            }
          }
        },
        "verify": {
          "type": "string"
        }
      }
    },
    "SubScore": {
      "type": "object",
      "properties": {
        "score": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "maximum": 100,
          "description": "null when assessment is individual_or_unverified"
        },
        "reasons": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string"
              },
              "points": {
                "type": "number"
              }
            }
          }
        }
      }
    },
    "WebsiteDeclared": {
      "type": "object",
      "description": "What a company's own website states about itself (provenance tier website_declared): identity context only, never a registry result. Present only when no Jid file holds or is associated with the domain.",
      "properties": {
        "tier": {
          "type": "string",
          "enum": [
            "website_declared"
          ]
        },
        "domain": {
          "type": "string"
        },
        "legal_name": {
          "type": "string",
          "description": "As printed, with its legal form"
        },
        "trade_name": {
          "type": [
            "string",
            "null"
          ]
        },
        "address": {
          "type": [
            "string",
            "null"
          ],
          "description": "As printed; null when the site prints addresses in several states"
        },
        "state": {
          "type": [
            "string",
            "null"
          ]
        },
        "postal_code": {
          "type": [
            "string",
            "null"
          ]
        },
        "source_url": {
          "type": "string"
        },
        "read_at": {
          "type": "string",
          "format": "date-time"
        },
        "how": {
          "type": "string"
        },
        "note": {
          "type": "string"
        }
      }
    }
  }
}