Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Cavuno v1 REST Page content API
version: 1.0.0
description: 'The Cavuno API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs. ## Base URL
Production: `https://api.cavuno.com/v1`
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. ## Authentication
The Cavuno API uses API keys to authenticate requests. You can view and manage your API keys in the Cavuno dashboard, under Settings → Developer → API keys. Cavuno API keys have the prefix `cavuno_live_`. Your API keys carry many privileges, so be sure to keep them secure. Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth. Authentication to the API is performed via Bearer auth. Provide your API key as the bearer token in the `Authorization` header:
```bash
curl https://api.cavuno.com/v1/jobs \
-H "Authorization: Bearer YOUR_SECRET_API_KEY"
```
API requests without authentication will fail. ## Rate limits
The Cavuno API has rate limits in place to ensure stability and reliability. By default, API keys are limited to 100 requests per minute. If you exceed your limit, requests return an HTTP 429 response with a `Retry-After` header indicating when you can try again. If you have a use case that needs a higher limit, contact support. ## Idempotency
The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. For example, if a request to create a job fails due to a network connection error, you can safely retry the request with the same idempotency key, and we''ll guarantee that only one job is created. To perform an idempotent request, provide an additional `Idempotency-Key` header on any `POST`, `PATCH`, or `DELETE` request:
```bash
curl https://api.cavuno.com/v1/jobs \
-X POST \
-H "Authorization: Bearer cavuno_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d ''{ "title": "Senior Engineer" }''
```
## Errors
Cavuno uses conventional HTTP response codes to indicate the success or failure of an API request. In general: codes in the `2xx` range indicate success, codes in the `4xx` range indicate an error that failed given the information provided (e.g., a required parameter was omitted), and codes in the `5xx` range indicate an error with Cavuno''s servers (these are rare). Error responses include a JSON body with details:
```json
{
"error": {
"code": "validation_bad_request",
"message": "Field ''title'' is required.",
"requestId": "req_..."
}
}
```
Some errors carry an additional `details` field with structured context, such as per-field validation issues. ### Plan upgrade hints
When an Operator API request is refused because of the board''s Cavuno plan, the error also carries an `upgrade` object. It names the capability that blocked the request, the cheapest self-serve plan that unlocks it (when that can be told), and the hosted billing endpoints that start the upgrade:
```json
{
"error": {
"code": "settings_plan_required_for_branding_removal",
"message": "Removing Cavuno branding requires a plan that includes branding removal.",
"requestId": "req_...",
"upgrade": {
"capability": "canRemoveBranding",
"requiredPlan": "basic",
"checkout": { "method": "POST", "path": "/v1/billing/checkout" },
"changePlan": { "method": "POST", "path": "/v1/billing/upgrade" }
}
}
}
```
Call `GET /v1/billing/subscription` first. With no active subscription, use `checkout`; with one, use `changePlan`. Send `{ "planKey": "" }` and give the returned `url` to a person: both endpoints return a hosted page where a person confirms the purchase. Nothing is charged until they do. Each `path` is relative to the API origin (`https://api.cavuno.com`), like `Location` headers and list `url` fields, so do not join it to a base URL that already ends in `/v1`.'
contact:
name: Cavuno
url: https://cavuno.com
servers:
- url: https://api.cavuno.com/v1
description: Production
security:
- bearerAuth: []
tags:
- name: Page Content
description: 'Intro copy on category and location pages: retrieve, set, and delete.'
paths:
/page-content:
get:
summary: Retrieve a page intro
description: Returns the intro and meta overrides written for one category or location page, with their placeholders filled, and as written in the `*Template` fields. Address the page with exactly one of `category` or `place`. An unknown slug is a 404.
parameters:
- schema:
type: string
minLength: 1
maxLength: 200
description: 'Slug of the category page: its slug, an alias, or its board-language slug.'
required: false
description: 'Slug of the category page: its slug, an alias, or its board-language slug.'
name: category
in: query
- schema:
type: string
minLength: 1
maxLength: 200
description: 'Slug of the location page: the place''s `slug`, `canonicalSlug` or a merged-away alias.'
required: false
description: 'Slug of the location page: the place''s `slug`, `canonicalSlug` or a merged-away alias.'
name: place
in: query
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/PageContent'
'404':
description: Unknown page, or the page has no intro and no meta overrides.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Page Content
operationId: getPageContent
put:
summary: Set a page intro
description: 'Sets the intro and meta overrides of one category or location page as a merge patch: omitted fields keep their value, `null` clears one, and the last write wins. The page shows them on page 1 with no filters, and the board''s public category and place resolutions return them as `introHtml`, `metaTitle` and `metaDescription`. Address the page with exactly one of `category` or `place`. An unknown slug is a 404.'
parameters:
- schema:
type: string
minLength: 1
maxLength: 200
description: 'Slug of the category page: its slug, an alias, or its board-language slug.'
required: false
description: 'Slug of the category page: its slug, an alias, or its board-language slug.'
name: category
in: query
- schema:
type: string
minLength: 1
maxLength: 200
description: 'Slug of the location page: the place''s `slug`, `canonicalSlug` or a merged-away alias.'
required: false
description: 'Slug of the location page: the place''s `slug`, `canonicalSlug` or a merged-away alias.'
name: place
in: query
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PutPageContentBody'
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/PageContent'
'404':
description: Unknown page.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Page Content
operationId: updatePageContent
delete:
summary: Delete a page intro
description: Removes the intro and meta overrides of one category or location page. Address the page with exactly one of `category` or `place`. An unknown slug is a 404.
parameters:
- schema:
type: string
minLength: 1
maxLength: 200
description: 'Slug of the category page: its slug, an alias, or its board-language slug.'
required: false
description: 'Slug of the category page: its slug, an alias, or its board-language slug.'
name: category
in: query
- schema:
type: string
minLength: 1
maxLength: 200
description: 'Slug of the location page: the place''s `slug`, `canonicalSlug` or a merged-away alias.'
required: false
description: 'Slug of the location page: the place''s `slug`, `canonicalSlug` or a merged-away alias.'
name: place
in: query
responses:
'204':
description: Deleted, or the page had no intro.
'404':
description: Unknown page.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Page Content
operationId: deletePageContent
components:
schemas:
PutPageContentBody:
type: object
properties:
intro:
type:
- string
- 'null'
minLength: 1
maxLength: 4000
description: Markdown shown with the job list on page 1 of the page. Served as sanitized HTML. May use the placeholders `{{category}}` (category pages) or `{{location}}` (location pages), `{{board_name}}`, `{{count}}`, `{{job_label}}`, `{{salary_range}}` and `{{salary_count}}`, filled with the page's live values when read; a sentence whose placeholder has no value, or does not apply to the page, is left out. Omit to keep the current intro; `null` clears it.
metaTitle:
type:
- string
- 'null'
minLength: 1
maxLength: 150
description: The page's `<title>`, used in place of the board's title template. May use the placeholders `{{category}}` (category pages) or `{{location}}` (location pages), `{{board_name}}`, `{{count}}`, `{{job_label}}`, `{{salary_range}}` and `{{salary_count}}`, filled with the page's live values when read; a sentence whose placeholder has no value, or does not apply to the page, is left out. Omit to keep; `null` clears it and the template applies again.
metaDescription:
type:
- string
- 'null'
minLength: 1
maxLength: 320
description: The page's meta description, used in place of the board's description template. May use the placeholders `{{category}}` (category pages) or `{{location}}` (location pages), `{{board_name}}`, `{{count}}`, `{{job_label}}`, `{{salary_range}}` and `{{salary_count}}`, filled with the page's live values when read; a sentence whose placeholder has no value, or does not apply to the page, is left out. Omit to keep; `null` clears it.
source:
type: string
enum:
- human
- llm
default: human
description: '`llm` marks an AI draft a person approved. Defaults to `human`.'
additionalProperties: false
PlanUpgradeHint:
type: object
properties:
capability:
type: string
enum:
- activeJobsLimit
- teamSeatLimit
- canBePublic
- canRemoveBranding
- apiAccess
description: The plan capability that blocked the request, named as in `GET /v1/billing/subscription` `capabilities`.
requiredPlan:
type: string
enum:
- starter
- basic
- grow
- advanced
- scale
description: The cheapest self-serve plan that unlocks the action. Pass it as `planKey`. Omitted when it cannot be told without more information; read `GET /v1/billing/subscription` and pick a higher plan.
checkout:
type: object
properties:
method:
type: string
enum:
- POST
path:
type: string
enum:
- /v1/billing/checkout
required:
- method
- path
description: Starts a hosted checkout when the board has no active subscription (for example during a trial).
changePlan:
type: object
properties:
method:
type: string
enum:
- POST
path:
type: string
enum:
- /v1/billing/upgrade
required:
- method
- path
description: Starts a hosted plan change when the board already has an active subscription.
required:
- capability
- checkout
- changePlan
description: 'Present only on Operator API errors caused by the board''s Cavuno plan. Read `GET /v1/billing/subscription` to choose between `checkout` and `changePlan`, call it with `{ "planKey": requiredPlan }`, and give the returned `url` to a person to confirm. Each `path` is relative to the API origin, not to a `/v1` base URL. Both endpoints need `billing.manage`. Board API errors never include it.'
PageContent:
type: object
properties:
object:
type: string
enum:
- page_content
category:
type:
- string
- 'null'
description: The category slug the page was addressed by.
place:
type:
- string
- 'null'
description: The place slug the page was addressed by.
intro:
type: string
description: The intro markdown with its placeholders filled; an empty string when the page has none.
metaTitle:
type:
- string
- 'null'
description: The title override with its placeholders filled; `null` when the board template applies.
metaDescription:
type:
- string
- 'null'
description: The meta description override with its placeholders filled; `null` when the board template applies.
introTemplate:
type: string
description: The intro markdown as written, placeholders included. Send this back in `intro` to keep them.
metaTitleTemplate:
type:
- string
- 'null'
description: The title override as written, placeholders included.
metaDescriptionTemplate:
type:
- string
- 'null'
description: The meta description override as written, placeholders included.
source:
type: string
enum:
- human
- llm
updatedAt:
type: string
required:
- object
- category
- place
- intro
- metaTitle
- metaDescription
- introTemplate
- metaTitleTemplate
- metaDescriptionTemplate
- source
- updatedAt
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Machine-readable error code, such as `validation_bad_request` or `jobs_not_found`.
message:
type: string
description: Human-readable explanation.
requestId:
type: string
description: Unique id for this request. Include it when contacting support.
details:
description: Structured context for some errors, such as per-field validation issues.
upgrade:
$ref: '#/components/schemas/PlanUpgradeHint'
required:
- code
- message
- requestId
required:
- error
description: The error envelope returned by every non-2xx response.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: cavuno_live_<keyId>_<secret>
description: Use your secret API key to authenticate. Pass it as a Bearer token in the `Authorization` header. You can view and manage your API keys in the Cavuno dashboard.
externalDocs:
description: Cavuno API reference
url: https://cavuno.com/docs/api