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 Email templates 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: Email Templates
description: Customize the subject, preview text, and body of the emails your board sends.
paths:
/email-templates:
get:
summary: List email templates
description: Returns every email your board sends that you can customize, one entry per type, whether or not you have customized it. Each entry lists the tokens you can use and the tokens the body must contain, so you can write a valid template. The list is short and returned in one page.
responses:
'200':
description: Successful response.
content:
application/json:
schema:
type: object
properties:
object:
type: string
enum:
- list
url:
type: string
example: /v1/email-templates
hasMore:
type: boolean
nextCursor:
type:
- string
- 'null'
data:
type: array
items:
$ref: '#/components/schemas/EmailTemplateSummary'
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:
- Email Templates
operationId: listEmailTemplates
/email-templates/{type}:
get:
summary: Retrieve an email template
description: 'Retrieves the template in effect for one email type: your published version when `customized` is `true`, otherwise the default template that the dashboard editor starts from.'
parameters:
- schema:
type: string
minLength: 1
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
example: board-magic-link
required: true
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
name: type
in: path
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/EmailTemplate'
'404':
description: No email template has this type (`email_templates_not_found`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Email Templates
operationId: getEmailTemplate
put:
summary: Publish an email template
description: 'Publishes your version of an email, replacing any version published before. It is used for every email of this type sent from then on. Send all three fields. The template is checked the same way as in the dashboard editor: length limits, only the tokens listed for this type, and every required body token present.'
parameters:
- schema:
type: string
minLength: 1
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
example: board-magic-link
required: true
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
name: type
in: path
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PublishEmailTemplateBody'
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/EmailTemplate'
'400':
description: 'The subject, preview text or body was rejected (`email_templates_invalid_content`): it is too long, contains a malformed or unsupported token, is missing a required body token, or puts a sensitive token (a `*_url` token, the verification code or an HTML chunk) anywhere but a body link href (`reason: unsafe_token_placement`). `error.details` names the `field`, the `reason` and the `token`.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No email template has this type (`email_templates_not_found`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Email Templates
operationId: publishEmailTemplate
delete:
summary: Reset an email template
description: Deletes your published version so the default template is sent again. Succeeds when the email was not customized.
parameters:
- schema:
type: string
minLength: 1
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
example: board-magic-link
required: true
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
name: type
in: path
responses:
'204':
description: Successful response.
'404':
description: No email template has this type (`email_templates_not_found`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Email Templates
operationId: resetEmailTemplate
/email-templates/{type}/test:
post:
summary: Send a test email
description: Sends the email in effect for this type, with sample values for its tokens and your board’s branding, to the email address of the member making the request (for an API key, the member who created it). Use it to check a template after publishing. A board can send 20 test emails an hour, shared with the dashboard editor.
parameters:
- schema:
type: string
minLength: 1
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
example: board-magic-link
required: true
description: The email template type, as returned in `type` by the list endpoint. One of `board-magic-link`, `board-email-verification`, `board-password-reset`, `board-work-email-verification`, `job-alert-subscription-confirmation`, `job-alert-digest`, `job-recommendation-digest`, `company-access-approved`, `company-access-rejected`, `public-job-submission-customer`, `public-job-submission-pending`, `public-job-submission-approved`, `billing-verification`, `board-new-message`, `board-job-invoice-on-issue`, `board-job-invoice-on-payment`, `board-email-change`, `board-email-changed-notice`, `board-account-deleted`, `board-company-invite`, `board-new-application`, `board-digital-product-purchase`, `board-digital-product-copy-ready`, `board-digital-product-updated`, `board-digital-product-download-link`, `board-item-verification-code`, `board-item-verification-expiring`, `board-item-verification-lapsed`, `board-item-verification-decided`.
name: type
in: path
responses:
'200':
description: Successful response.
content:
application/json:
schema:
$ref: '#/components/schemas/EmailTemplateTest'
'403':
description: The member making the request is no longer an active member of the board.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No email template has this type (`email_templates_not_found`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The member has no email address (`email_templates_no_test_recipient`), or the board is not set up yet (`email_templates_board_not_configured`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: The board has sent 20 test emails in the last hour (`email_templates_test_rate_limited`). The `Retry-After` header gives the seconds to wait.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Email Templates
operationId: testEmailTemplate
components:
schemas:
EmailTemplateTest:
type: object
properties:
object:
type: string
enum:
- email_template_test
description: String representing the object's type. Objects of the same type share the same value.
type:
type: string
description: The email template type that was sent.
sent:
type: boolean
enum:
- true
description: Always `true` when the test was sent.
required:
- object
- type
- sent
PublishEmailTemplateBody:
type: object
properties:
subject:
type: string
description: Subject line, up to 200 characters. May use the tokens listed in `subjectTokens`, written as `{{token}}`.
previewText:
type: string
description: Inbox preview text, up to 150 characters. May use the tokens listed in `subjectTokens`. An empty string sends the default preview text.
bodyHtml:
type: string
description: Body HTML, up to 100 KB, in the same shape as the default template returned by the retrieve endpoint (paragraphs, headings, links and buttons; the board’s header, footer and theme are added around it). May use the tokens listed in `bodyTokens` and must contain every token in `requiredBodyTokens`.
required:
- subject
- previewText
- bodyHtml
additionalProperties: false
EmailTemplateSummary:
type: object
properties:
id:
type: string
description: Unique identifier for the email template. Same as `type`.
object:
type: string
enum:
- email_template
description: String representing the object's type. Objects of the same type share the same value.
type:
type: string
description: The email template type.
name:
type: string
description: Display name of the email.
description:
type: string
description: When the email is sent.
customized:
type: boolean
description: Whether the board has published its own version. When `false`, the default template is sent.
publishedAt:
type:
- string
- 'null'
description: Time the customized version was last published, or `null` when the default is in use. ISO 8601 datetime.
subjectTokens:
type: array
items:
type: string
description: Tokens available in `subject` and `previewText`, without braces. Write them as `{{token}}`.
bodyTokens:
type: array
items:
type: string
description: Tokens available in `bodyHtml`, without braces. Includes block tokens that expand to a rendered section, such as a list of jobs.
requiredBodyTokens:
type: array
items:
type: string
description: Tokens `bodyHtml` must contain, without braces. A publish without them is rejected.
required:
- id
- object
- type
- name
- description
- customized
- publishedAt
- subjectTokens
- bodyTokens
- requiredBodyTokens
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.'
EmailTemplate:
type: object
properties:
id:
type: string
description: Unique identifier for the email template. Same as `type`.
object:
type: string
enum:
- email_template
description: String representing the object's type. Objects of the same type share the same value.
type:
type: string
description: The email template type.
name:
type: string
description: Display name of the email.
description:
type: string
description: When the email is sent.
customized:
type: boolean
description: Whether the board has published its own version. When `false`, the default template is sent.
publishedAt:
type:
- string
- 'null'
description: Time the customized version was last published, or `null` when the default is in use. ISO 8601 datetime.
subjectTokens:
type: array
items:
type: string
description: Tokens available in `subject` and `previewText`, without braces. Write them as `{{token}}`.
bodyTokens:
type: array
items:
type: string
description: Tokens available in `bodyHtml`, without braces. Includes block tokens that expand to a rendered section, such as a list of jobs.
requiredBodyTokens:
type: array
items:
type: string
description: Tokens `bodyHtml` must contain, without braces. A publish without them is rejected.
subject:
type: string
description: Subject line in effect, with tokens unexpanded.
previewText:
type: string
description: Inbox preview text in effect, with tokens unexpanded.
bodyHtml:
type: string
description: Body HTML in effect, with tokens unexpanded. Edit it and send it back with the publish endpoint.
required:
- id
- object
- type
- name
- description
- customized
- publishedAt
- subjectTokens
- bodyTokens
- requiredBodyTokens
- subject
- previewText
- bodyHtml
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