{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/api-evangelist/cosuno/main/json-schema/cosuno-project-response-schema.json",
  "title": "ProjectResponse",
  "x-generated": "2026-10-11",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/cosuno-openapi.json#/components/schemas/ProjectResponse",
  "properties": {
    "number": {
      "type": [
        "string",
        "null"
      ],
      "description": "Internal project number or reference code used by your company.",
      "maxLength": 100
    },
    "name": {
      "type": "string",
      "description": "Name of the project.",
      "maxLength": 100
    },
    "customer": {
      "type": [
        "string",
        "null"
      ],
      "description": "Customer (client) the project is being delivered for.",
      "maxLength": 100
    },
    "location": {
      "type": "string",
      "description": "Location of the construction site (typically an address or place name).",
      "maxLength": 200
    },
    "description": {
      "type": [
        "string",
        "null"
      ],
      "description": "Longer free-form description of the project.",
      "maxLength": 60000
    },
    "budget": {
      "type": [
        "number",
        "null"
      ],
      "format": "double",
      "description": "Total budget allocated for the project, in the project's currency."
    },
    "notes": {
      "type": [
        "string",
        "null"
      ],
      "description": "Free-form internal notes about the project."
    },
    "defaultTaxRate": {
      "type": [
        "number",
        "null"
      ],
      "format": "double",
      "description": "Default value-added tax rate applied to new bid packages in the project, expressed as a fraction between 0 and 1 (e.g. 0.19 for 19%).",
      "minimum": 0,
      "maximum": 1
    },
    "id": {
      "type": "string",
      "description": "ID of the project."
    },
    "status": {
      "$ref": "#/$defs/PROJECT_STATUS",
      "description": "Current lifecycle status of the project."
    },
    "office": {
      "$ref": "#/$defs/OfficeResponse",
      "description": "Office that owns the project."
    },
    "primaryUser": {
      "$ref": "#/$defs/UserResponse",
      "description": "Primary user in charge of the project."
    },
    "primaryContactUser": {
      "$ref": "#/$defs/UserResponse",
      "description": "User designated as the primary contact for subcontractors on the project. Defaults to the primary user if not set explicitly."
    },
    "projectUsers": {
      "items": {
        "$ref": "#/$defs/ProjectUserResponse"
      },
      "type": "array",
      "description": "Users assigned to the project with their roles."
    },
    "isEstimating": {
      "type": "boolean",
      "description": "Whether the project is currently in the estimating phase (no tenders have been sent out yet)."
    },
    "category": {
      "$ref": "#/$defs/PROJECT_CATEGORY",
      "description": "Category classifying the kind of construction work (e.g. new build, renovation)."
    },
    "customFields": {
      "items": {
        "$ref": "#/$defs/MappedCustomField"
      },
      "type": "array",
      "description": "Values for the custom fields defined on projects in your company."
    },
    "startsOn": {
      "type": "string",
      "description": "Planned start date of the project's construction work.",
      "format": "date"
    },
    "endsOn": {
      "type": "string",
      "description": "Planned end date of the project's construction work.",
      "format": "date"
    },
    "tenderingStartsOn": {
      "type": "string",
      "description": "Planned date on which tendering for the project starts.",
      "format": "date"
    },
    "preferredBoQFileFormat": {
      "$ref": "#/$defs/BOQ_FILE_FORMAT",
      "description": "Preferred BoQ file format for the project."
    },
    "costGroupCatalogs": {
      "items": {
        "$ref": "#/$defs/ProjectCostGroupCatalog"
      },
      "type": "array",
      "description": "Cost group catalogs enabled on the project."
    }
  },
  "required": [
    "name",
    "location",
    "id",
    "status",
    "office",
    "projectUsers",
    "isEstimating",
    "preferredBoQFileFormat",
    "costGroupCatalogs"
  ],
  "type": "object",
  "additionalProperties": false,
  "$defs": {
    "BOQ_FILE_FORMAT": {
      "type": "string",
      "enum": [
        "oenorm",
        "gaebXml",
        "gaeb90",
        "xlsx"
      ],
      "nullable": false
    },
    "MappedCustomField": {
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "value": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "number",
              "format": "double"
            },
            {
              "type": "boolean"
            },
            {
              "type": "string",
              "format": "date-time"
            },
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            }
          ],
          "nullable": true
        }
      },
      "required": [
        "id",
        "label"
      ],
      "type": "object",
      "additionalProperties": false
    },
    "OFFICE_STATUS": {
      "type": "string",
      "enum": [
        "active",
        "inactive"
      ],
      "nullable": false
    },
    "OfficeResponse": {
      "properties": {
        "id": {
          "type": "string",
          "description": "ID of the office."
        },
        "name": {
          "type": "string",
          "description": "Display name of the office."
        },
        "status": {
          "$ref": "#/$defs/OFFICE_STATUS",
          "description": "Current status of the office. Inactive offices can no longer have new projects or users assigned to them."
        }
      },
      "required": [
        "id",
        "name",
        "status"
      ],
      "type": "object",
      "additionalProperties": false
    },
    "PROJECT_CATEGORY": {
      "type": "string",
      "enum": [
        "newBuilding",
        "modification",
        "rehabilitation",
        "renovation",
        "masterAgreement",
        "other",
        "maintenance"
      ],
      "nullable": false
    },
    "PROJECT_COST_CATALOG_TYPE": {
      "type": "string",
      "enum": [
        "custom",
        "din276",
        "oenorm",
        "stlbWorkCategory"
      ],
      "nullable": false
    },
    "PROJECT_STATUS": {
      "type": "string",
      "enum": [
        "draft",
        "published",
        "completed",
        "closed"
      ],
      "nullable": false
    },
    "ProjectCostGroupCatalog": {
      "properties": {
        "catalogType": {
          "$ref": "#/$defs/PROJECT_COST_CATALOG_TYPE",
          "description": "Type of cost group catalog used on the project."
        },
        "customCatalogId": {
          "type": [
            "string",
            "null"
          ],
          "description": "ID of the custom cost catalog. Required when `catalogType` is `custom`; ignored otherwise."
        }
      },
      "required": [
        "catalogType"
      ],
      "type": "object",
      "additionalProperties": false
    },
    "ProjectUserResponse": {
      "properties": {
        "userRole": {
          "type": "string",
          "description": "Role of the user on the project (e.g. project manager, team member). Accepted values depend on your company's configuration."
        },
        "isContactPerson": {
          "type": "boolean",
          "description": "Whether this user is designated as a contact person for subcontractors on the project."
        },
        "user": {
          "$ref": "#/$defs/UserResponse",
          "description": "The user assigned to the project."
        }
      },
      "required": [
        "userRole",
        "isContactPerson",
        "user"
      ],
      "type": "object",
      "additionalProperties": false
    },
    "USER_STATUS": {
      "type": "string",
      "enum": [
        "approvalPending",
        "adminApprovalPending",
        "invited",
        "inviteCanceled",
        "inviteFailed",
        "inviteRequested",
        "active",
        "inactive"
      ],
      "nullable": false
    },
    "USER_TYPE": {
      "type": "string",
      "enum": [
        "custom",
        "administrator",
        "employee",
        "guest",
        "collaborator",
        "manager"
      ],
      "nullable": false
    },
    "UserResponse": {
      "properties": {
        "id": {
          "type": "string",
          "description": "ID of the user."
        },
        "email": {
          "type": "string",
          "description": "Email address of the user. Also used as their login identifier."
        },
        "status": {
          "$ref": "#/$defs/USER_STATUS",
          "description": "Current status of the user."
        },
        "firstName": {
          "type": "string",
          "description": "Given name of the user."
        },
        "lastName": {
          "type": "string",
          "description": "Family name of the user."
        },
        "type": {
          "$ref": "#/$defs/USER_TYPE",
          "description": "Account type of the user. Values starting with `custom` indicate a custom user role (see `customUserRoleId`)."
        },
        "customUserRoleId": {
          "type": "string",
          "description": "ID of the custom user role assigned to the user. Present only when `type` refers to a custom user role."
        }
      },
      "required": [
        "id",
        "email",
        "status",
        "type"
      ],
      "type": "object",
      "additionalProperties": false
    }
  }
}