OrganizationMembership schema
Generated from the canonical schema
schemas/organization-membership.schema.jsonbyscripts/generate-schema-docs.mjs— do not edit this page by hand.
A User's association with an Organization. Users may belong to many Organizations at once, and at most one membership per user/Organization is active (ended_at null) at a time — leaving and rejoining creates a new record, and history is never rewritten. Membership can be established three ways (recorded as provenance): verifying an email at the Organization's canonical verified domain, an admin adding the User directly, or an admin approving the User's membership request. Membership is affiliation only: it is not administrative authority (see OrganizationAdmin) and does not attribute the User's work to the Organization.
Schema version: 1.0.0 · $id: https://tokensforprogress.org/schemas/organization-membership.schema.json
Fields
id
Type: string · Required: yes · Mutable: no · Pattern: ^mem_[0-9a-z]{10,32}$
Stable opaque identifier for this membership record.
Example: "mem_01jf90bb2link"
user_id
Type: string · Required: yes · Mutable: no · Pattern: ^usr_[0-9a-z]{10,32}$
The member User.
Example: "usr_01jf8xw3tempo"
organization_id
Type: string · Required: yes · Mutable: no · Pattern: ^org_[0-9a-z]{10,32}$
The Organization the User is associated with.
Example: "org_01jf90aa1mit0"
role
Type: string \| null · Required: no · Mutable: yes
Optional free-text descriptive role ('Research Scientist', 'PhD Student'), editable by Organization admins. Descriptive only — changing it never alters permissions; administrative capability lives on OrganizationAdmin.
Example: "PhD student"
joined_at
Type: string · Required: yes · Mutable: no
RFC 3339 UTC timestamp when the membership began on TfP.
Example: "2026-08-31T15:04:11Z"
ended_at
Type: string \| null · Required: no · Mutable: yes
RFC 3339 UTC timestamp when the membership ended, or null while current. Set once when the association ends; historical attribution referencing this Organization is unaffected.
Example: null
established_via
Type: domain_email | admin | request_approval · Required: yes · Mutable: no
How the membership was established: domain_email (the User verified an email at the Organization's canonical domain), admin (an admin added the User), request_approval (an admin approved the User's request).
Example: "domain_email"
established_by_user_id
Type: string · Required: yes · Mutable: no · Pattern: ^usr_[0-9a-z]{10,32}$
Who established the membership: the joining User for domain_email, the acting admin for admin, the approving admin for request_approval.
Example: "usr_01jf8xw3tempo"
JSON Schema source
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://tokensforprogress.org/schemas/organization-membership.schema.json",
"title": "OrganizationMembership",
"description": "A User's association with an Organization. Users may belong to many Organizations at once, and at most one membership per user/Organization is active (ended_at null) at a time — leaving and rejoining creates a new record, and history is never rewritten. Membership can be established three ways (recorded as provenance): verifying an email at the Organization's canonical verified domain, an admin adding the User directly, or an admin approving the User's membership request. Membership is affiliation only: it is not administrative authority (see OrganizationAdmin) and does not attribute the User's work to the Organization.",
"x-tfp-version": "1.0.0",
"type": "object",
"additionalProperties": false,
"required": [
"id",
"user_id",
"organization_id",
"joined_at",
"established_via",
"established_by_user_id"
],
"properties": {
"id": {
"type": "string",
"pattern": "^mem_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "Stable opaque identifier for this membership record.",
"examples": [
"mem_01jf90bb2link"
]
},
"user_id": {
"type": "string",
"pattern": "^usr_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "The member User.",
"examples": [
"usr_01jf8xw3tempo"
]
},
"organization_id": {
"type": "string",
"pattern": "^org_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "The Organization the User is associated with.",
"examples": [
"org_01jf90aa1mit0"
]
},
"role": {
"type": [
"string",
"null"
],
"maxLength": 80,
"x-mutable": true,
"description": "Optional free-text descriptive role ('Research Scientist', 'PhD Student'), editable by Organization admins. Descriptive only — changing it never alters permissions; administrative capability lives on OrganizationAdmin.",
"examples": [
"PhD student"
]
},
"joined_at": {
"type": "string",
"format": "date-time",
"x-mutable": false,
"description": "RFC 3339 UTC timestamp when the membership began on TfP.",
"examples": [
"2026-08-31T15:04:11Z"
]
},
"ended_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"x-mutable": true,
"description": "RFC 3339 UTC timestamp when the membership ended, or null while current. Set once when the association ends; historical attribution referencing this Organization is unaffected.",
"examples": [
null
]
},
"established_via": {
"type": "string",
"enum": [
"domain_email",
"admin",
"request_approval"
],
"x-mutable": false,
"description": "How the membership was established: domain_email (the User verified an email at the Organization's canonical domain), admin (an admin added the User), request_approval (an admin approved the User's request).",
"examples": [
"domain_email"
]
},
"established_by_user_id": {
"type": "string",
"pattern": "^usr_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "Who established the membership: the joining User for domain_email, the acting admin for admin, the approving admin for request_approval.",
"examples": [
"usr_01jf8xw3tempo"
]
}
}
}