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 Billing 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: Billing
description: Your account's platform subscription, entitlements, checkout, upgrade, and Stripe Connect status.
paths:
/billing/checkout:
post:
summary: Create hosted checkout for a plan
description: Returns a hosted human-consent URL for the target plan. Requires `billing.manage`.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BillingCheckoutBody'
responses:
'200':
description: Hosted checkout session created.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingCheckout'
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:
- Billing
operationId: createCheckoutSession
/billing/portal:
post:
summary: Create a billing portal session
description: Returns a hosted billing portal URL for the Board's own Cavuno subscription, the same portal the dashboard's Manage billing button opens. A person uses it to view invoices, update payment methods, and manage the subscription. Each call issues a fresh URL. Returns `billing_portal_unavailable` (409) when the Board has never subscribed; start a subscription with `POST /v1/billing/checkout` instead. Requires `billing.manage`.
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/CreateBillingPortalSessionBody'
responses:
'200':
description: Billing portal session created.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingPortalSession'
'400':
description: The request was malformed or `returnUrl` is not allowed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The Board has no billing account yet.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'502':
description: The billing portal could not be opened.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Billing
operationId: createBillingPortalSession
/billing/upgrade:
post:
summary: Upgrade the account plan
description: Creates a hosted human-consent handoff for an upgrade. It never charges a saved payment method directly. Requires `billing.manage` and an `Idempotency-Key` header.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BillingUpgradeBody'
responses:
'200':
description: Upgrade completed or checkout required.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingUpgrade'
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:
- Billing
operationId: upgradeSubscription
/billing/subscription:
get:
summary: Get the account platform subscription
description: Returns the Board's Cavuno plan, status, renewal state, and included product capabilities. Provider identifiers are never returned.
responses:
'200':
description: The account billing subscription.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingSubscription'
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:
- Billing
operationId: getBillingSubscription
/billing/connect:
get:
summary: Get payment connection status
description: 'Returns the Board''s payment connection readiness: whether payments and payouts are enabled, the connected Stripe account id, the tax collection status, and the names of any details Stripe still needs.'
responses:
'200':
description: The Board payment connection status.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingConnect'
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:
- Billing
operationId: getBillingConnect
delete:
summary: Disconnect the payment connection
description: 'Disconnects the Board''s payment account, as the dashboard''s Disconnect action does. The Board stops taking payments through it straight away: paid plans can no longer be checked out and the job-seeker paywall is unpublished. Nothing changes inside the payment account itself: collected money, payouts, customers, and existing subscriptions stay there and keep renewing, but buyers lose the self-serve billing link on the Board until you reconnect. The synced tax status is cleared. Reconnect later with `POST /v1/billing/connect/onboarding-link`. Disconnecting a Board that is not connected succeeds. Sandbox boards use a platform-provisioned test connection and are refused with `sandbox_connect_managed` (409). Requires `plans.manage`.'
responses:
'204':
description: Payment connection removed.
'409':
description: Sandbox boards cannot disconnect.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
x-audience: operator
tags:
- Billing
operationId: disconnectBillingConnect
/billing/builder-credits:
get:
summary: Get Builder credit history
description: 'Returns the Board''s Builder credit ledger: automatic top-up settings, the newest credit grants, and recent credit spend per day, month and billing period. Credit amounts are in tenths of a credit, like GET /usage, which carries the current balances.'
responses:
'200':
description: The Board Builder credit history.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingBuilderCredits'
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:
- Billing
operationId: getBillingBuilderCredits
/billing/tax:
get:
summary: Get tax collection settings
description: 'Returns the Board''s tax collection settings, read live from its connected Stripe account: default tax behavior and tax code, head office country, and active tax registrations. Cavuno only reads these settings; change them in Stripe. When Stripe is not connected the response has `connected: false`.'
responses:
'200':
description: The Board tax collection settings.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingTax'
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:
- Billing
operationId: getBillingTax
/billing/connect/onboarding-link:
post:
summary: Create a Stripe Connect onboarding link
description: 'Returns a hosted Stripe onboarding URL for the Board''s payment connection, creating the connected account first if the Board has none. The URL is single-use and expires within minutes: hand it to a human immediately, then poll `GET /v1/billing/connect` until `acceptingPayments` and `payoutsEnabled` are both true. Calling this again issues a fresh link, so request a new one if the human did not finish in time. When the human finishes or the link expires, Stripe sends them to the Board''s payment settings in the dashboard. Sandbox boards use a platform-provisioned test connection and are refused with `sandbox_connect_managed` (409). Requires `plans.manage`.'
responses:
'200':
description: Onboarding link created.
content:
application/json:
schema:
$ref: '#/components/schemas/BillingConnectOnboardingLink'
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:
- Billing
operationId: createBillingConnectOnboardingLink
components:
schemas:
BillingConnect:
type: object
properties:
object:
type: string
enum:
- billing_connect
connected:
type: boolean
acceptingPayments:
type: boolean
payoutsEnabled:
type: boolean
detailsSubmitted:
type: boolean
actionRequired:
type: boolean
stripeAccountId:
type:
- string
- 'null'
description: The Board's connected Stripe account id (`acct_...`), or null when Stripe is not connected. Use it to find the account in the Stripe Dashboard.
taxCollectionStatus:
type:
- string
- 'null'
enum:
- active
- pending
- null
description: '`active`: Stripe Tax is set up and checkouts collect tax. `pending`: Stripe Tax setup was started but is not finished. Null when tax collection was never set up. Details are on GET /billing/tax.'
requirements:
type:
- object
- 'null'
properties:
currentlyDue:
type: array
items:
type: string
description: Names of the details Stripe needs now to keep the account enabled, for example `external_account`.
pastDue:
type: array
items:
type: string
description: Names of the details whose deadline has passed. Payments or payouts stay paused until they are provided.
required:
- currentlyDue
- pastDue
description: What Stripe still needs from the account holder, as requirement names only. Null when Stripe is not connected.
required:
- object
- connected
- acceptingPayments
- payoutsEnabled
- detailsSubmitted
- actionRequired
- stripeAccountId
- taxCollectionStatus
- requirements
BillingCheckout:
type: object
properties:
object:
type: string
enum:
- billing_checkout
funding:
$ref: '#/components/schemas/BillingHostedCheckoutFunding'
url:
type: string
format: uri
description: Short-lived hosted checkout URL.
planKey:
type: string
enum:
- starter
- basic
- grow
- advanced
- scale
- enterprise
description: Self-serve plan key. enterprise is not self-serve and returns plan_not_self_serve.
interval:
type: string
enum:
- monthly
- annual
required:
- object
- funding
- url
- planKey
- interval
BuilderCreditUsagePeriod:
type: object
properties:
kind:
type: string
enum:
- day
- month
- billing
description: 'Window the counter covers: a UTC day, a UTC month, or the billing period of the plan.'
periodKey:
type: string
description: Stable key of the window, in the same form as the `periodKey` fields of GET /usage.
usedTenths:
type: integer
minimum: 0
description: Credits spent in the window. In tenths of a credit, like GET /usage (10 is one credit).
runCount:
type: integer
minimum: 0
description: Metered Builder chat runs counted in the window.
required:
- kind
- periodKey
- usedTenths
- runCount
BuilderCreditAutoTopup:
type: object
properties:
available:
type: boolean
description: Whether automatic top-ups are offered at all. When false, no automatic top-up runs, whatever `enabled` says.
canTopUp:
type: boolean
description: Whether the Board's plan allows buying credits. When false, no automatic top-up runs, whatever `enabled` says.
enabled:
type: boolean
description: Whether the Board opted in to automatic credit top-ups. False when it never did. Top-ups only run when `available` and `canTopUp` are also true.
packTenths:
type: integer
minimum: 0
description: Credits bought by each automatic top-up. In tenths of a credit, like GET /usage (10 is one credit).
monthlyCapUsdCents:
type:
- integer
- 'null'
minimum: 0
description: Most that automatic top-ups may spend in one UTC month, in US cents. Null means no cap.
disabledReason:
type:
- string
- 'null'
description: Why automatic top-ups are paused, as `{code}|{month}` (for example a declined card), or null. A pause only lasts for the month it names.
consentedAt:
type:
- string
- 'null'
description: ISO-8601 time a person on the Board opted in to automatic top-ups, or null when they never did.
required:
- available
- canTopUp
- enabled
- packTenths
- monthlyCapUsdCents
- disabledReason
- consentedAt
BillingBuilderCredits:
type: object
properties:
object:
type: string
enum:
- billing_builder_credits
autoTopup:
$ref: '#/components/schemas/BuilderCreditAutoTopup'
grants:
type: array
items:
$ref: '#/components/schemas/BuilderCreditGrant'
description: The 20 newest credit grants (refreshes and purchases), newest first.
usagePeriods:
type: array
items:
$ref: '#/components/schemas/BuilderCreditUsagePeriod'
description: 'Recent credit spend: up to 14 days, 6 months and 6 billing periods, each newest first.'
required:
- object
- autoTopup
- grants
- usagePeriods
BillingUpgrade:
type: object
properties:
object:
type: string
enum:
- billing_upgrade
funding:
$ref: '#/components/schemas/BillingHostedCheckoutFunding'
status:
type: string
enum:
- human_action_required
url:
type: string
format: uri
planKey:
type: string
enum:
- starter
- basic
- grow
- advanced
- scale
- enterprise
description: Self-serve plan key. enterprise is not self-serve and returns plan_not_self_serve.
required:
- object
- funding
- status
- url
- planKey
BillingHostedCheckoutFunding:
type: object
properties:
type:
type: string
enum:
- hosted_checkout
required:
- type
BillingSubscription:
type: object
properties:
object:
type: string
enum:
- billing_subscription
active:
type: boolean
status:
type:
- string
- 'null'
planKey:
type:
- string
- 'null'
currentPeriodEnd:
type:
- number
- 'null'
description: Subscription period end as a millisecond epoch.
cancelAtPeriodEnd:
type: boolean
capabilities:
type: object
properties:
activeJobsLimit:
type:
- number
- 'null'
subscriberLimit:
type:
- number
- 'null'
teamSeatLimit:
type:
- number
- 'null'
canBePublic:
type: boolean
canRemoveBranding:
type: boolean
apiAccess:
type: boolean
required:
- activeJobsLimit
- subscriberLimit
- teamSeatLimit
- canBePublic
- canRemoveBranding
- apiAccess
required:
- object
- active
- status
- planKey
- currentPeriodEnd
- cancelAtPeriodEnd
- capabilities
CreateBillingPortalSessionBody:
type: object
properties:
returnUrl:
type: string
format: uri
description: Where to send the person when they leave the portal. Must be an https URL on the Cavuno dashboard origin. Defaults to the Board billing settings page in the dashboard.
additionalProperties: false
BillingTaxRegistration:
type: object
properties:
country:
type: string
description: Two-letter ISO country code of the tax registration.
type:
type: string
description: Stripe registration type for the country, for example `standard`, `oss_union`, `oss_non_union` or `ioss`.
required:
- country
- type
BillingUpgradeBody:
type: object
properties:
planKey:
type: string
enum:
- starter
- basic
- grow
- advanced
- scale
- enterprise
description: Self-serve plan key. enterprise is not self-serve and returns plan_not_self_serve.
interval:
type: string
enum:
- monthly
- annual
description: Billing interval. Defaults to monthly when omitted.
required:
- planKey
BillingTax:
type: object
properties:
object:
type: string
enum:
- billing_tax
connected:
type: boolean
description: Whether the Board has a connected Stripe account. When false, every other field is null.
taxCollectionStatus:
type:
- string
- 'null'
enum:
- active
- pending
- null
description: '`active`: checkouts collect tax. `pending`: setup was started but is not finished. Null when tax collection was never set up.'
livemode:
type:
- boolean
- 'null'
description: Whether the Stripe account is in live mode. False for a test account. Null when Stripe is not connected.
taxBehavior:
type:
- string
- 'null'
enum:
- inferred_by_currency
- inclusive
- exclusive
- null
description: 'Whether prices include tax by default: `inclusive`, `exclusive`, or `inferred_by_currency`. Null when not set or when Stripe could not be reached.'
taxCode:
type:
- string
- 'null'
description: Default Stripe product tax code, for example `txcd_10000000`. `txcd_00000000` means nontaxable. Null when not set or when Stripe could not be reached.
taxCodeName:
type:
- string
- 'null'
description: Name of the default tax code, or null.
headOfficeCountry:
type:
- string
- 'null'
description: Two-letter ISO country code of the head office address set in Stripe Tax, or null.
registrations:
type:
- array
- 'null'
items:
$ref: '#/components/schemas/BillingTaxRegistration'
description: Active tax registrations, up to 100. An empty list means no registrations, so no tax is collected anywhere. Null when Stripe is not connected or the list could not be loaded.
required:
- object
- connected
- taxCollectionStatus
- livemode
- taxBehavior
- taxCode
- taxCodeName
- headOfficeCountry
- registrations
BillingPortalSession:
type: object
properties:
object:
type: string
enum:
- billing_portal_session
url:
type: string
format: uri
description: Short-lived hosted billing portal URL. Hand it to a human straight away; request a new one if it expires.
required:
- object
- url
BillingCheckoutBody:
type: object
properties:
planKey:
type: string
enum:
- starter
- basic
- grow
- advanced
- scale
- enterprise
description: Self-serve plan key. enterprise is not self-serve and returns plan_not_self_serve.
interval:
type: string
enum:
- monthly
- annual
description: Billing interval. Defaults to monthly when omitted.
required:
- planKey
BuilderCreditGrant:
type: object
properties:
source:
type: string
enum:
- refresh
- topup
- auto-topup
description: '`refresh`: a one-time refresh of the plan allowance. `topup`: credits a person bought. `auto-topup`: credits bought automatically.'
tenths:
type: integer
minimum: 0
description: Credits granted. In tenths of a credit, like GET /usage (10 is one credit).
remainingTenths:
type: integer
minimum: 0
description: Credits of this grant not yet spent. In tenths of a credit, like GET /usage (10 is one credit).
refundedTenths:
type: integer
minimum: 0
description: Credits taken back after a refund or a lost dispute. In tenths of a credit, like GET /usage (10 is one credit).
priceUsdCents:
type:
- integer
- 'null'
minimum: 0
description: Price paid for a purchase, in US cents. Null for a refresh, which is free.
createdAt:
type: string
description: ISO-8601 time the grant was created.
expiresAt:
type:
- string
- 'null'
description: ISO-8601 time the unspent credits expire, or null when they never expire (purchases).
required:
- source
- tenths
- remainingTenths
- refundedTenths
- priceUsdCents
- createdAt
- expiresAt
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.'
BillingConnectOnboardingLink:
type: object
properties:
object:
type: string
enum:
- billing_connect_onboarding_link
url:
type: string
format: uri
description: Single-use hosted Stripe onboarding URL. Hand it to a human straight away; it expires within minutes.
expiresAt:
type: string
format: date-time
description: ISO 8601 time after which the URL no longer works.
required:
- object
- url
- expiresAt
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