ASAP Billing API

Stripe checkout, subscription state, customer portal, and webhook receiver.

Operations 17

POST /v1/billing/checkout-session POST /v1/billing/checkout-session #
GET /v1/billing/invoices GET /v1/billing/invoices #
GET /v1/billing/payment-methods GET /v1/billing/payment-methods #
POST /v1/billing/payment-methods/default POST /v1/billing/payment-methods/default #
DELETE /v1/billing/payment-methods/{id} DELETE /v1/billing/payment-methods/{id} #
POST /v1/billing/portal-session POST /v1/billing/portal-session #
POST /v1/billing/setup-intent POST /v1/billing/setup-intent #
GET /v1/billing/subscription GET /v1/billing/subscription #
POST /v1/billing/subscription POST /v1/billing/subscription #
PATCH /v1/billing/subscription PATCH /v1/billing/subscription #
POST /v1/billing/subscription/cancel POST /v1/billing/subscription/cancel #
GET /v1/billing/subscription/preview GET /v1/billing/subscription/preview #
POST /v1/billing/subscription/reactivate POST /v1/billing/subscription/reactivate #
GET /v1/pricing GET /v1/pricing #
POST /v1/stripe/connect/webhook `POST /v1/stripe/connect/webhook` #
POST /v1/stripe/webhook `POST /v1/stripe/webhook` #
GET /v1/usage GET /v1/usage #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • 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.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/asap-cool:asap-cool-billing-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API 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 Specification

asap-cool-billing-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: ASAP Platform Billing API
  description: 'Public HTTP API for ASAP Platform (api.asap.cool).


    All `/v1` responses are wrapped in a standard envelope. Success responses are `{ "data": , "meta": { "request_id", "next_cursor"?, "has_more"? } }` — the schema documented for each operation describes the inner `data` value. Errors are `{ "error": { "code", "message", "field"?, "request_id" } }`. Every response also carries an `X-Request-Id` header matching `meta.request_id` / `error.request_id`.'
  license:
    name: BUSL-1.1
  version: 0.0.0
servers:
- url: https://api.asap.cool
  description: Production
tags:
- name: Billing
  description: Stripe checkout, subscription state, customer portal, and webhook receiver.
