{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/cavuno-com/json-schema/cavuno-com-job-summary-schema.json",
  "title": "JobSummary",
  "x-generated": "2026-11-04",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/cavuno-com-openapi.json#/components/schemas/JobSummary",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Unique identifier for the object. Use this value as the `{id}` path parameter for the job endpoints (e.g. `GET /v1/jobs/{id}`)."
    },
    "object": {
      "type": "string",
      "enum": [
        "job"
      ],
      "description": "String representing the object's type. Objects of the same type share the same value."
    },
    "title": {
      "type": "string",
      "description": "The job title."
    },
    "slug": {
      "type": [
        "string",
        "null"
      ],
      "description": "URL-friendly slug used in public board URLs, or `null` if no slug is set."
    },
    "status": {
      "type": "string",
      "enum": [
        "draft",
        "published",
        "expired",
        "archived",
        "pending_approval"
      ],
      "description": "Current status of the job. One of `draft`, `published`, `expired`, `archived`, or `pending_approval`. A `pending_approval` job is waiting for an operator to approve it: approve with `POST /v1/jobs/:id/publish`, reject with `DELETE /v1/jobs/:id`. It is not public, like a draft."
    },
    "companyId": {
      "type": [
        "string",
        "null"
      ],
      "description": "Identifier of the company the job belongs to, or `null` if no company is attached."
    },
    "employmentType": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "full_time",
        "part_time",
        "contract",
        "internship",
        "temporary",
        "volunteer",
        "other"
      ],
      "description": "Employment type of the role, or `null` if not specified. For a job with a custom employment type, this is the Google equivalent of the custom type."
    },
    "customEmploymentType": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "key": {
          "type": "string",
          "description": "Stable key of the custom employment type. Never changes."
        },
        "label": {
          "type": "string",
          "description": "Display name of the custom employment type, as configured."
        }
      },
      "required": [
        "key",
        "label"
      ],
      "description": "The board's custom employment type for this job (for example `Casual`), or `null` when the job uses a built-in type only. A deleted custom type reads back as `null` and the job shows its built-in `employmentType`."
    },
    "remoteOption": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "on_site",
        "hybrid",
        "remote"
      ],
      "description": "Whether the role is on-site, hybrid, or fully remote. `null` only on older jobs saved without one; create requires it and `PATCH` cannot clear it."
    },
    "seniority": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "entry_level",
        "associate",
        "mid_level",
        "senior",
        "lead",
        "principal",
        "director",
        "executive"
      ],
      "description": "Seniority level of the role, or `null` if not specified."
    },
    "salaryMin": {
      "type": [
        "number",
        "null"
      ],
      "description": "Minimum salary in `salaryCurrency` units, or `null` if not specified."
    },
    "salaryMax": {
      "type": [
        "number",
        "null"
      ],
      "description": "Maximum salary in `salaryCurrency` units, or `null` if not specified."
    },
    "salaryCurrency": {
      "type": [
        "string",
        "null"
      ],
      "description": "Three-letter ISO 4217 currency code for the salary range, or `null` if no salary is specified."
    },
    "salaryTimeframe": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "per_year",
        "per_month",
        "per_week",
        "per_day",
        "per_hour"
      ],
      "description": "Period the salary range is quoted against, or `null` if no salary is specified."
    },
    "isFeatured": {
      "type": "boolean",
      "description": "Whether the job appears in featured slots on the public board."
    },
    "publishedAt": {
      "type": [
        "string",
        "null"
      ],
      "description": "Time at which the job was first published, or `null` if not yet published. ISO 8601 datetime."
    },
    "expiresAt": {
      "type": [
        "string",
        "null"
      ],
      "description": "Time at which the job expires as an ISO 8601 datetime. `null` can appear when the expiry requirement does not apply, including for drafts and sponsored jobs; ordinary published jobs always have an expiry."
    },
    "createdAt": {
      "type": "string",
      "description": "Time at which the job was created. ISO 8601 datetime."
    },
    "updatedAt": {
      "type": "string",
      "description": "Time at which the job was last updated. ISO 8601 datetime."
    },
    "revision": {
      "type": "integer",
      "minimum": 0,
      "description": "Monotonic Job lifecycle revision used to reconcile webhook events. Legacy rows are 0 until the rollout backfill runs."
    },
    "skills": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Canonical skill slugs assigned to the job."
    },
    "categories": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Canonical category slugs assigned to the job."
    },
    "externalId": {
      "type": [
        "string",
        "null"
      ],
      "description": "External identifier supplied by the caller on create, used for deduplication via `GET /v1/jobs?externalId=...`. `null` when no external identifier was set."
    },
    "customFieldValues": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "type": "string"
          },
          {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          {
            "type": "boolean"
          },
          {
            "type": "number"
          }
        ]
      },
      "description": "Board-defined custom-field values for this job, keyed by the field `key` (the definitions are published at `GET /v1/settings/job-form`). Each value is returned as stored: a string (`short_text` / `long_text` / a `single_select` option key), a string array (`multi_select` option keys), a boolean, or a number. Always an object: `{}` when the job has no custom-field values, never `null` or a missing field. Only real values are stored, so this never contains `null` or empty values."
    },
    "collectionValues": {
      "type": "object",
      "additionalProperties": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "maxItems": 100
      },
      "description": "Operator-facing collection record IDs keyed by job collection field. Always an object; values are arrays even for single-select fields. Fields whose collection is archived are omitted."
    },
    "proposedCompany": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of the proposed company."
        },
        "website": {
          "type": [
            "string",
            "null"
          ],
          "description": "Website URL of the proposed company, or `null` if the source gives none."
        }
      },
      "required": [
        "name",
        "website"
      ],
      "description": "Present only while the job has no company: the company the job's source names, which isn't on your board yet. Read-only. Publishing the job (`POST /jobs/{id}/publish`) adds this company to your board, or uses an existing company with the same website. To publish under a different company, set `companyId` first with `PATCH /jobs/{id}`. `null` when the job has a company."
    },
    "companyLocked": {
      "type": "boolean",
      "description": "`true` once an operator has changed the job's company (in the dashboard or with `companyId` on `PATCH /jobs/{id}`). A locked job keeps its company when the job's source refreshes or republishes it, even when the source names another company. Read-only."
    },
    "links": {
      "$ref": "#/$defs/AdminOnlyResourceLinks"
    }
  },
  "required": [
    "id",
    "object",
    "title",
    "slug",
    "status",
    "companyId",
    "employmentType",
    "customEmploymentType",
    "remoteOption",
    "seniority",
    "salaryMin",
    "salaryMax",
    "salaryCurrency",
    "salaryTimeframe",
    "isFeatured",
    "publishedAt",
    "expiresAt",
    "createdAt",
    "updatedAt",
    "revision",
    "skills",
    "categories",
    "externalId",
    "customFieldValues",
    "collectionValues",
    "proposedCompany",
    "companyLocked",
    "links"
  ],
  "$defs": {
    "AdminOnlyResourceLinks": {
      "type": "object",
      "properties": {
        "admin": {
          "type": "string",
          "format": "uri",
          "description": "URL inside the Cavuno app where the authenticated owner can manage this resource."
        }
      },
      "required": [
        "admin"
      ],
      "description": "Links related to this resource. List responses carry the operator URL; detail responses may also carry the public URL."
    }
  }
}