> ## Documentation Index
> Fetch the complete documentation index at: https://docs.saasybill.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List plans

> Every plan unless `status` narrows it. What a new subscription can use is `?status=active,draft`.

<Info>Requires the `catalogue:read` scope. See [Authentication](/api-reference/authentication#scopes).</Info>


## OpenAPI

````yaml /api-reference/openapi.json get /v1/plans
openapi: 3.1.0
info:
  title: Saasybill API
  version: 1.0.0
  description: >-
    Create and manage subscriptions in Saasybill from your own platform.


    **Authentication.** `Authorization: Bearer saasybill_live_…`. Create keys
    under Developer Settings.


    **Idempotency.** Send an `Idempotency-Key` on writes. It is required to
    create a subscription.


    **Webhooks.** Saasybill calls your URL when something changes. Events:
    `customer.created`, `customer.updated`, `customer.deleted`,
    `subscription.created`, `subscription.updated`, `subscription.ended`,
    `subscription.restored`, `subscription.deleted`, `invoice.created`,
    `invoice.updated`, `invoice.paid`, `invoice.voided`, `invoice.deleted`,
    `credit_note.created`, `credit_note.updated`, `credit_note.voided`,
    `credit_note.deleted`. Each request is signed: `Saasybill-Signature: t=<unix
    seconds>,v1=<hex>`, where `v1` is `HMAC-SHA256(secret, "<t>.<raw body>")`.
    Reject a `t` more than five minutes old. Deliveries are at-least-once,
    retried for about 20 hours, and unordered: de-duplicate on the event `id`.
    Changes are detected about once a minute, so an event can arrive up to a
    minute late, and changes inside one minute are combined.


    **Testing.** Create a sandbox under Developer Settings → Configuration,
    connect it to a Xero Demo Company, and use a test key (`saasybill_test_…`)
    created inside it. A test key works only in its sandbox, which sends no
    emails and is never billed. Your plans, customers and subscriptions can be
    copied into the sandbox when it is created or reset, and its test clock can
    be advanced to see renewals without waiting. `GET /v1/organisation` returns
    `livemode: false` for a sandbox.
servers:
  - url: https://api.saasybill.com
    description: Production
security: []
tags:
  - name: Organisation
    description: The organisation an API key belongs to.
  - name: Customers
    description: >-
      Customers are synced from Xero. Create one only where the organisation
      allows it.
  - name: Plans
    description: Read the pricing plans you can sell.
  - name: Charges
    description: Read the one-off fees that can be added to a new subscription.
  - name: Subscriptions
    description: Create subscriptions, change units, and end or restore them.
  - name: Invoices
    description: Read the invoices Saasybill raises in Xero.
  - name: Credit notes
    description: >-
      Read the credit notes Saasybill raises in Xero, and where their credit was
      applied.
  - name: Usage
    description: Report the usage that is billed in arrears against a subscription.
paths:
  /v1/plans:
    get:
      tags:
        - Plans
      summary: List plans
      description: >-
        Every plan unless `status` narrows it. What a new subscription can use
        is `?status=active,draft`.
      operationId: get_v1_plans
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: starting_after
          in: query
          description: The id of the last object on the previous page.
          schema:
            type: string
        - name: code
          in: query
          description: The plan's code.
          schema:
            type: string
        - name: status
          in: query
          description: Only these statuses, comma-separated. Every status when left out.
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              enum:
                - draft
                - active
                - inactive
                - legacy
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        object:
                          type: string
                          const: plan
                        code:
                          type: string
                        name:
                          type: string
                        type:
                          type: string
                          enum:
                            - flat_fee
                            - per_unit
                            - tiered
                            - volume
                            - stairstep
                            - no_base_fee
                          description: >-
                            How the plan's recurring fee is priced.
                            `no_base_fee` is a plan with no recurring fee, which
                            bills only its usage: its `price` is 0 and it has no
                            units.
                        interval:
                          type: object
                          properties:
                            unit:
                              type: string
                              enum:
                                - day
                                - week
                                - month
                                - year
                            count:
                              type: integer
                          required:
                            - unit
                            - count
                          additionalProperties: false
                        currency:
                          type: string
                        price:
                          type: string
                          description: A decimal string, e.g. "19.9900".
                        minimum_units:
                          type: integer
                        free_units:
                          type: integer
                        unit_labels:
                          type: object
                          properties:
                            singular:
                              type:
                                - string
                                - 'null'
                            plural:
                              type:
                                - string
                                - 'null'
                          required:
                            - singular
                            - plural
                          additionalProperties: false
                        allows_price_override:
                          type: boolean
                        status:
                          type: string
                          enum:
                            - draft
                            - active
                            - inactive
                            - legacy
                        tiers:
                          type: array
                          items:
                            type: object
                            properties:
                              from_units:
                                type: integer
                              to_units:
                                anyOf:
                                  - type: integer
                                  - type: 'null'
                              price:
                                type: string
                                description: A decimal string, e.g. "19.9900".
                            required:
                              - from_units
                              - to_units
                              - price
                            additionalProperties: false
                        meters:
                          type: array
                          items:
                            type: object
                            properties:
                              meter:
                                type: string
                                description: The Saasybill meter id.
                              meter_code:
                                type: string
                                description: >-
                                  The meter's ID as shown in Saasybill. What
                                  `POST /v1/usage_events` takes.
                              name:
                                type: string
                              unit_labels:
                                type: object
                                properties:
                                  singular:
                                    type:
                                      - string
                                      - 'null'
                                  plural:
                                    type:
                                      - string
                                      - 'null'
                                required:
                                  - singular
                                  - plural
                                additionalProperties: false
                                description: What one unit of this meter is called.
                              pricing_model:
                                type: string
                                enum:
                                  - per_unit
                                  - tiered
                                  - volume
                                  - stairstep
                              price:
                                anyOf:
                                  - type: string
                                    description: A decimal string, e.g. "19.9900".
                                  - type: 'null'
                                description: >-
                                  The rate per unit. Only for `per_unit`; null
                                  when the meter prices from `tiers`.
                              included_units:
                                anyOf:
                                  - type: integer
                                  - type: 'null'
                                description: >-
                                  Units included before charging starts. Only
                                  for `per_unit`; a tiered model includes some
                                  by making its first band free.
                              minimum_units:
                                type: integer
                                description: >-
                                  The least a period bills for this meter: a
                                  period bills the larger of what was reported
                                  and this, before the pricing. 0 is none. A
                                  subscription may raise it for itself.
                              tiers:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    from_units:
                                      type: integer
                                    to_units:
                                      anyOf:
                                        - type: integer
                                        - type: 'null'
                                    price:
                                      type: string
                                      description: >-
                                        The per-unit rate for `tiered` and
                                        `volume`; the band's flat price for
                                        `stairstep`.
                                  required:
                                    - from_units
                                    - to_units
                                    - price
                                  additionalProperties: false
                                description: Empty for `per_unit`.
                            required:
                              - meter
                              - meter_code
                              - name
                              - unit_labels
                              - pricing_model
                              - price
                              - included_units
                              - minimum_units
                              - tiers
                            additionalProperties: false
                          description: >-
                            The meters this plan bills for beside its recurring
                            fee, each priced on its own. Empty for a plan that
                            bills no usage. Usage is billed in arrears, when the
                            subscription's period ends.
                        created:
                          type: string
                          format: date-time
                          description: ISO 8601, UTC.
                      required:
                        - id
                        - object
                        - code
                        - name
                        - type
                        - interval
                        - currency
                        - price
                        - minimum_units
                        - free_units
                        - unit_labels
                        - allows_price_override
                        - status
                        - tiers
                        - meters
                        - created
                      additionalProperties: false
                  has_more:
                    type: boolean
                required:
                  - data
                  - has_more
                additionalProperties: false
              example:
                data:
                  - id: b6c1e0a4-2f7d-4a61-8f0c-5d3e9a7b2c44
                    object: plan
                    code: TEAM-MONTHLY
                    name: Team
                    type: per_unit
                    interval:
                      unit: month
                      count: 1
                    currency: AUD
                    price: '12.0000'
                    minimum_units: 5
                    free_units: 0
                    unit_labels:
                      singular: seat
                      plural: seats
                    allows_price_override: false
                    status: active
                    tiers: []
                    created: '2026-06-02T23:10:44.000Z'
                    meters: []
                has_more: false
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
            RateLimit-Limit:
              $ref: '#/components/headers/RateLimit-Limit'
            RateLimit-Remaining:
              $ref: '#/components/headers/RateLimit-Remaining'
            RateLimit-Reset:
              $ref: '#/components/headers/RateLimit-Reset'
        '401':
          description: The key is missing, malformed, revoked or expired.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: authentication_error
                  code: invalid_api_key
                  message: 'Provide a valid API key as `Authorization: Bearer <key>`.'
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
        '403':
          description: >-
            The key lacks the scope, is a test key, or the organisation has not
            allowed this.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: permission_error
                  code: insufficient_scope
                  message: This API key does not have the `subscriptions:write` scope.
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
        '404':
          description: No such object.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: not_found
                  code: plan_not_found
                  message: There is no plan with that id.
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
        '409':
          description: >-
            The request conflicts with the current state, or with an earlier
            request using the same `Idempotency-Key`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: conflict
                  code: idempotency_conflict
                  message: >-
                    This `Idempotency-Key` was used with a different request.
                    Use a new key for a different request.
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
        '422':
          description: A field is missing or invalid. `error.param` names it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: invalid_request_error
                  code: invalid_parameter
                  message: '`units`: Invalid input: expected number, received string'
                  param: units
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
        '429':
          description: 'Rate limited: 120 requests a minute per key. See `Retry-After`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: rate_limit_error
                  code: rate_limited
                  message: Too many requests. Try again in 12 seconds.
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
        '500':
          description: >-
            Something went wrong on our side. Retry; quote `error.request_id` if
            it persists.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: api_error
                  code: internal_error
                  message: >-
                    Something went wrong on our side. Retry the request; if it
                    keeps failing, quote the request id.
                  request_id: req_4f1a9c2e7b8d3a605e1c9f02
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
      security:
        - bearerAuth:
            - catalogue:read
components:
  headers:
    Request-Id:
      description: A unique id for the request. Quote it when you contact support.
      schema:
        type: string
        example: req_4f1a9c2e7b8d3a605e1c9f02
    RateLimit-Limit:
      description: Requests allowed per minute for this key.
      schema:
        type: integer
        example: 120
    RateLimit-Remaining:
      description: Requests left in the current window.
      schema:
        type: integer
        example: 117
    RateLimit-Reset:
      description: Seconds until the oldest counted request stops counting.
      schema:
        type: integer
        example: 41
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              type: string
              enum:
                - authentication_error
                - permission_error
                - invalid_request_error
                - not_found
                - conflict
                - rate_limit_error
                - api_error
            code:
              type: string
              description: Stable. Branch on this, never on `message`.
            message:
              type: string
            param:
              type: string
            request_id:
              type: string
          required:
            - type
            - code
            - message
            - request_id
          additionalProperties: false
      required:
        - error
      additionalProperties: false
      description: >-
        Every failed request answers with this shape. Branch on `error.code`,
        never on `error.message`.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key. Its scopes decide what it may call: `customers:read` (List
        and look up customers.) `customers:write` (Create customers, and Xero
        contacts where the organisation allows it.) `catalogue:read` (List plans
        and charges.) `subscriptions:read` (List and look up subscriptions.)
        `subscriptions:write` (Create subscriptions, change units, end and
        restore them.) `invoices:read` (List and look up invoices.)
        `credit_notes:read` (List and look up credit notes, and where their
        credit was applied.)

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.