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 Blog authors 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: Blog authors
description: Create, list, update, and delete blog authors.
paths:
/blog/authors:
get:
summary: List blog authors
description: Returns a list of your blog authors. The authors are returned sorted by update date, with the most recently updated authors appearing first.
parameters:
- schema:
type: string
minLength: 1
description: An opaque pagination cursor returned in the `nextCursor` field of a previous response. Pass it back to fetch the next page of results.
required: false
description: An opaque pagination cursor returned in the `nextCursor` field of a previous response. Pass it back to fetch the next page of results.
name: cursor
in: query
- schema:
type: integer
minimum: 1
maximum: 100
description: A limit on the number of objects to be returned. Limit can range between 1 and 100.
required: false
description: A limit on the number of objects to be returned. Limit can range between 1 and 100.
example: 20
name: limit
in: query
responses:
'200':
description: Successful response.
content:
application/json:
schema:
type: object
properties:
object:
type: string
enum:
- list
url:
type: string
example: /v1/blog/authors
hasMore:
type: boolean
nextCursor:
type:
- string
- 'null'
data:
type: array
items:
$ref: '#/components/schemas/BlogAuthor'
required:
- object
- url
- hasMore
- nextCursor
- data
'400':
description: The request was malformed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Blog authors
operationId: listBlogAuthors
post:
summary: Create a blog author
description: Creates a new blog author. The request is idempotent when an `Idempotency-Key` header is supplied.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAuthorBody'
responses:
'201':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/BlogAuthor'
'400':
description: The request was malformed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Another author already uses the same slug.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Blog authors
operationId: createBlogAuthor
/blog/authors/{id}:
get:
summary: Retrieve a blog author
description: Retrieves the details of an existing blog author. You only need to supply the unique author ID that was returned upon author creation.
parameters:
- schema:
type: string
minLength: 1
description: 'The author''s opaque object `id`: the `id` field returned by the author endpoints (e.g. `a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7`). This is NOT the `slug` or name; passing a slug like `jane-doe` returns 404. To look up an author by name or slug, use `GET /v1/blog/authors` and read the returned `id`.'
required: true
description: 'The author''s opaque object `id`: the `id` field returned by the author endpoints (e.g. `a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7`). This is NOT the `slug` or name; passing a slug like `jane-doe` returns 404. To look up an author by name or slug, use `GET /v1/blog/authors` and read the returned `id`.'
example: a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7
name: id
in: path
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/BlogAuthor'
'404':
description: Author not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Blog authors
operationId: getBlogAuthor
patch:
summary: Update a blog author
description: Updates the specified blog author by setting the values of the parameters passed. Any parameters not provided will be left unchanged. The request is idempotent when an `Idempotency-Key` header is supplied.
parameters:
- schema:
type: string
minLength: 1
description: 'The author''s opaque object `id`: the `id` field returned by the author endpoints (e.g. `a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7`). This is NOT the `slug` or name; passing a slug like `jane-doe` returns 404. To look up an author by name or slug, use `GET /v1/blog/authors` and read the returned `id`.'
required: true
description: 'The author''s opaque object `id`: the `id` field returned by the author endpoints (e.g. `a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7`). This is NOT the `slug` or name; passing a slug like `jane-doe` returns 404. To look up an author by name or slug, use `GET /v1/blog/authors` and read the returned `id`.'
example: a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7
name: id
in: path
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateAuthorBody'
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/BlogAuthor'
'400':
description: The request was malformed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Author not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Another author already uses the same slug.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Blog authors
operationId: updateBlogAuthor
delete:
summary: Delete a blog author
description: Permanently deletes a blog author and schedules removal of its ID from every post `authorIds` array on the board (paginated drain). It cannot be undone.
parameters:
- schema:
type: string
minLength: 1
description: 'The author''s opaque object `id`: the `id` field returned by the author endpoints (e.g. `a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7`). This is NOT the `slug` or name; passing a slug like `jane-doe` returns 404. To look up an author by name or slug, use `GET /v1/blog/authors` and read the returned `id`.'
required: true
description: 'The author''s opaque object `id`: the `id` field returned by the author endpoints (e.g. `a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7`). This is NOT the `slug` or name; passing a slug like `jane-doe` returns 404. To look up an author by name or slug, use `GET /v1/blog/authors` and read the returned `id`.'
example: a4u7t9k2d6q0r3s8v1w5x9y2z6b0c4m7
name: id
in: path
responses:
'204':
description: Successful response.
'404':
description: Author not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Blog authors
operationId: deleteBlogAuthor
/blog/authors/export:
get:
summary: Export blog authors
description: Exports the account’s blog authors. `format=json` returns an inline list of export rows (max 10,000; fields mirror the CSV columns, camelCase). `format=csv` (default) returns `202` with an `exports.generate` operation — poll it, then download the CSV from `GET /v1/operations/{id}/download` once it succeeds. Requires `blog.read`.
parameters:
- schema:
type: string
enum:
- csv
- json
default: csv
description: Export format. `json` streams an inline list of blog author export rows (capped at 10,000 rows); `csv` (default) starts an async `exports.generate` operation.
required: false
description: Export format. `json` streams an inline list of blog author export rows (capped at 10,000 rows); `csv` (default) starts an async `exports.generate` operation.
name: format
in: query
responses:
'200':
description: Inline JSON export (`format=json`).
content:
application/json:
schema:
type: object
properties:
object:
type: string
enum:
- list
url:
type: string
example: /v1/blog/authors/export
hasMore:
type: boolean
nextCursor:
type:
- string
- 'null'
data:
type: array
items:
$ref: '#/components/schemas/ExportRow'
required:
- object
- url
- hasMore
- nextCursor
- data
'202':
description: An `exports.generate` operation was started (`format=csv`). Poll the operation; once it succeeds, download the CSV from `GET /v1/operations/{id}/download`.
content:
application/json:
schema:
$ref: '#/components/schemas/OperationResource'
default:
description: An error. Every non-2xx response uses the same envelope; see the Errors section of the introduction.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Blog authors
operationId: exportBlogAuthors
components:
schemas:
OperationErrorEnvelope:
type:
- object
- 'null'
properties:
code:
type: string
description: Machine-readable error code.
message:
type: string
description: Human-readable error message.
required:
- code
- message
description: Error envelope, populated once the operation reaches `failed`. `null` otherwise.
CreateAuthorBody:
type: object
properties:
slug:
type: string
minLength: 1
maxLength: 120
pattern: ^[a-z0-9-]+$
description: URL-friendly slug for the author. Auto-generated from `name` when omitted.
bio:
type: string
maxLength: 4000
description: Short biography for the author. Sanitized HTML.
email:
type: string
maxLength: 320
format: email
description: The author's email address.
location:
type: string
maxLength: 200
description: Free-text location label for the author (e.g. `Sydney, Australia`).
status:
type: string
enum:
- active
- inactive
description: Author visibility status. One of `active` or `inactive`.
avatarMediaId:
type:
- string
- 'null'
description: Cavuno media ID of an uploaded avatar image. Pass `null` to clear it.
websiteUrl:
type: string
maxLength: 500
description: The author's personal website URL. Normalized to a canonical URL when stored.
facebookUrl:
type: string
maxLength: 500
description: The author's Facebook profile URL.
twitterUrl:
type: string
maxLength: 500
description: The author's X (Twitter) profile URL. Stored as the canonical `https://x.com/<handle>` URL.
linkedinUrl:
type: string
maxLength: 500
description: The author's LinkedIn profile URL.
githubUrl:
type: string
maxLength: 500
description: The author's GitHub profile URL.
metaTitle:
type: string
maxLength: 150
description: SEO meta title for the author page.
metaDescription:
type: string
maxLength: 320
description: SEO meta description for the author page.
name:
type: string
minLength: 1
maxLength: 200
description: The author's display name.
required:
- name
additionalProperties: false
UpdateAuthorBody:
type: object
properties:
slug:
type: string
minLength: 1
maxLength: 120
pattern: ^[a-z0-9-]+$
description: URL-friendly slug for the author. Auto-generated from `name` when omitted.
bio:
type: string
maxLength: 4000
description: Short biography for the author. Sanitized HTML.
email:
type:
- string
- 'null'
maxLength: 320
format: email
description: The author's email address. Pass `null` to clear the stored value; omitted means unchanged.
location:
type: string
maxLength: 200
description: Free-text location label for the author (e.g. `Sydney, Australia`).
status:
type: string
enum:
- active
- inactive
description: Author visibility status. One of `active` or `inactive`.
avatarMediaId:
type:
- string
- 'null'
description: Cavuno media ID of an uploaded avatar image. Pass `null` to clear it.
websiteUrl:
type:
- string
- 'null'
maxLength: 500
description: The author's personal website URL. Normalized to a canonical URL when stored. Pass `null` or `""` to clear the stored value; omitted means unchanged.
facebookUrl:
type:
- string
- 'null'
maxLength: 500
description: The author's Facebook profile URL. Pass `null` or `""` to clear the stored value; omitted means unchanged.
twitterUrl:
type:
- string
- 'null'
maxLength: 500
description: The author's X (Twitter) profile URL. Stored as the canonical `https://x.com/<handle>` URL. Pass `null` or `""` to clear the stored value; omitted means unchanged.
linkedinUrl:
type:
- string
- 'null'
maxLength: 500
description: The author's LinkedIn profile URL. Pass `null` or `""` to clear the stored value; omitted means unchanged.
githubUrl:
type:
- string
- 'null'
maxLength: 500
description: The author's GitHub profile URL. Pass `null` or `""` to clear the stored value; omitted means unchanged.
metaTitle:
type: string
maxLength: 150
description: SEO meta title for the author page.
metaDescription:
type: string
maxLength: 320
description: SEO meta description for the author page.
name:
type: string
minLength: 1
maxLength: 200
description: The author's display name.
additionalProperties: false
ExportRow:
type: object
properties:
id:
type: string
description: Stable identifier for the exported row.
required:
- id
additionalProperties: {}
description: A single export row. Fields mirror the entity’s CSV columns (camelCase); array fields are JSON arrays and timestamps are epoch-millisecond UTC numbers.
BlogAuthor:
type: object
properties:
id:
type: string
description: Unique identifier for the object. Use this value as the `{id}` path parameter for the author endpoints (e.g. `GET /v1/blog/authors/{id}`).
object:
type: string
enum:
- blog_author
description: String representing the object's type. Objects of the same type share the same value.
name:
type: string
description: Display name of the author.
slug:
type: string
description: URL-friendly slug for the author.
bio:
type:
- string
- 'null'
description: Short biography, or `null` if not set.
email:
type:
- string
- 'null'
description: The author's email address, or `null` if not set.
location:
type:
- string
- 'null'
description: The author's free-text location label, or `null` if not set.
status:
type:
- string
- 'null'
description: Author visibility status, or `null` if not set.
avatarUrl:
type:
- string
- 'null'
description: URL of the author avatar, or `null` if no avatar is set.
websiteUrl:
type:
- string
- 'null'
description: The author's website URL, or `null` if not set.
facebookUrl:
type:
- string
- 'null'
description: The author's Facebook URL, or `null` if not set.
twitterUrl:
type:
- string
- 'null'
description: The author's X (Twitter) URL, or `null` if not set.
linkedinUrl:
type:
- string
- 'null'
description: The author's LinkedIn URL, or `null` if not set.
githubUrl:
type:
- string
- 'null'
description: The author's GitHub URL, or `null` if not set.
metaTitle:
type:
- string
- 'null'
description: SEO meta title, or `null` if not set.
metaDescription:
type:
- string
- 'null'
description: SEO meta description, or `null` if not set.
createdAt:
type: string
description: Time at which the author was created. ISO 8601 datetime.
updatedAt:
type:
- string
- 'null'
description: Time at which the author was last updated, or `null` if it has never been updated. ISO 8601 datetime.
required:
- id
- object
- name
- slug
- bio
- email
- location
- status
- avatarUrl
- websiteUrl
- facebookUrl
- twitterUrl
- linkedinUrl
- githubUrl
- metaTitle
- metaDescription
- createdAt
- updatedAt
OperationProgress:
type:
- object
- 'null'
properties:
percent:
type: number
description: Progress as a percentage between 0 and 100, when the operation reports a percentage.
message:
type: string
description: Human-readable progress message, when available.
processed:
type: number
description: Number of items processed so far, when applicable.
total:
type: number
description: Total number of items to process, when known.
description: Snapshot of the operation's progress, or `null` if the operation does not report progress.
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.'
OperationResource:
type: object
properties:
id:
type: string
description: Unique identifier for the object.
object:
type: string
enum:
- operation
description: String representing the object's type. Objects of the same type share the same value.
kind:
type: string
enum:
- domains.verify
- imports.parse
- imports.confirm
- subscribers.export
- subscribers.import
- custom_objects.records_import
- exports.generate
- candidates.remove
- employers.remove
description: Operation kind, identifying which workflow the operation runs.
state:
type: string
enum:
- pending
- running
- succeeded
- failed
- cancelled
description: Current state of the operation.
progress:
$ref: '#/components/schemas/OperationProgress'
result:
type:
- object
- 'null'
properties:
totalRows:
type: number
created:
type: number
updated:
type: number
failed:
type: number
errors:
type: array
items:
type: object
properties:
rowIndex:
type: number
code:
type: string
message:
type: string
required:
- rowIndex
- code
- message
required:
- totalRows
- created
- updated
- failed
- errors
description: A safe workflow result summary when the operation kind publishes one.
error:
$ref: '#/components/schemas/OperationErrorEnvelope'
createdAt:
type: string
description: Time at which the operation was created. ISO 8601 datetime.
updatedAt:
type: string
description: Time at which the operation was last updated. ISO 8601 datetime.
completedAt:
type:
- string
- 'null'
description: Time at which the operation reached a terminal state, or `null` if it has not yet completed. ISO 8601 datetime.
cancelRequested:
type: boolean
description: Whether cancellation of the operation has been requested.
resource:
type:
- object
- 'null'
properties:
object:
type: string
enum:
- company
- domain
- import
- employer
- candidate
- custom_object_type
id:
type: string
required:
- object
- id
description: Stable product resource affected by the operation, or `null` when no public resource applies.
required:
- id
- object
- kind
- state
- progress
- error
- createdAt
- updatedAt
- completedAt
- cancelRequested
- resource
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