paths:
  /v1/billing/checkout-session:
    post:
      tags:
      - Billing
      summary: POST /v1/billing/checkout-session
      operationId: create_checkout_session
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CheckoutSessionRequest'
        required: true
      responses:
        '200':
          description: Stripe Checkout URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RedirectResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: '`success_url` or `cancel_url` is not on the application origin (`invalid_redirect_url`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: Stripe is not configured, or no Stripe price resolved for the requested plan/interval.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/invoices:
    get:
      tags:
      - Billing
      summary: GET /v1/billing/invoices
      operationId: list_invoices
      responses:
        '200':
          description: Invoices for the active org, most recent first.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/InvoiceView'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '403':
          description: API key lacks the billing:read scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/payment-methods:
    get:
      tags:
      - Billing
      summary: GET /v1/billing/payment-methods
      operationId: list_payment_methods
      responses:
        '200':
          description: Card payment methods attached to the org's Stripe customer.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PaymentMethodView'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/payment-methods/default:
    post:
      tags:
      - Billing
      summary: POST /v1/billing/payment-methods/default
      operationId: set_default_payment_method
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetDefaultPaymentMethodRequest'
        required: true
      responses:
        '204':
          description: Default payment method updated.
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No billing customer for the org.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/payment-methods/{id}:
    delete:
      tags:
      - Billing
      summary: DELETE /v1/billing/payment-methods/{id}
      operationId: detach_payment_method
      parameters:
      - name: id
        in: path
        description: Stripe payment method id (pm_…).
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Payment method detached.
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '409':
          description: Method is still set as default for an active subscription.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/portal-session:
    post:
      tags:
      - Billing
      summary: POST /v1/billing/portal-session
      operationId: create_portal_session
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PortalSessionRequest'
        required: true
      responses:
        '200':
          description: Stripe Customer Portal URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RedirectResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No Stripe customer for the active org.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: '`return_url` is not on the application origin (`invalid_redirect_url`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: Stripe is not configured.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/setup-intent:
    post:
      tags:
      - Billing
      summary: POST /v1/billing/setup-intent
      operationId: create_setup_intent
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetupIntentRequest'
        required: true
      responses:
        '200':
          description: Stripe SetupIntent client secret.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SetupIntentResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/subscription:
    get:
      tags:
      - Billing
      summary: GET /v1/billing/subscription
      operationId: get_subscription
      responses:
        '200':
          description: 'Subscription view, with `plan: starter` when no row exists.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionView'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '403':
          description: API key lacks the billing:read scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
    post:
      tags:
      - Billing
      summary: POST /v1/billing/subscription
      operationId: create_subscription
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSubscriptionRequest'
        required: true
      responses:
        '200':
          description: Created subscription.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateSubscriptionResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '409':
          description: Org already has an active subscription.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: Promotion code is unknown or inactive.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: No Stripe price resolved for the requested plan/interval.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
    patch:
      tags:
      - Billing
      summary: PATCH /v1/billing/subscription
      operationId: change_subscription_plan
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChangePlanRequest'
        required: true
      responses:
        '200':
          description: Plan changed with proration applied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChangePlanResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No subscription to update.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: No Stripe price resolved for the requested plan/interval.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/subscription/cancel:
    post:
      tags:
      - Billing
      summary: POST /v1/billing/subscription/cancel
      operationId: cancel_subscription
      responses:
        '200':
          description: Cancellation scheduled at period end.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No subscription to cancel.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/subscription/preview:
    get:
      tags:
      - Billing
      summary: GET /v1/billing/subscription/preview
      operationId: preview_subscription_change
      parameters:
      - name: plan
        in: query
        description: Target plan slug (solo|studio; the retired pro|business are still accepted).
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Proration preview for the requested plan swap.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PreviewResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No subscription to preview against.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: No Stripe price resolved for the requested plan/interval.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/billing/subscription/reactivate:
    post:
      tags:
      - Billing
      summary: POST /v1/billing/subscription/reactivate
      operationId: reactivate_subscription
      responses:
        '200':
          description: Pending cancellation removed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChangePlanResponse'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No subscription to reactivate.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
  /v1/pricing:
    get:
      tags:
      - Billing
      summary: GET /v1/pricing
      operationId: get_pricing
      responses:
        '200':
          description: 'The plan grid: prices from Stripe, ceilings and features from the plan tables.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PricingView'
  /v1/stripe/connect/webhook:
    post:
      tags:
      - Billing
      summary: '`POST /v1/stripe/connect/webhook`'
      description: 'Returns `200` on success, duplicate replay and every deliberate skip

        (unknown account, foreign document, non-payment mode); `400` on signature

        failure; `503` when Stripe is not configured; `500` (with the idempotency

        key rolled back) on a reconciliation DB failure so Stripe retries.'
      operationId: stripeConnectWebhook
      requestBody:
        description: Raw Stripe Connect event payload (signature-verified before parsing).
        content:
          application/json: {}
      responses:
        '200':
          description: Event processed, replayed, or deliberately ignored.
        '400':
          description: Missing or invalid Stripe-Signature header.
        '503':
          description: Stripe is not configured on this instance.
  /v1/stripe/webhook:
    post:
      tags:
      - Billing
      summary: '`POST /v1/stripe/webhook`'
      description: 'Returns `200 OK` on success and on duplicate replays, `400` on

        signature failure, `503` when Stripe is not configured.'
      operationId: stripeWebhook
      requestBody:
        description: Raw Stripe event payload (signature-verified before parsing).
        content:
          application/json: {}
      responses:
        '200':
          description: Event processed (or replayed).
        '400':
          description: Missing or invalid Stripe-Signature header.
        '503':
          description: Stripe is not configured on this instance.
  /v1/usage:
    get:
      tags:
      - Billing
      summary: GET /v1/usage
      operationId: get_usage
      responses:
        '200':
          description: Plan limits and current usage for the active org.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UsageView'
        '401':
          description: Caller is not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
