Skip to content
Documentation navigation +
betaMay change before the API is declared stable.

Credit purchases

One-time USD credit packs are implemented behind ALIVE_BILLING_ENABLED=false by default. There are no built-in monetary prices. The operator binds an approved Stripe price to an integer credit entitlement. Organization purchases and verified sponsor-program pool funding use the same payment boundary. This is a code candidate, not a verified hosted payment offering.

Paid subscriptions, automated cash refunds/disputes, broader enrollment abuse controls and real Stripe test/live acceptance remain pending. Existing plan/quota records are not a paid subscription integration. Isaac must approve the billing terms/rates and applicable statements before activation, as required by the repository's instructions.

Endpoints

Operation Contract
GET /v1/billing/packs Authenticated catalog: configured keys/titles/credits and actual Stripe USD price amounts; includes live_mode.
POST /v1/billing/checkout {pack_key, org_id} or {pack_key, program_id}; exactly one owner; Idempotency-Key required. Returns intent/session ids, URL and expiry.
GET /v1/billing/purchases/{intent_id} Authorized owner/admin inspection; pending/completed/failed/refunded state and confirmed ledger transaction when available.
POST /v1/billing/stripe/webhook Stripe-signed snapshot events; no Alive bearer token. Not an endpoint for developers to invent payment events.

Purchases require a signed-in user session with organization admin/owner authority. API tokens cannot initiate payment. Program funding additionally requires an assigned institution admin, operator verification and an unclosed/unexpired program. Draft programs can be funded before activation; funding does not approve beneficiaries or allocate to them. Historical purchase inspection remains possible after program closure/expiry.

Confirmation and retry behavior

Before creating Checkout, the API stores the exact owner, price id, actual amount/currency, credits, environment, expiry and return URL in a service-only intent. The caller cannot supply credits, price, amount or redirect URLs. The provider idempotency key derives from that intent. Concurrent retries with the same owner/key/body create one intended session; changed bodies return IDEMPOTENCY_KEY_REUSED. Billing has its own owner/key namespace.

Stripe is retrieved with expanded line items on confirmation. Its mode/environment, intent identity, one-unit price, amount and currency must match the saved intent. Only a paid session can issue credits. Event recording, purchase completion and ledger issuance commit together. Repeated events or sessions cannot issue a second grant. A callback can recover an intent even if the API failed before saving the session response.

An unpaid asynchronous payment stays pending. Paid async success can complete it; async failure or expiration marks a pending purchase failed. Failed/refunded terminal purchases cannot be resurrected by a late completion. Such conflicts require operator investigation, not a new grant. Unknown sessions without an Alive intent are ignored. Unrelated events are ignored.

Supported events: checkout.session.completed, checkout.session.async_payment_succeeded, checkout.session.async_payment_failed, checkout.session.expired. Configure snapshot payloads for the pinned SDK API version 2026-09-30.endive. Signature verification uses the unmodified body and Stripe's default timestamp tolerance. The event body is limited to 1 MiB after reading; the deployment must also enforce request-size limits at the ingress.

Checkout links expire after one hour. Ten new intents per owner per rolling hour are allowed; unchanged retries do not consume that count. An expired intent cannot create a replacement session. Inspect/reconcile it before intentionally starting another purchase with a new key. Do not infer failure from a browser close or from a missing webhook.

Stripe guidance: Checkout fulfillment and webhook verification. Implementation follows paid-session confirmation; a redirect alone does not establish payment.

App behavior and records

When configured, Settings exposes packs for organization administrators; program pages expose pool funding. The browser saves the intent/retry key locally, opens Stripe and provides a payment-status check on return. Returning/canceling does not grant credits. Unchanged retries retain their key; confirmed completion refreshes the recorded state. Reload to refresh balances. Each organization/program remains a separate owner; no recipient credit transfer/resale is added.

Saved operational records contain intent/session ids, entitlement, money amount/currency, owner/creator ids, status and ledger/audit references. The webhook record stores a small session/intent/status summary rather than the full Stripe customer/payment payload. Stripe handles its hosted checkout data. Data-handling terms and production access remain review gates; this record shape is not a privacy certification.

Errors and limitations

  • BILLING_NOT_CONFIGURED (503): disabled or configured price is not active, fixed, one-time USD in the intended mode. Production configuration also requires live mode and HTTPS return URL.
  • PAYMENT_PROVIDER_ERROR (502): ambiguous provider failure; keep the same body/key for retry. It does not assert that a payment failed or that no charge exists.
  • APPROVAL_REQUIRED (409): institution verification missing.
  • CONFLICT (409): closed/expired program, expired checkout, mismatched payment or intent limit.
  • VALIDATION_FAILED (422): malformed owner/body or invalid event signature/environment.
  • Standard auth/role/idempotency errors: errors and limits.

No discounts, dynamic quantities, multi-currency checkout, subscriptions, automatic prorations or cash-refund API are offered in this checkpoint. Do not manually issue compensating credits and also replay a paid session. Refund/dispute entitlement handling requires an approved policy and implementation before accepting real money. See the operator setup how-to.