Billing
Plans, pricing, Stripe checkout, subscription management, and overage billing.
Billing endpoints are only available in cloud mode. Self-hosted deployments manage billing externally. All endpoints require admin role.
Base URL: https://api.airaproof.com/api/v1
Plans & Pricing
| Plan | Monthly | Included Ops | Seats | Case Overage | Other Op Overage | Support |
|---|---|---|---|---|---|---|
| Free | €0 | 100 | 3 | Hard wall (429) | Hard wall (429) | — |
| Pro | €299 | 10,000 | Unlimited | €0.03/case | €0.05/op | |
| Business | €699 | 100,000 | Unlimited | €0.015/case | €0.03/op | Priority, 99.5% SLA |
| Enterprise | Custom | Unlimited | Unlimited | Custom | Custom | Dedicated, 99.9% SLA, self-hosted |
All features are available on all plans. Self-hosted deployments have no limits.
What counts as an operation?
An operation is any billable event on your monthly counter. Every billable event is 1 op; cases use the case rate, everything else uses the op rate.
| Event | Fired by | Billable |
|---|---|---|
case_run | POST /api/v1/cases | 1 op (case rate) |
action_authorize | POST /api/v1/actions — at policy decision | 1 op |
chat | POST /api/v1/chat | 1 op per message |
compliance_bundle | POST /api/v1/compliance/bundles | 1 op per bundle |
settlement | POST /api/v1/settlements (admin) | 1 op per sealed batch |
drift_check | POST /api/v1/agents/{id}/drift/check | 1 op per check |
Agent actions bill at authorize, not notarize. The expensive compute — policy engine evaluation, any LLM calls in AI/consensus mode, content scan, and the multi-party signature on the PolicyEvaluation row — all happens inside POST /api/v1/actions. The follow-up POST /api/v1/actions/{id}/notarize is a free bookkeeping call that just mints the Ed25519 receipt for the outcome your agent reports.
This means denied-by-policy and held-for-approval actions also bill: the policy decision is the artifact you're paying for, regardless of what the agent was ultimately allowed to do.
You can't notarize without authorizing first. The action_uuid in the notarize URL is a server-assigned identifier that only exists after POST /api/v1/actions creates the action row. If you pass an unknown id you get 404 NOT_FOUND; denied or pending-approval actions return 409 INVALID_ACTION_STATE. Every successful notarize is backed by exactly one billable authorize in the same org, so the free-notarize rule can't be used to avoid paying for compute.
The following are not billed — they stay free on every plan:
- Notarize:
POST /api/v1/actions/{id}/notarizeis free — and it only succeeds for actions that were previously authorized by your org, so the decision has always been paid for already. - Reads: every
GETendpoint, including verification, inclusion proofs, and bundle exports. - Workflow metadata: approvals, denials, cosignatures, drift-alert acknowledgements, legal-hold release.
- One-time setup: drift baseline computations (production, synthetic, pooled).
- Retries with the same
idempotency_key— they return the original resource without a second charge.
Create Checkout Session
POST /api/v1/billing/checkout
Authorization: Bearer <token>Redirects to Stripe Checkout for plan upgrade. Only pro and business plans are available for self-service.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
plan | string | Yes | Target plan: pro or business |
success_url | string | Yes | URL to redirect after successful checkout |
cancel_url | string | Yes | URL to redirect if checkout is cancelled |
Response
{
"checkout_url": "https://checkout.stripe.com/c/pay/cs_test_...",
"request_id": "req_abc123"
}Behavior
- Free → Pro/Business: Creates a new Stripe Checkout session
- Pro → Business: Upgrades inline (swaps subscription items, prorated)
- Same plan: Returns error (
You are already on the pro plan.) - Downgrade: Not supported via self-service. Use the billing portal to cancel, then resubscribe.
Create Portal Session
POST /api/v1/billing/portal
Authorization: Bearer <token>Opens the Stripe Customer Portal for subscription management (update payment method, view invoices, cancel subscription).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
return_url | string | Yes | URL to return to after portal session |
Response
{
"portal_url": "https://billing.stripe.com/p/session/...",
"request_id": "req_abc123"
}Billing Status
GET /api/v1/billing/status
Authorization: Bearer <token>Returns current subscription status.
Response
{
"plan": "pro",
"has_subscription": true,
"billing_period_end": "2026-04-26T00:00:00Z",
"cancel_at_period_end": false,
"request_id": "req_abc123"
}| Field | Type | Description |
|---|---|---|
plan | string | Current plan: free, pro, business, enterprise |
has_subscription | boolean | Whether a Stripe subscription exists |
billing_period_end | string/null | ISO 8601 datetime of period end |
cancel_at_period_end | boolean | Whether subscription cancels at period end |
Stripe Webhook
POST /api/v1/billing/stripe/webhookNo authentication — verified by Stripe signature. Handles:
| Event | Action |
|---|---|
checkout.session.completed | Activates plan, stores subscription ID |
customer.subscription.updated | Syncs plan and billing period |
customer.subscription.deleted | Reverts to free plan |
invoice.paid | Logged for audit |
invoice.payment_failed | Logged as warning (Stripe handles retry) |
Overage Billing
When a paid plan exceeds its included operations:
- Each usage event (case run, action notarization) is reported to Stripe's Billing Meter
- Stripe aggregates usage over the billing period
- At the end of the period, overage is invoiced alongside the base subscription
Overage is never charged on the free plan — free users hit a hard wall (HTTP 429) at 100 operations.
Testing
Use Stripe test mode with card 4242 4242 4242 4242 (any future expiry, any CVC). Test webhook events with the Stripe CLI:
stripe listen --forward-to localhost:8001/api/v1/billing/stripe/webhook