components:
  schemas:
    CeilingView:
      type: object
      description: One quota ceiling of a plan.
      required:
      - dimension
      properties:
        dimension:
          type: string
          description: Dimension slug (`contacts`, `invoices_finalized_monthly`, …).
        limit:
          type:
          - integer
          - 'null'
          format: int64
          description: The ceiling, or `null` when the plan grants this unlimited.
    CheckoutPlan:
      type: string
      description: Wire-format plan slug accepted by checkout.
      enum:
      - solo
      - studio
    RedirectResponse:
      type: object
      description: 'Response payload for `POST /v1/billing/checkout-session` and

        `POST /v1/billing/portal-session`.'
      required:
      - url
      properties:
        url:
          type: string
          description: Hosted URL the SPA should navigate to.
    SetupIntentRequest:
      type: object
      description: JSON body of `POST /v1/billing/setup-intent`.
      required:
      - email
      properties:
        email:
          type: string
          description: Email used to seed the Stripe customer when none exists yet.
    ErrorBody:
      type: object
      description: 'Generic error body returned by API handlers when they fail. `code` is a

        stable machine-readable token; `message` is human-friendly and meant for

        surfacing to end users.'
      required:
      - code
      - message
      properties:
        code:
          type: string
          description: Stable machine token (e.g. `invalid_credentials`).
        field:
          type:
          - string
          - 'null'
          description: Offending request field for validation errors, when known.
        message:
          type: string
          description: Human-readable message.
    InvoiceView:
      type: object
      description: One invoice row returned by `GET /v1/billing/invoices`.
      required:
      - id
      - status
      - amount_due_cents
      - amount_paid_cents
      - currency
      - created
      properties:
        amount_due_cents:
          type: integer
          format: int64
          description: Amount due in the smallest currency unit (cents).
        amount_paid_cents:
          type: integer
          format: int64
          description: Amount paid in the smallest currency unit (cents).
        created:
          type: integer
          format: int64
          description: Issue date as a Unix timestamp (seconds).
        currency:
          type: string
          description: ISO 4217 currency code (lowercase).
        hosted_invoice_url:
          type:
          - string
          - 'null'
          description: Stripe-hosted invoice URL, present once finalized.
        id:
          type: string
          description: Stripe invoice id (`in_…`).
        status:
          type: string
          description: Lifecycle status (`draft`, `open`, `paid`, `void`, `uncollectible`).
    PreviewResponse:
      type: object
      description: Response of `GET /v1/billing/subscription/preview`.
      required:
      - amount_due_cents
      - currency
      - next_invoice_at
      - proration_lines
      properties:
        amount_due_cents:
          type: integer
          format: int64
          description: Total to charge immediately, in cents.
        currency:
          type: string
          description: ISO 4217 lowercase currency.
        next_invoice_at:
          type: integer
          format: int64
          description: Next invoice timestamp (seconds).
        proration_lines:
          type: array
          items:
            $ref: '#/components/schemas/ProrationLineView'
          description: Per-line breakdown of the proration.
    BillingIntervalWire:
      type: string
      description: 'Billing cadence accepted by checkout and plan changes. Absent means

        monthly, so a client that predates the annual offer is unaffected.'
      enum:
      - month
      - year
    LimitView:
      type: object
      description: One quota dimension in the usage view.
      required:
      - dimension
      properties:
        dimension:
          type: string
          description: Dimension slug (`contacts`, `ai_credits_monthly`, …).
        limit:
          type:
          - integer
          - 'null'
          format: int64
          description: Per-plan ceiling, or `null` when the plan grants this unlimited.
        used:
          type:
          - integer
          - 'null'
          format: int64
          description: Current usage, or `null` when not measured yet (module absent).
    PriceView:
      type: object
      description: What a plan costs at one cadence.
      required:
      - amount_cents
      - currency
      properties:
        amount_cents:
          type: integer
          format: int64
          description: Unit amount in the currency's smallest unit — cents, never a float.
        currency:
          type: string
          description: ISO 4217 code, lowercase.
    PlanView:
      type: object
      description: One plan of the grid.
      required:
      - plan
      - ceilings
      - features
      properties:
        ceilings:
          type: array
          items:
            $ref: '#/components/schemas/CeilingView'
          description: Quota ceilings, one per dimension.
        features:
          type: array
          items:
            type: string
          description: Slugs of the gated features this plan includes.
        month:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/PriceView'
            description: 'Monthly price, or `null` when Stripe resolved none (and for Free, which

              is not a Stripe price at all).'
        plan:
          type: string
          description: Plan slug (`starter`, `solo`, `studio`).
        year:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/PriceView'
            description: Yearly price, or `null` when Stripe resolved none.
    SetDefaultPaymentMethodRequest:
      type: object
      description: JSON body of `POST /v1/billing/payment-methods/default`.
      required:
      - payment_method_id
      properties:
        payment_method_id:
          type: string
          description: '`pm_…` identifier to pin as default for invoices.'
    ChangePlanResponse:
      type: object
      description: Response of `PATCH /v1/billing/subscription`.
      required:
      - subscription_id
      - status
      properties:
        status:
          type: string
          description: Resulting subscription status.
        subscription_id:
          type: string
          description: Stripe `sub_…` identifier (unchanged across plan swaps).
    PortalSessionRequest:
      type: object
      description: JSON body of `POST /v1/billing/portal-session`.
      required:
      - return_url
      properties:
        return_url:
          type: string
          description: URL Stripe redirects to once the user leaves the portal; must be on the application origin.
    SetupIntentResponse:
      type: object
      description: Response of `POST /v1/billing/setup-intent`.
      required:
      - client_secret
      properties:
        client_secret:
          type: string
          description: Short-lived secret consumed by `<PaymentElement>` to confirm a card.
    PricingView:
      type: object
      description: Response of `GET /v1/pricing`.
      required:
      - plans
      properties:
        plans:
          type: array
          items:
            $ref: '#/components/schemas/PlanView'
          description: The three plans, cheapest first.
    UsageView:
      type: object
      description: Response for `GET /v1/usage`.
      required:
      - plan
      - limits
      properties:
        limits:
          type: array
          items:
            $ref: '#/components/schemas/LimitView'
          description: Per-dimension limits and usage.
        plan:
          type: string
          description: Resolved plan slug (`starter`, `solo`, `studio`).
    ProrationLineView:
      type: object
      description: One line of a proration preview.
      required:
      - description
      - amount_cents
      properties:
        amount_cents:
          type: integer
          format: int64
          description: Signed amount in cents (positive = charge, negative = credit).
        description:
          type: string
          description: Human-readable description from Stripe.
    CheckoutSessionRequest:
      type: object
      description: JSON body of `POST /v1/billing/checkout-session`.
      required:
      - plan
      - success_url
      - cancel_url
      - email
      properties:
        cancel_url:
          type: string
          description: URL Stripe redirects to on cancel/back; must be on the application origin.
        email:
          type: string
          description: 'Email used to seed the Stripe customer when none exists yet.

            Caller is expected to send the org owner''s email.'
        interval:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/BillingIntervalWire'
            description: Billing cadence (`month` / `year`); defaults to monthly.
        plan:
          $ref: '#/components/schemas/CheckoutPlan'
          description: Target plan.
        success_url:
          type: string
          description: URL Stripe redirects to on success; must be on the application origin.
    CancelResponse:
      type: object
      description: Response of `POST /v1/billing/subscription/cancel`.
      required:
      - cancel_at
      properties:
        cancel_at:
          type: integer
          format: int64
          description: Unix timestamp at which access ends (end of current period).
    CreateSubscriptionRequest:
      type: object
      description: JSON body of `POST /v1/billing/subscription`.
      required:
      - plan
      - payment_method_id
      properties:
        interval:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/BillingIntervalWire'
            description: Billing cadence (`month` / `year`); defaults to monthly.
        payment_method_id:
          type: string
          description: '`pm_…` identifier of the card to charge.'
        plan:
          $ref: '#/components/schemas/CheckoutPlan'
          description: Target plan slug.
        promotion_code:
          type:
          - string
          - 'null'
          description: 'Optional customer-facing promotion code (e.g. `BIENVENUE8`). When

            set and valid, the discount applies to the first invoice; an

            unknown or inactive code is rejected with 422 before any charge.'
    ChangePlanRequest:
      type: object
      description: JSON body of `PATCH /v1/billing/subscription`.
      required:
      - plan
      properties:
        interval:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/BillingIntervalWire'
            description: Billing cadence (`month` / `year`); defaults to monthly.
        plan:
          $ref: '#/components/schemas/CheckoutPlan'
          description: New plan slug.
    PaymentMethodView:
      type: object
      description: One row in `GET /v1/billing/payment-methods`.
      required:
      - id
      - last4
      - brand
      - exp_month
      - exp_year
      - is_default
      properties:
        brand:
          type: string
          description: Brand (`visa`, `mastercard`, …).
        exp_month:
          type: integer
          format: int32
          description: Expiration month (1–12).
          minimum: 0
        exp_year:
          type: integer
          format: int32
          description: Expiration year (four digits).
          minimum: 0
        id:
          type: string
          description: Stripe `pm_…` identifier.
        is_default:
          type: boolean
          description: Whether this method is the customer's default for invoices.
        last4:
          type: string
          description: Last four digits.
    SubscriptionView:
      type: object
      description: Subscription view returned by `GET /v1/billing/subscription`.
      required:
      - plan
      - cancel_at_period_end
      properties:
        cancel_at_period_end:
          type: boolean
          description: '`true` when the user has scheduled an end-of-period cancellation.'
        card:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/CardView'
            description: Card on file, when one has been captured.
        current_period_end:
          type:
          - integer
          - 'null'
          format: int64
          description: '`current_period_end` as a Unix timestamp (seconds), when known.'
        plan:
          type: string
          description: Resolved plan slug (`starter`, `solo`, `studio`).
        status:
          type:
          - string
          - 'null'
          description: Stripe subscription status as a lowercase string, when a row exists.
        trial_end:
          type:
          - integer
          - 'null'
          format: int64
          description: 'End of the trial as a Unix timestamp (seconds), when in trial: a

            Stripe trial, or the 14-day reverse trial every new org starts with

            (`status` is then absent and `plan` is `solo`).'
    CardView:
      type: object
      description: Card on file as exposed by `GET /v1/billing/subscription`.
      required:
      - brand
      - last4
      - exp_month
      - exp_year
      properties:
        brand:
          type: string
          description: Card brand (`visa`, `mastercard`, …).
        exp_month:
          type: integer
          format: int32
          description: Expiration month (1–12).
        exp_year:
          type: integer
          format: int32
          description: Expiration year (four digits).
        last4:
          type: string
          description: Last four digits.
    CreateSubscriptionResponse:
      type: object
      description: Response of `POST /v1/billing/subscription`.
      required:
      - subscription_id
      - status
      properties:
        requires_action_client_secret:
          type:
          - string
          - 'null'
          description: Set when 3DS confirmation is required — pass to `confirmCardPayment`.
        status:
          type: string
          description: Subscription status (`active`, `incomplete`, …).
        subscription_id:
          type: string
          description: Stripe `sub_…` identifier.
  securitySchemes:
    api_key:
      type: http
      scheme: bearer
    session:
      type: apiKey
      in: cookie
      name: asap_session