Indraft Billing API
The billing API from Indraft — 3 operation(s) for billing.
The billing API from Indraft — 3 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/indraft-io:indraft-io-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: Indraft Io Billing API
version: '1'
description: 'Operations tagged billing across 2 of this provider''s published API definitions: indraft-io-openapi.json, indraft-io.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.indraft.io
security:
- bearerAuth: []
tags:
- name: Billing
paths:
/billing/usage:
get:
summary: Plan, subscription status, and usage against every quota
description: 'Plan, subscription state, and usage against every quota, served from the control plane rather than the workspace. That separation is deliberate: billing state has to be readable when a workspace is at its storage ceiling, and checking whether you are over budget must not consume the budget.'
tags:
- Billing
operationId: get_billing_usage
x-indraft-capability: crm:read
x-indraft-scopes:
- crm:read
- crm:write
- crm:configure
- crm:admin
- crm:revert
- data:export
responses:
'200':
description: Success
headers:
ratelimit-limit:
description: Requests permitted in the window closest to refusing this caller.
schema:
type: integer
ratelimit-remaining:
description: Requests left in that window. Zero means the next request is refused.
schema:
type: integer
ratelimit-reset:
description: Seconds until that window resets.
schema:
type: integer
ratelimit-policy:
description: Every window in force, not only the one reported above.
schema:
type: string
content:
application/json:
schema:
type: object
properties:
plan:
type: string
status:
type: string
metrics:
type: array
items:
type: object
properties:
metric:
type: string
used:
type: integer
limit:
type: integer
required:
- metric
- used
- limit
additionalProperties: true
activity:
type: object
properties:
interactions:
type: integer
tasks:
type: integer
required:
- interactions
- tasks
additionalProperties: true
capacity:
type: object
properties:
bytes:
type: integer
ceilingBytes:
type: integer
fractionUsed:
type: integer
warning:
type: string
enum:
- none
- approaching
- critical
operatorAlert:
type: boolean
projection:
type: object
properties:
observedDays:
type: integer
bytesPerDay:
type: integer
monthsToCeiling:
type: integer
reachesCeilingAt:
type: string
required:
- observedDays
- bytesPerDay
- monthsToCeiling
- reachesCeilingAt
additionalProperties: true
indexedRecords:
type: integer
required:
- bytes
- ceilingBytes
- fractionUsed
- warning
- operatorAlert
- projection
additionalProperties: true
overage:
type: object
properties:
pooled:
type: object
properties:
records:
type: integer
changes:
type: integer
required:
- records
- changes
additionalProperties: true
lines:
type: array
items:
type: object
properties:
metric:
type: string
enum:
- records
- changes
over:
type: integer
blocks:
type: integer
blockSize:
type: integer
perBlockMinor:
type: integer
amountMinor:
type: integer
required:
- metric
- over
- blocks
- blockSize
- perBlockMinor
- amountMinor
additionalProperties: true
seatsMinor:
type: integer
totalMinor:
type: integer
cappedTo:
type: string
savedMinor:
type: integer
required:
- pooled
- lines
- seatsMinor
- totalMinor
- cappedTo
- savedMinor
additionalProperties: true
required:
- plan
- status
- metrics
additionalProperties: true
'401':
description: No credential, or one that has been revoked.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Authenticated, and this capability is not held.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Infrastructure protection tripped. This is not a product quota.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers:
ratelimit-limit:
description: Requests permitted in the window closest to refusing this caller.
schema:
type: integer
ratelimit-remaining:
description: Requests left in that window. Zero means the next request is refused.
schema:
type: integer
ratelimit-reset:
description: Seconds until that window resets.
schema:
type: integer
ratelimit-policy:
description: Every window in force, not only the one reported above.
schema:
type: string
retry-after:
description: Seconds to wait before retrying. The request itself was fine.
schema:
type: integer
'500':
description: A defect on our side. The hint says so, and carries an incident id.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://api.indraft.io
/billing/checkout:
post:
summary: Start a Stripe Checkout session for a plan
description: Starts a Stripe Checkout session and returns the URL to send the customer to. No card details reach Indraft at any point, and no CRM record reaches Stripe.
tags:
- Billing
operationId: post_billing_checkout
x-indraft-capability: billing:manage
x-indraft-scopes: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
plan:
type: string
enum:
- solo
- team
- scale
- business
interval:
type: string
enum:
- month
- year
required:
- plan
additionalProperties: false
responses:
'200':
description: Success
headers:
ratelimit-limit:
description: Requests permitted in the window closest to refusing this caller.
schema:
type: integer
ratelimit-remaining:
description: Requests left in that window. Zero means the next request is refused.
schema:
type: integer
ratelimit-reset:
description: Seconds until that window resets.
schema:
type: integer
ratelimit-policy:
description: Every window in force, not only the one reported above.
schema:
type: string
content:
application/json:
schema:
type: object
properties:
url:
type: string
required:
- url
additionalProperties: true
'401':
description: No credential, or one that has been revoked.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'402':
description: A product quota is spent, or the subscription is not active.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Authenticated, and this capability is not held.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'A conflict the caller can resolve: a stale expectedVersion, an idempotency key reused for different input, an ambiguous or duplicate identity, or a merge that no longer applies.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: The body, or a single record inside it, exceeds its bound.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: The request does not satisfy the schema on this page.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Infrastructure protection tripped. This is not a product quota.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers:
ratelimit-limit:
description: Requests permitted in the window closest to refusing this caller.
schema:
type: integer
ratelimit-remaining:
description: Requests left in that window. Zero means the next request is refused.
schema:
type: integer
ratelimit-reset:
description: Seconds until that window resets.
schema:
type: integer
ratelimit-policy:
description: Every window in force, not only the one reported above.
schema:
type: string
retry-after:
description: Seconds to wait before retrying. The request itself was fine.
schema:
type: integer
'500':
description: A defect on our side. The hint says so, and carries an incident id.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'507':
description: The workspace is at its storage ceiling.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://api.indraft.io
/billing/portal:
post:
summary: Open the Stripe Customer Portal
description: 'Opens the Stripe Customer Portal, where a customer changes their card, reads invoices, or cancels. Cancelling there is the whole path: there is no retention flow to get through.'
tags:
- Billing
operationId: post_billing_portal
x-indraft-capability: billing:manage
x-indraft-scopes: []
responses:
'200':
description: Success
headers:
ratelimit-limit:
description: Requests permitted in the window closest to refusing this caller.
schema:
type: integer
ratelimit-remaining:
description: Requests left in that window. Zero means the next request is refused.
schema:
type: integer
ratelimit-reset:
description: Seconds until that window resets.
schema:
type: integer
ratelimit-policy:
description: Every window in force, not only the one reported above.
schema:
type: string
content:
application/json:
schema:
type: object
properties:
url:
type: string
required:
- url
additionalProperties: true
'401':
description: No credential, or one that has been revoked.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'402':
description: A product quota is spent, or the subscription is not active.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Authenticated, and this capability is not held.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'A conflict the caller can resolve: a stale expectedVersion, an idempotency key reused for different input, an ambiguous or duplicate identity, or a merge that no longer applies.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Infrastructure protection tripped. This is not a product quota.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers:
ratelimit-limit:
description: Requests permitted in the window closest to refusing this caller.
schema:
type: integer
ratelimit-remaining:
description: Requests left in that window. Zero means the next request is refused.
schema:
type: integer
ratelimit-reset:
description: Seconds until that window resets.
schema:
type: integer
ratelimit-policy:
description: Every window in force, not only the one reported above.
schema:
type: string
retry-after:
description: Seconds to wait before retrying. The request itself was fine.
schema:
type: integer
'500':
description: A defect on our side. The hint says so, and carries an incident id.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'507':
description: The workspace is at its storage ceiling.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
servers:
- url: https://api.indraft.io
components:
schemas:
ErrorDetail:
type: object
additionalProperties: true
description: The structured payload a recovery needs. Its shape differs per code; the keys below are the ones that recur, and anything else a code carries is present alongside them.
properties:
fieldErrors:
type: object
additionalProperties:
type: string
description: One message per field the caller sent, keyed by that field. The key `(body)` is the request body itself, which is what an unrecognised key reports under.
reason:
type: string
description: One sentence, where the refusal is about the request rather than a field. A refusal that names alternatives puts them here.
available:
type: array
items:
type: string
description: What could have been asked for instead. Present on a filter, sort or group-by the API does not serve, so a correction is one edit rather than a round trip to read the schema.
options:
type: array
items:
type: string
description: The values an enum accepts, on a value it does not.
currentVersion:
type: integer
description: What the record's version actually is, on `stale_version`. With the value you sent it is everything needed to decide whether to re-read and retry or to stop.
expectedVersion:
type: integer
description: The version you sent, echoed back on `stale_version`.
requiredScope:
type: string
description: 'The capability the credential lacks. Empty nowhere: a route no credential can reach is human-only and says so in its scopes instead.'
Error:
type: object
required:
- code
- message
- recoveryHint
- requestId
properties:
code:
type: string
enum:
- unauthorized
- forbidden_scope
- standing_override_refused
- workspace_not_found
- validation_error
- record_not_found
- ambiguous_identity
- duplicate_identity
- stale_version
- invalid_stage_transition
- idempotency_conflict
- not_reversible
- merge_conflict
- rate_limited
- quota_exceeded
- payload_too_large
- workspace_capacity
- payment_required
- billing_state_stale
- operation_in_flight
- internal_error
message:
type: string
recoveryHint:
type: string
requestId:
type: string
detail:
$ref: '#/components/schemas/ErrorDetail'
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: An Indraft API token, or a WorkOS-issued session or MCP access token.
x-refined-from:
- indraft-io-openapi.json
- indraft-io.json