---
title: "Expire a job"
method: POST
path: "/jobs/{id}/expire"
tags: ["Jobs"]
---

# Expire a job

`POST /jobs/{id}/expire`

## Request

- Base URL: `https://api.cavuno.com/v1`
- URL: `https://api.cavuno.com/v1/jobs/{id}/expire`
- Auth: HTTP bearer

Marks a published job as expired. The `status` is set to `expired` and `expiresAt` is set to the current time. Expired jobs are removed from the public board and can be reopened by publishing them again.

## Path parameters

- `id` string, required: The job's opaque object `id`: the `id` field returned by the job endpoints (e.g. `j8k2q7d4b9r3m6x0p5t1v7w2y9z4c8n3`). This is NOT the `slug` or title; passing a slug like `senior-backend-engineer` returns 404. To look up a job by title or slug, use `GET /v1/jobs` or `POST /v1/jobs/search` and read the returned `id`.

## Response `200`

Successful response.

- Job
  - `id` string, required: Unique identifier for the object. Use this value as the `{id}` path parameter for the job endpoints (e.g. `GET /v1/jobs/{id}`).
  - `object` 'job', required: String representing the object's type. Objects of the same type share the same value.
  - `title` string, required: The job title.
  - `slug` string, nullable, required: URL-friendly slug used in public board URLs, or `null` if no slug is set.
  - `status` 'draft' | 'published' | 'expired' | 'archived' | 'pending_approval', required: 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` string, nullable, required: Identifier of the company the job belongs to, or `null` if no company is attached.
  - `employmentType` 'full_time' | 'part_time' | 'contract' | 'internship' | 'temporary' | 'volunteer' | 'other', nullable, required: 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` object, nullable, required: 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`.
    - `key` string, required: Stable key of the custom employment type. Never changes.
    - `label` string, required: Display name of the custom employment type, as configured.
  - `remoteOption` 'on_site' | 'hybrid' | 'remote', nullable, required: 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` 'entry_level' | 'associate' | 'mid_level' | 'senior' | 'lead' | 'principal' | 'director' | 'executive', nullable, required: Seniority level of the role, or `null` if not specified.
  - `salaryMin` number, nullable, required: Minimum salary in `salaryCurrency` units, or `null` if not specified.
  - `salaryMax` number, nullable, required: Maximum salary in `salaryCurrency` units, or `null` if not specified.
  - `salaryCurrency` string, nullable, required: Three-letter ISO 4217 currency code for the salary range, or `null` if no salary is specified.
  - `salaryTimeframe` 'per_year' | 'per_month' | 'per_week' | 'per_day' | 'per_hour', nullable, required: Period the salary range is quoted against, or `null` if no salary is specified.
  - `isFeatured` boolean, required: Whether the job appears in featured slots on the public board.
  - `publishedAt` string, nullable, required: Time at which the job was first published, or `null` if not yet published. ISO 8601 datetime.
  - `expiresAt` string, nullable, required: 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` string, required: Time at which the job was created. ISO 8601 datetime.
  - `updatedAt` string, required: Time at which the job was last updated. ISO 8601 datetime.
  - `revision` integer, required: Monotonic Job lifecycle revision used to reconcile webhook events. Legacy rows are 0 until the rollout backfill runs.
  - `skills` string[], required: Canonical skill slugs assigned to the job.
  - `categories` string[], required: Canonical category slugs assigned to the job.
  - `externalId` string, nullable, required: External identifier supplied by the caller on create, used for deduplication via `GET /v1/jobs?externalId=...`. `null` when no external identifier was set.
  - `customFieldValues` object, required: 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` object, required: Operator-facing collection record IDs keyed by job collection field. Always an object; values are arrays even for single-select fields.
  - `links` object, required: Public + admin URLs for this job. `public` may be `null` if the job lacks a slug or company-slug.
    - `admin` string, uri, required: URL inside the Cavuno app where the authenticated owner can manage this resource.
    - `public` string, uri, nullable, required: Canonical public URL for this job, or `null` when the job has no slug or no associated company slug (so a stable URL cannot be assembled).
  - `resolvedCollectionFields` ResolvedJobCollectionField[], required: Collection selections resolved to current live names, logos, and public record details.
    - `key` string, required
    - `label` string, required
    - `entries` object[], required
      - `id` string, required
      - `name` string, required
      - `slug` string: URL-safe identifier, unique within the collection. Changing it keeps the previous value reserved.
      - `logoUrl` string: The entry's logo: the image in the collection's logo field, or a legacy logo URL on older entries. Absent when the entry has neither.
      - `title` string, required: The entry's title on this job: the job's `titleOverride` when set, otherwise the entry name. Render this.
      - `description` string, nullable, required: The entry's description on this job: the job's `descriptionOverride` when set, otherwise the value of the field's default description field, or `null` when neither exists. Sanitised HTML when the default description field is rich text, with a plain-text override escaped into paragraphs. Render this.
      - `titleOverride` string, nullable, required: The title this job set for the entry, or `null` when it uses the entry name.
      - `descriptionOverride` string, nullable, required: The plain-text description this job set for the entry, or `null` when it uses the default description.
      - `fields` object[], required
        - `key` string, required
        - `label` string, required
        - `type` 'short_text' | 'long_text' | 'rich_text' | 'single_select' | 'multi_select' | 'boolean' | 'number' | 'date' | 'url' | 'email' | 'phone' | 'image' | 'image_gallery' | 'file' | 'reference', required
        - `helpText` string
        - `options` object[]
          - `key` string, required
          - `label` string, required
      - `values` object, required
      - `references` object
  - `description` string, nullable, required: Long-form description of the role (HTML), or `null` if not specified.
  - `applicationUrl` string, nullable, required: Where candidates apply, or `null` if not specified. An HTTPS URL or `mailto:` URI.
  - `remotePermits` object[], required: Hierarchical permit selection authored by the caller. Lossless round-trip with the input: `[{type:"world_region",value:"EMEA"}]` goes in and comes out the same. The three `remoteWorkPermit*` and `remoteWorldwide` fields below are read-only derived projections of this list.
    - `type` string, required
    - `value` string, required
  - `remoteWorldwide` boolean, nullable, required: Read-only: derived from `remotePermits`. `true` only when the authored selection is a single `{type:"worldwide"}` entry.
  - `remoteTimezones` object[], required: Hierarchical timezone selection. Lossless round-trip with the authored input. When omitted on POST, the server auto-derives this from `remotePermits` (or `[{all,all}]` if neither was provided). PATCH never auto-re-derives: once set, only an explicit replacement updates the stored value. The flat `remoteAllowedTzOffsets` field below is the read-only derived projection used by search.
    - `type` string, required
    - `value` string, required
    - `plusMinus` number
  - `remoteAllowedTzOffsets` number[], required: Read-only: derived from `remoteTimezones` (per-country/per-region offset fan-out). UTC hour offsets used by the job-search index.
  - `remoteWorkPermitCountryCodes` string[], required: Read-only: derived from `remotePermits` (hierarchical groups fan out to alpha2 sets; subdivisions auto-add the parent country). ISO 3166-1 alpha-2 codes.
  - `remoteWorkPermitSubdivisionCodes` string[], required: Read-only: derived from `remotePermits` (subdivision entries only). ISO 3166-2 codes.
  - `remoteSponsorship` 'yes' | 'no' | 'unknown', required: Whether the employer sponsors visas for remote candidates. One of `yes`, `no`, or `unknown`.
  - `educationRequirements` string[], required: Required education credentials. Each value is one of `high_school`, `associate_degree`, `bachelor_degree`, `professional_certificate`, `postgraduate_degree`, or `no_requirements`.
  - `experienceMonths` number, nullable, required: Minimum required experience in months, or `null` if not specified.
  - `experienceInPlaceOfEducation` boolean, nullable, required: If `true`, equivalent experience may substitute for the listed education requirements. `null` if not specified.
  - `inOfficePeriod` 'per_week' | 'per_month' | 'per_year', nullable, required: Period denominator for `inOfficeFrequency`, or `null` if not specified.
  - `inOfficeFrequency` number, nullable, required: How often the candidate must be in-office over `inOfficePeriod`, or `null` if not specified.
  - `company` JobCompany, nullable, required: Embedded company resource for the job, or `null` if no company is attached.
    - `id` string, required: Unique identifier for the company.
    - `name` string, nullable, required: Display name of the company, or `null` if not yet set.
    - `slug` string, nullable, required: URL slug of the company, or `null` if not yet set.
    - `logoUrl` string, nullable, required: URL of the company logo, or `null` if no logo is set.
    - `website` string, nullable, required: Company website URL, or `null` if no website is set.
  - `officeLocations` JobOfficeLocation[], required: Physical office locations associated with the job.
    - `countryCode` string, nullable, required: ISO 3166-1 alpha-2 country code, or `null` if the location was not resolved.
    - `country` string, nullable, required: Full country name, or `null` if the location was not resolved.
    - `locality` string, nullable, required: Neighborhood or sub-locality, or `null` if not resolved.
    - `city` string, nullable, required: City, or `null` if not resolved.
    - `region` string, nullable, required: Region, state, or province name, or `null` if not resolved.
    - `regionCode` string, nullable, required: Region or state code (e.g. `CA` for California), or `null` if not resolved.
    - `postalCode` string, nullable, required: Postal or ZIP code, or `null` if not resolved.
    - `displayName` string, nullable, required: Pre-formatted display name for the location, or `null` if not resolved.

## Other responses

- `404`: Job not found.
- `409`: The job is not currently published.

## Changes

- **2026-10-19** `c34152c38176`: 2 info
  - added the optional property `error/upgrade` to the response with the `404` status
  - added the optional property `error/upgrade` to the response with the `409` status

[Operation history](https://skmtc.dev/cavuno/apis/cavuno-v1-rest-api/changes/jobs/:id/expire/post.md)

---

[API](https://skmtc.dev/cavuno/apis/cavuno-v1-rest-api.md) · [All operations](https://skmtc.dev/cavuno/apis/cavuno-v1-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cavuno/apis/cavuno-v1-rest-api/revisions/d5974dabff14?raw)
