TfP Docs

OrganizationDomain schema

Generated from the canonical schema schemas/organization-domain.schema.json by scripts/generate-schema-docs.mjs — do not edit this page by hand.

A verification-bearing relationship between an Organization and an institutional domain. Created on first successful verification — merely claiming a domain reserves nothing. Cardinality is one-to-one for v0: at most one Organization holds a non-revoked relationship to a given domain, and an Organization has at most one non-revoked canonical domain (alias/additional domains are a deliberate later extension). DNS-verified domain control can be established by any authenticated User — including one who is not yet an Organization admin — and serves as the recovery path for an already-claimed Organization: the domain controller becomes an admin with the narrow authority to end other admin grants, and controller status itself can rotate: a current controller may remove another controller grant, but never the last one. The current strength is derived from the strongest non-revoked verification event: email_verified (mailbox access at the domain) or domain_controlled (DNS control, which outranks email). Commodity personal-mail domains are ineligible.

Schema version: 1.0.0 · $id: https://tokensforprogress.org/schemas/organization-domain.schema.json

Fields

id

Type: string · Required: yes · Mutable: no · Pattern: ^dom_[0-9a-z]{10,32}$

Stable opaque identifier.

Example: "dom_01jf91aa1anth"

organization_id

Type: string · Required: yes · Mutable: no · Pattern: ^org_[0-9a-z]{10,32}$

The Organization this domain relationship belongs to.

Example: "org_01jf90aa1mit0"

domain

Type: string · Required: yes · Mutable: no · Pattern: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$

The verified domain, lowercased, exactly as verified (institutional subdomains are preserved, not silently widened to a parent domain).

Example: "example.org"

status

Type: email_verified | domain_controlled | revoked · Required: yes · Mutable: yes

Current derived verification strength. domain_controlled (DNS proof) outranks email_verified (mailbox proof). revoked relationships free the domain for another Organization.

Example: "email_verified"

created_at

Type: string · Required: yes · Mutable: no

RFC 3339 UTC timestamp of the first successful verification.

Example: "2026-08-31T18:00:00Z"

updated_at

Type: string · Required: yes · Mutable: yes

RFC 3339 UTC timestamp of the most recent status change.

Example: "2026-08-31T18:00:00Z"

JSON Schema source

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://tokensforprogress.org/schemas/organization-domain.schema.json",
  "title": "OrganizationDomain",
  "description": "A verification-bearing relationship between an Organization and an institutional domain. Created on first successful verification — merely claiming a domain reserves nothing. Cardinality is one-to-one for v0: at most one Organization holds a non-revoked relationship to a given domain, and an Organization has at most one non-revoked canonical domain (alias/additional domains are a deliberate later extension). DNS-verified domain control can be established by any authenticated User — including one who is not yet an Organization admin — and serves as the recovery path for an already-claimed Organization: the domain controller becomes an admin with the narrow authority to end other admin grants, and controller status itself can rotate: a current controller may remove another controller grant, but never the last one. The current strength is derived from the strongest non-revoked verification event: email_verified (mailbox access at the domain) or domain_controlled (DNS control, which outranks email). Commodity personal-mail domains are ineligible.",
  "x-tfp-version": "1.0.0",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "id",
    "organization_id",
    "domain",
    "status",
    "created_at",
    "updated_at"
  ],
  "properties": {
    "id": {
      "type": "string",
      "pattern": "^dom_[0-9a-z]{10,32}$",
      "x-mutable": false,
      "description": "Stable opaque identifier.",
      "examples": [
        "dom_01jf91aa1anth"
      ]
    },
    "organization_id": {
      "type": "string",
      "pattern": "^org_[0-9a-z]{10,32}$",
      "x-mutable": false,
      "description": "The Organization this domain relationship belongs to.",
      "examples": [
        "org_01jf90aa1mit0"
      ]
    },
    "domain": {
      "type": "string",
      "pattern": "^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$",
      "x-mutable": false,
      "description": "The verified domain, lowercased, exactly as verified (institutional subdomains are preserved, not silently widened to a parent domain).",
      "examples": [
        "example.org"
      ]
    },
    "status": {
      "type": "string",
      "enum": [
        "email_verified",
        "domain_controlled",
        "revoked"
      ],
      "x-mutable": true,
      "description": "Current derived verification strength. domain_controlled (DNS proof) outranks email_verified (mailbox proof). revoked relationships free the domain for another Organization.",
      "examples": [
        "email_verified"
      ]
    },
    "created_at": {
      "type": "string",
      "format": "date-time",
      "x-mutable": false,
      "description": "RFC 3339 UTC timestamp of the first successful verification.",
      "examples": [
        "2026-08-31T18:00:00Z"
      ]
    },
    "updated_at": {
      "type": "string",
      "format": "date-time",
      "x-mutable": true,
      "description": "RFC 3339 UTC timestamp of the most recent status change.",
      "examples": [
        "2026-08-31T18:00:00Z"
      ]
    }
  }
}