Chronary Billing API
The Billing API from Chronary — 5 operation(s) for billing.
The Billing API from Chronary — 5 operation(s) for billing.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/chronary-ai:chronary-ai-billing-api"
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.
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: Chronary Billing API
version: 1.0.0
description: 'Calendar-as-a-service API for AI agents.
Manage calendars, events, and availability for AI and human agents.
All endpoints require an API key passed as a Bearer token.
**Authentication:** `Authorization: Bearer chr_sk_...` or `Authorization: Bearer chr_ak_...`
**Rate limit:** 10 requests/second per API key. Exceeds return HTTP 429.
**Quotas:** Monthly operation limits by plan — see Billing & plans and Rate limits.
**Agent bootstrap:** Custom extensions prefixed `x-agent-*` describe the self-signup flow for AI agents. These are not part of any registered OpenAPI extension — they are a Chronary convention.'
contact:
name: Chronary Support
email: support@chronary.ai
url: https://docs.chronary.ai
servers:
- url: https://api.chronary.ai
description: Production
security:
- BearerAuth: []
tags:
- name: Billing
paths:
/v1/billing:
get:
operationId: getBilling
summary: Get billing status
description: Plan, subscription status, renewal or cancellation date, Pro pricing and any pending upgrade request. Never contains payment-provider ids. Works even when the org has hit its usage limit. Org-level API keys or a console session; agent-scoped keys receive 403.
tags:
- Billing
responses:
'200':
description: Billing summary
headers:
X-Chronary-Plan:
description: The current plan of the authenticated organization (free | pro | scale)
schema:
type: string
enum:
- free
- pro
- scale
content:
application/json:
schema:
$ref: '#/components/schemas/BillingSummary'
'401':
description: Unauthorized — missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden — quota exceeded or operation not permitted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/v1/billing/upgrade-requests:
post:
operationId: createUpgradeRequest
summary: Ask a human to upgrade to Pro
description: 'Creates an upgrade request and emails the account owner. Give `approval_url` to your human — only a human can pay. At most one request is pending per org: a repeat call returns it with `reused: true` (200). Poll `GET /v1/billing/upgrade-requests/{id}` at most once a minute. Org-level API keys only; signed-in humans use the console Billing page instead. Honors `Idempotency-Key`.'
tags:
- Billing
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUpgradeRequest'
responses:
'200':
description: 'A pending request already existed (`reused: true`)'
content:
application/json:
schema:
$ref: '#/components/schemas/UpgradeRequest'
'201':
description: Upgrade request created; the owner is notified
content:
application/json:
schema:
$ref: '#/components/schemas/UpgradeRequest'
'400':
description: Validation error — invalid request body or query parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized — missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Agent-scoped key, console session (`use_billing_page`), or unverified email (`email_verification_required`)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: '`already_subscribed`, `unsupported_plan` (with `contact_url`), `founding_offer_pending` (early-access account — the founding offer opens at launch), or `upgrade_request_recently_declined` (with `retry_after`)'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: '`upgrade_request_limit` — at most 3 new requests per 24 hours (with `retry_after`)'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: Billing is not configured on this environment
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/v1/billing/upgrade-requests/{id}:
get:
operationId: getUpgradeRequest
summary: Get an upgrade request
description: Poll at most once a minute. After `completed`, wait about 15 seconds before retrying the call that hit the plan limit.
tags:
- Billing
parameters:
- schema:
type: string
example: upr_V1StGXR8Z5jd
description: Upgrade request ID
required: true
description: Upgrade request ID
name: id
in: path
responses:
'200':
description: Upgrade request
content:
application/json:
schema:
$ref: '#/components/schemas/UpgradeRequest'
'401':
description: Unauthorized — missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden — quota exceeded or operation not permitted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/v1/billing/upgrade-requests/{id}/cancel:
post:
operationId: cancelUpgradeRequest
summary: Cancel an upgrade request
description: Withdraw a pending upgrade request.
tags:
- Billing
parameters:
- schema:
type: string
example: upr_V1StGXR8Z5jd
description: Upgrade request ID
required: true
description: Upgrade request ID
name: id
in: path
responses:
'200':
description: Upgrade request canceled
content:
application/json:
schema:
$ref: '#/components/schemas/UpgradeRequest'
'401':
description: Unauthorized — missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden — quota exceeded or operation not permitted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The request is no longer pending — `error.status` carries its current status
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/v1/billing/upgrade-requests/{id}/decline:
post:
operationId: declineUpgradeRequest
summary: Decline an upgrade request (console only)
description: 'Human-only: requires a console session and the `X-Chronary-CSRF: 1` header. API keys receive 403 `human_only`. A decline blocks new requests from the org for 72 hours.'
tags:
- Billing
security:
- SessionAuth: []
parameters:
- schema:
type: string
example: upr_V1StGXR8Z5jd
description: Upgrade request ID
required: true
description: Upgrade request ID
name: id
in: path
responses:
'200':
description: Upgrade request declined
content:
application/json:
schema:
$ref: '#/components/schemas/UpgradeRequest'
'401':
description: Missing or invalid console session — these endpoints require a console JWT, not an API key.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden — quota exceeded or operation not permitted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The request is no longer pending — `error.status` carries its current status
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
BillingSummary:
type: object
properties:
plan:
type: string
example: free
plan_source:
type:
- string
- 'null'
plan_expires_at:
type:
- string
- 'null'
format: date-time
status:
type:
- string
- 'null'
description: Subscription status (active, trialing, past_due, canceled, …); null if never subscribed
interval:
type:
- string
- 'null'
enum:
- month
- year
- null
example: month
current_period_end:
type:
- string
- 'null'
format: date-time
cancel_at:
type:
- string
- 'null'
format: date-time
description: When a scheduled cancellation takes effect
cancel_at_period_end:
type: boolean
renews_at:
type:
- string
- 'null'
format: date-time
price:
type:
- object
- 'null'
properties:
amount:
type: integer
example: 2900
currency:
type: string
example: usd
interval:
type: string
enum:
- month
- year
example: month
tax_exclusive:
type: boolean
enum:
- true
required:
- amount
- currency
- interval
- tax_exclusive
has_billing_account:
type: boolean
self_serve_upgrade:
type: boolean
upgrade_options:
type: array
items:
type: object
properties:
plan:
type: string
enum:
- pro
interval:
type: string
enum:
- month
- year
example: month
amount:
type: integer
example: 2900
description: Minor units (cents)
currency:
type: string
example: usd
savings_vs_monthly:
type: integer
example: 0
required:
- plan
- interval
- amount
- currency
- savings_vs_monthly
upgrade_url:
type:
- string
- 'null'
manage_url:
type: string
contact_url:
type:
- string
- 'null'
pending_upgrade_request:
allOf:
- $ref: '#/components/schemas/UpgradeRequest'
- type:
- object
- 'null'
offer:
allOf:
- $ref: '#/components/schemas/BillingOffer'
- type:
- object
- 'null'
description: Founding-member offer for early-access accounts; null otherwise
required:
- plan
- plan_source
- plan_expires_at
- status
- interval
- current_period_end
- cancel_at
- cancel_at_period_end
- renews_at
- price
- has_billing_account
- self_serve_upgrade
- upgrade_options
- upgrade_url
- manage_url
- contact_url
- pending_upgrade_request
- offer
CreateUpgradeRequest:
type: object
properties:
interval:
type: string
enum:
- month
- year
example: month
description: Defaults to month
reason:
type: string
maxLength: 500
example: Need scoped keys for the support agents.
feature:
type: string
example: scoped_keys
description: The `feature` from a plan_required error
metric:
type: string
example: api_calls
description: The `metric` from a quota error
Error:
type: object
properties:
error:
type: object
properties:
type:
type: string
example: invalid_request
message:
type: string
example: The field "name" is required.
request_id:
type: string
example: req_01H9X4M2P5R8T6V0
required_plan:
type: string
example: pro
description: 'plan_required: the plan that unlocks the feature'
feature:
type: string
description: 'plan_required: the gated feature'
metric:
type: string
description: 'quota_exceeded and count caps: the metric at its limit (a PLAN_LIMITS key, accepted by POST /v1/billing/upgrade-requests)'
limit:
type: integer
description: 'quota_exceeded and count caps: the plan''s limit for `metric`'
upgrade_url:
type: string
description: Where a human upgrades the plan
docs_url:
type: string
contact_url:
type: string
description: 'Contract-managed plans: where to contact sales'
retry_after:
type: integer
description: Seconds until the request may be retried
required:
- type
- message
- request_id
required:
- error
BillingOffer:
type: object
properties:
kind:
type: string
enum:
- founding
status:
type: string
enum:
- upcoming
- available
- redeemed
description: '`upcoming` — early-access account; the offer opens at launch (checkout returns 409 `founding_offer_pending` until then). `available` — free Pro until `ends_at`; subscribe before then at the founding discount. `redeemed` — the subscription was created on founding terms.'
ends_at:
type:
- string
- 'null'
format: date-time
description: 'available: when free Pro and the offer end'
trial_until:
type:
- string
- 'null'
format: date-time
description: 'available: billing starts on this date if you subscribe now (null in the last ~2 days: billing starts at checkout). redeemed: trial end while trialing.'
discount_percent:
type:
- integer
- 'null'
example: 50
discount_months:
type:
- integer
- 'null'
example: 12
description: 'Paid months the discount covers (annual: the first year)'
renewal_consent:
type:
- string
- 'null'
enum:
- required
- given
- null
description: 'redeemed: `required` while a trial with a Washington DC billing address waits for the human to choose "Continue to paid Pro" on the console Billing page (otherwise the subscription ends at the trial end, with no charge); `given` once they have. Null otherwise. Agents cannot give this consent.'
required:
- kind
- status
- ends_at
- trial_until
- discount_percent
- discount_months
- renewal_consent
UpgradeRequest:
type: object
properties:
id:
type: string
example: upr_V1StGXR8Z5jd
status:
type: string
enum:
- pending
- completed
- declined
- canceled
- expired
example: pending
plan:
type: string
enum:
- pro
interval:
type: string
enum:
- month
- year
example: month
reason:
type:
- string
- 'null'
description: Note from the agent, shown to the human as plain text on the approval page. Never emailed.
feature:
type:
- string
- 'null'
example: scoped_keys
description: Pro feature that triggered the request
metric:
type:
- string
- 'null'
example: null
description: Usage limit that triggered the request
requested_via:
type: string
enum:
- api
- mcp
requested_by_key_prefix:
type:
- string
- 'null'
description: First 20 characters of the requesting key; never the full key
approval_url:
type:
- string
- 'null'
example: https://console.chronary.ai/settings/billing/requests/upr_V1StGXR8Z5jd
description: Give this to your human. Null once the request is no longer pending.
created_at:
type: string
format: date-time
expires_at:
type: string
format: date-time
description: Pending requests expire 7 days after creation
completed_at:
type:
- string
- 'null'
format: date-time
declined_at:
type:
- string
- 'null'
format: date-time
canceled_at:
type:
- string
- 'null'
format: date-time
owner_notification:
type: string
enum:
- queued
- not_configured
- skipped_internal
- already_notified
description: Create responses only — whether the account owner was emailed
reused:
type: boolean
description: Create responses only — true when a pending request already existed; do not create again
required:
- id
- status
- plan
- interval
- reason
- feature
- metric
- requested_via
- requested_by_key_prefix
- approval_url
- created_at
- expires_at
- completed_at
- declined_at
- canceled_at
securitySchemes:
BearerAuth:
type: http
scheme: bearer
description: 'API key with `chr_sk_*` for org-level access or `chr_ak_*` for agent-scoped access. Pass in the Authorization header: `Authorization: Bearer chr_sk_...`'
SessionAuth:
type: apiKey
in: cookie
name: chronary_session
description: Console session JWT (HS256), issued by sign-in and sent as the `chronary_session` cookie (a Bearer JWT is also accepted). This is NOT a chr_sk_*/chr_ak_* API key — API keys are rejected with 401 on these endpoints.
x-agent-self-signup:
url: https://api.chronary.ai/v1/agent/sign-up
verify_url: https://api.chronary.ai/v1/agent/verify
restricted_key_returned: true
human_in_the_loop: otp_email
rate_limit: 5 requests per 60s per client IP
x-agent-bootstrap-script:
npx: npx @chronary/agent-init@latest
shell: https://chronary.ai/agent-init.sh
description: One-liner that performs sign-up, prompts for OTP, verifies, and creates a smoke calendar. Accepts CHRONARY_EMAIL and CHRONARY_OTP env vars for non-interactive flows.
x-llms-txt: https://docs.chronary.ai/llms.txt
x-llms-full-txt: https://docs.chronary.ai/llms-full.txt
x-mcp-server-card: https://chronary.ai/.well-known/mcp/server-card.json
x-api-catalog: https://chronary.ai/.well-known/api-catalog