---
title: "Update an employer plan"
method: PATCH
path: "/plans/{id}"
tags: ["Plans"]
---

# Update an employer plan

`PATCH /plans/{id}`

## Request

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

Patch plan metadata. Archive with `isArchived: true`; publish/unpublish with `isPublic`. There is no hard DELETE.

## Path parameters

- `id` string, required: The plan ID returned by create or list endpoints.

## Request body

- UpdatePlanBody
  - `name` string
  - `description` string
  - `isPublic` boolean: Publish/unpublish the plan.
  - `isRecommended` boolean
  - `isArchived` boolean: Archive the plan (soft-delete). There is no hard DELETE.
  - `displayOrder` integer
  - `pricingMode` 'priced' | 'contact': How the plan is sold. `priced` takes a price and syncs it to Stripe; `contact` renders a contact CTA and creates no Stripe objects — setting a price on a contact plan is rejected. Omitted on create means `priced`.
  - `priceText` string: Display price text for a contact plan. Send an empty string to clear it.
  - `ctaText` string: CTA label for a contact plan. Empty string clears it.
  - `ctaDestination` string: CTA target for a contact plan. Must be an https, mailto:, or tel: URL. Empty string clears it.

## Response `200`

Updated plan.

- AdminPlan
  - `id` string, required: Unique identifier for the plan.
  - `object` 'plan', required
  - `name` string, required
  - `description` string, nullable, required
  - `kind` string, required
  - `billingInterval` 'day' | 'week' | 'month' | 'year', nullable, required: Subscription billing interval. Required for kind=subscription. Pair with billingIntervalCount for non-1 counts (quarterly = month × 3).
  - `billingIntervalCount` integer, nullable, required: Stripe recurring.interval_count. Null/omitted means 1. Quarterly is month × 3.
  - `purpose` 'job_posting' | 'talent_access' | 'membership' | 'job_seeker' | 'employer_service' | 'job_seeker_service', required: What the plan entitles: job-posting, talent-access, membership (employer membership), job-seeker (candidate paywall), or contact-led employer_service / job_seeker_service catalogue rows.
  - `isPublic` boolean, required
  - `isRecommended` boolean, required
  - `isArchived` boolean, required
  - `displayOrder` number, nullable, required
  - `pricingMode` 'priced' | 'contact', required: How the plan is sold. Plans created before this field existed report `priced`.
  - `priceText` string, nullable, required: Operator-authored display price text for a contact plan, e.g. "From $2,000". Null when unset.
  - `ctaText` string, nullable, required: Operator-authored CTA label for a contact plan.
  - `ctaDestination` string, nullable, required: The CTA target: an https, mailto:, or tel: URL. Null when unset, in which case no CTA is rendered.
  - `price` PlanPrice, nullable, required: The plan single active price, or null when no price has been set.
    - `currency` string, required: ISO 4217 currency code, lowercase.
    - `amountCents` integer, required: Unit amount in the smallest currency unit.
  - `features` PlanFeature[], required
    - `key` 'jobs.max_active' | 'jobs.included_posts' | 'jobs.duration_days' | 'jobs.featured_slots' | 'jobs.included_featured' | 'jobs.feature_selection_mode' | 'jobs.posting_discount_percent' | 'talent.profile_unlocks' | 'talent.messages_sent', required: Stable Cavuno plan capability key.
    - `name` string, nullable, required
    - `value` string, nullable, required

## Other responses

- `404`: Plan not found.

## Changes

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

[Operation history](https://skmtc.dev/cavuno/apis/cavuno-v1-rest-api/changes/plans/:id/patch.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)
