{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/good-grants/json-schema/good-grants-tab-schema.json",
  "title": "Tab",
  "description": "Section of a form that groups what is collected from applicants, such as application details, custom fields, attachments, contributors, or referees.",
  "x-generated": "2026-10-28",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/good-grants-openapi.yaml#/components/schemas/Tab",
  "type": "object",
  "properties": {
    "categories": {
      "type": "array",
      "description": "Categories the tab is shown in, or `[\"*\"]` when it is shown in every category.\n\n`category_option` says which of the two a tab is using, so read that rather than testing for the marker. The same shape is used by the `categories` property of a field.",
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "slug": {
                "type": "string",
                "description": "Short URL-safe identifier for the category."
              },
              "link": {
                "type": "string",
                "format": "uri",
                "description": "Canonical URL for the category resource."
              },
              "name": {
                "type": "object",
                "description": "Map of translated strings keyed by locale code (for example, `en_GB` or `fr_FR`).",
                "additionalProperties": {
                  "type": "string"
                }
              }
            }
          },
          {
            "type": "string",
            "enum": [
              "*"
            ]
          }
        ]
      }
    },
    "category_option": {
      "type": "string",
      "description": "How categories are applied to the tab.\n  * `all` - Shown in every category.\n  * `select` - Shown only in the categories listed in `categories`.",
      "enum": [
        "all",
        "select"
      ]
    },
    "content_block": {
      "type": [
        "object",
        "null"
      ],
      "description": "Content block shown at the top of the tab, or `null` when no content block is assigned.",
      "properties": {
        "slug": {
          "type": "string",
          "description": "Short URL-safe identifier for the content block."
        },
        "link": {
          "type": "string",
          "format": "uri",
          "description": "Canonical URL for the content block resource."
        },
        "name": {
          "type": "object",
          "description": "Map of translated strings keyed by locale code (for example, `en_GB` or `fr_FR`).",
          "additionalProperties": {
            "type": "string"
          }
        }
      }
    },
    "created": {
      "type": "string",
      "format": "date-time",
      "description": "Date and time when the tab was created."
    },
    "field_count": {
      "type": "integer",
      "description": "Number of fields attached to the tab."
    },
    "form": {
      "type": "string",
      "pattern": "^[A-Za-z]{8}$",
      "description": "Slug of the form the tab belongs to."
    },
    "locked": {
      "type": "boolean",
      "description": "Specifies whether the tab is locked.\n\nA locked tab always holds position `1` and you cannot reorder or delete it."
    },
    "name": {
      "type": "object",
      "description": "Display name of the tab, as a map of translated strings keyed by locale code.",
      "additionalProperties": {
        "type": "string"
      }
    },
    "order": {
      "type": "integer",
      "description": "Position of the tab within the form, where lower values appear first."
    },
    "resource": {
      "type": "string",
      "description": "Resource the tab collects data for.\n  * `applications` - Part of an application form.\n  * `users` - Part of the user profile form.",
      "enum": [
        "applications",
        "users"
      ]
    },
    "season": {
      "type": "object",
      "description": "Season the tab belongs to.",
      "properties": {
        "slug": {
          "type": "string",
          "description": "Short URL-safe identifier for the season."
        },
        "link": {
          "type": "string",
          "format": "uri",
          "description": "Canonical URL for the season resource."
        },
        "name": {
          "type": "object",
          "description": "Map of translated strings keyed by locale code (for example, `en_GB` or `fr_FR`).",
          "additionalProperties": {
            "type": "string"
          }
        }
      }
    },
    "settings": {
      "type": [
        "object",
        "null"
      ],
      "description": "Configuration that applies only to this type of tab, or `null` for a type that carries none, such as a details or fields tab.\n\nEach type populates its own properties and omits the rest: an attachments tab carries the upload limits, an eligibility tab the assessment and communication settings, a referees tab the reference limits, and a contributors tab the contributor limits.\n\nThese are the limits the applicant form applies. Apply them in your own interface so that applicants do not upload files the form would refuse.",
      "properties": {
        "allowed_file_types": {
          "type": [
            "object",
            "array"
          ],
          "maxItems": 0,
          "description": "File extensions accepted, keyed by file type group. The groups are `documents`, `images`, `graphics`, `audio`, `video` and `archives`, and each extension belongs to the group it is listed under.\n\nAn empty array (`[]`) when the tab accepts every extension the account allows.",
          "additionalProperties": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "accept_attachment_links": {
          "type": "boolean",
          "description": "Specifies whether the tab accepts a link to a file in place of an upload."
        },
        "min_attachments": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Smallest number of attachments required, or `null` when no minimum is set."
        },
        "max_attachments": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Largest number of attachments accepted, or `null` when no maximum is set."
        },
        "min_filesize": {
          "type": [
            "number",
            "null"
          ],
          "description": "Smallest accepted file size in megabytes, or `null` when no minimum is set."
        },
        "max_filesize": {
          "type": [
            "number",
            "null"
          ],
          "description": "Largest accepted file size in megabytes, or `null` when no maximum is set.\n\nThe account file size limit applies as well, and the smaller of the two wins."
        },
        "min_video_length": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Shortest accepted video length in seconds, or `null` when no minimum is set."
        },
        "max_video_length": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Longest accepted video length in seconds, or `null` when no maximum is set."
        },
        "image_dimension_constraints": {
          "type": "object",
          "description": "Pixel dimensions accepted for uploaded images. Each value is `null` when that constraint is not set.",
          "properties": {
            "min_width": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Smallest accepted image width in pixels."
            },
            "max_width": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Largest accepted image width in pixels."
            },
            "min_height": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Smallest accepted image height in pixels."
            },
            "max_height": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Largest accepted image height in pixels."
            }
          }
        },
        "assessment_mode": {
          "type": [
            "string",
            "null"
          ],
          "description": "How an eligibility tab decides the outcome, or `null` when no mode is set.\n  * `auto` - Scored against `min_eligibility_score`.\n  * `manual` - Decided by a program manager.\n  * `both` - Scored first, then confirmed by a program manager.",
          "enum": [
            "auto",
            "manual",
            "both",
            null
          ]
        },
        "min_eligibility_score": {
          "type": [
            "number",
            "null"
          ],
          "description": "Score an application must reach to be eligible. Applies when `assessment_mode` is `auto` or `both`."
        },
        "hide_other_tabs_when_ineligible": {
          "type": "boolean",
          "description": "Specifies whether the remaining tabs are hidden from an application found ineligible."
        },
        "eligible_content_block": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the content block shown to an eligible application."
        },
        "ineligible_content_block": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the content block shown to an ineligible application."
        },
        "pending_eligibility_content_block": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the content block shown while eligibility is still being decided."
        },
        "eligible_notification": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the notification sent when an application is found eligible."
        },
        "ineligible_notification": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the notification sent when an application is found ineligible."
        },
        "pending_eligibility_notification": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the notification sent while eligibility is still being decided."
        },
        "action_stage": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug of the action stage a referees tab collects references for."
        },
        "min_referees": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Smallest number of referees required, or `null` when no minimum is set."
        },
        "max_referees": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Largest number of referees accepted, or `null` when no maximum is set."
        },
        "min_contributors": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Smallest number of contributors required, or `null` when no minimum is set."
        },
        "max_contributors": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Largest number of contributors accepted, or `null` when no maximum is set."
        }
      }
    },
    "slug": {
      "type": "string",
      "description": "Short URL-safe identifier for the tab."
    },
    "tab_divider_on_pdfs": {
      "type": "boolean",
      "description": "Specifies whether generated PDF documents include a divider page for the tab."
    },
    "type": {
      "type": "string",
      "description": "Type of the tab, which determines what the tab collects.\n  * `details` - Core application details, such as the application title and the category the application is submitted to.\n  * `attachments` - Supplementary files uploaded against the application.\n  * `contributors` - People credited on the application alongside the applicant.\n  * `fields` - Answers to the custom fields on the form.\n  * `eligibility` - Answers used to assess whether the application is eligible.\n  * `referees` - Referees asked to provide a reference for the application.",
      "enum": [
        "details",
        "attachments",
        "contributors",
        "fields",
        "eligibility",
        "referees"
      ]
    },
    "updated": {
      "type": "string",
      "format": "date-time",
      "description": "Date and time when the tab was last updated."
    },
    "visible_to_applicants": {
      "type": "boolean",
      "description": "Specifies whether applicants see the tab.\n\nA tab hidden from applicants stays visible to program managers, so use it to collect information applicants do not manage themselves."
    }
  }
}