Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/cavuno-com:cavuno-com-skills-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Cavuno v1 REST Skills 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: Skills
description: Create, list, update, and delete job skills, and manage their aliases.
paths:
/taxonomies/skills:
get:
summary: List skills
description: List taxonomy skills for the authenticated account.
parameters:
- schema:
type: string
minLength: 1
required: false
name: cursor
in: query
- schema:
type: integer
minimum: 1
maximum: 100
required: false
name: limit
in: query
- schema:
type: string
minLength: 1
maxLength: 200
description: Full-text search over the taxonomy name (matches name tokens, not slug).
required: false
description: Full-text search over the taxonomy name (matches name tokens, not slug).
name: search
in: query
responses:
'200':
description: Successful response.
content:
application/json:
schema:
type: object
properties:
object:
type: string
enum:
- list
url:
type: string
example: /v1/taxonomies/skills
hasMore:
type: boolean
nextCursor:
type:
- string
- 'null'
data:
type: array
items:
$ref: '#/components/schemas/Skill'
required:
- object
- url
- hasMore
- nextCursor
- data
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:
- Skills
operationId: listTaxonomiesSkills
post:
summary: Create a skill
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSkillBody'
responses:
'201':
description: Created.
content:
application/json:
schema:
$ref: '#/components/schemas/Skill'
'409':
description: Slug taken.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: createTaxonomiesSkill
/taxonomies/skills/{id}:
get:
summary: Retrieve a skill
parameters:
- schema:
type: string
minLength: 1
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
required: true
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
name: id
in: path
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/Skill'
'404':
description: Not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: getTaxonomiesSkill
patch:
summary: Update a skill
description: Partial update. Changing slug auto-adds the previous slug to aliasSlugs and taxonomyAliases and cascades denormalized job data.
parameters:
- schema:
type: string
minLength: 1
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
required: true
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
name: id
in: path
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateSkillBody'
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/Skill'
'404':
description: Not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Slug taken.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: updateTaxonomiesSkill
delete:
summary: Delete a skill
description: Deletes the skill. Jobs may retain stale skill slugs (by design).
parameters:
- schema:
type: string
minLength: 1
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
required: true
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
name: id
in: path
responses:
'204':
description: Deleted.
'404':
description: Not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: deleteTaxonomiesSkill
/taxonomies/skills/{id}/aliases:
post:
summary: Add skill aliases
description: Dual-writes aliasSlugs and taxonomyAliases. Max 20 aliases per request.
parameters:
- schema:
type: string
minLength: 1
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
required: true
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
name: id
in: path
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddSkillAliasesBody'
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/Skill'
'409':
description: Alias taken.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: createTaxonomiesSkillAlias
/taxonomies/skills/{id}/aliases/{alias}:
get:
summary: Retrieve a skill alias
description: Checks that `alias` is an alias of the skill and returns the skill, in the same shape as the add aliases response. The alias is normalized to a slug before matching, as it is when you remove one.
parameters:
- schema:
type: string
minLength: 1
required: true
name: id
in: path
- schema:
type: string
minLength: 1
required: true
name: alias
in: path
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/Skill'
'404':
description: Skill or alias not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: getTaxonomiesSkillAlias
delete:
summary: Remove a skill alias
parameters:
- schema:
type: string
minLength: 1
required: true
name: id
in: path
- schema:
type: string
minLength: 1
required: true
name: alias
in: path
responses:
'204':
description: Removed.
'404':
description: Skill or alias not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: deleteTaxonomiesSkillAlias
/taxonomies/skills/{id}/merge-preview:
get:
summary: Preview a skill merge
description: Counts what merging this skill into `intoId` would change. Writes nothing.
parameters:
- schema:
type: string
minLength: 1
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
required: true
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
name: id
in: path
- schema:
type: string
minLength: 1
description: The id of the term that would survive the merge.
required: true
description: The id of the term that would survive the merge.
name: intoId
in: query
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/TaxonomyMergePreview'
'400':
description: The two terms cannot be merged.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: previewTaxonomiesSkillMerge
/taxonomies/skills/{id}/merge:
post:
summary: Merge a skill
description: 'Merges this skill into `intoId`: its jobs, aliases and translations move to the surviving skill, and this skill is deleted. Jobs are retagged in the background. Undo is available for 30 days once `undo.status` is `ready`.'
parameters:
- schema:
type: string
minLength: 1
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
required: true
description: The skill's opaque object id (not the slug). Use list/create responses to obtain it.
name: id
in: path
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MergeTaxonomyBody'
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/TaxonomyMerge'
'400':
description: The two terms cannot be merged.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The merge conflicted with another change.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: mergeTaxonomiesSkill
/taxonomies/skills/merges/{mergeId}/undo:
post:
summary: Undo a skill merge
description: Recreates the merged skill with its slug, name, aliases and translations, and retags the jobs the merge retagged. Available for 30 days, unless the surviving skill has since been renamed, deleted or merged with another.
parameters:
- schema:
type: string
minLength: 1
description: The merge id returned by the merge endpoint.
required: true
description: The merge id returned by the merge endpoint.
name: mergeId
in: path
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/TaxonomyMerge'
'404':
description: Not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The merge can no longer be undone.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Skills
operationId: undoTaxonomiesSkillMerge
components:
schemas:
TaxonomyMerge:
type: object
properties:
id:
type: string
object:
type: string
enum:
- taxonomy_merge
kind:
type: string
enum:
- category
- skill
from:
type: object
properties:
id:
type: string
name:
type: string
slug:
type: string
required:
- id
- name
- slug
description: The term merged away. Its id no longer exists after the merge.
into:
type: object
properties:
id:
type: string
name:
type: string
slug:
type: string
required:
- id
- name
- slug
description: The term that survived.
undo:
type: object
properties:
status:
type: string
enum:
- applying
- ready
- over_cap
- undoing
- undone
- expired
description: '`applying` while jobs are being retagged; `ready` once undo is available; `over_cap` when the merge retagged too many jobs to undo; `undoing` / `undone` after an undo; `expired` after 30 days.'
expiresAt:
type: string
description: When undo stops being available.
restoredId:
type:
- string
- 'null'
description: After an undo, the id of the recreated term.
required:
- status
- expiresAt
- restoredId
createdAt:
type: string
required:
- id
- object
- kind
- from
- into
- undo
- createdAt
AddSkillAliasesBody:
type: object
properties:
aliases:
type: array
items:
type: string
minLength: 1
minItems: 1
maxItems: 20
required:
- aliases
additionalProperties: false
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.
UpdateSkillBody:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 200
slug:
type: string
minLength: 1
maxLength: 120
pattern: ^[a-z0-9-]+$
sourceLocale:
type: string
minLength: 2
maxLength: 16
additionalProperties: false
CreateSkillBody:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 200
slug:
type: string
minLength: 1
maxLength: 120
pattern: ^[a-z0-9-]+$
aliasSlugs:
type: array
items:
type: string
minLength: 1
maxItems: 20
sourceLocale:
type: string
minLength: 2
maxLength: 16
required:
- name
additionalProperties: false
Skill:
type: object
properties:
id:
type: string
object:
type: string
enum:
- skill
name:
type: string
slug:
type: string
aliasSlugs:
type: array
items:
type: string
sourceLocale:
type:
- string
- 'null'
createdAt:
type: string
required:
- id
- object
- name
- slug
- aliasSlugs
- sourceLocale
- createdAt
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.'
TaxonomyMergePreview:
type: object
properties:
object:
type: string
enum:
- taxonomy_merge_preview
kind:
type: string
enum:
- category
- skill
from:
type: object
properties:
id:
type: string
name:
type: string
slug:
type: string
jobCount:
type: integer
description: Live jobs tagged with this term.
required:
- id
- name
- slug
- jobCount
into:
type: object
properties:
id:
type: string
name:
type: string
slug:
type: string
jobCount:
type: integer
description: Live jobs tagged with this term.
required:
- id
- name
- slug
- jobCount
childCount:
type: integer
description: Subcategories that move to the surviving category.
undoAvailable:
type: boolean
description: 'Whether the merge will be undoable: `from` has no more live jobs than `undoJobCap`.'
undoJobCap:
type: integer
undoWindowDays:
type: integer
required:
- object
- kind
- from
- into
- childCount
- undoAvailable
- undoJobCap
- undoWindowDays
MergeTaxonomyBody:
type: object
properties:
intoId:
type: string
minLength: 1
description: The id of the term that survives the merge.
required:
- intoId
additionalProperties: false
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