> ## 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.

# Change a subscription's units

> Sets the new total. The same classification as the Update Units dialog decides what happens: charged now on an invoice, deferred to the renewal invoice, or credited.

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


## OpenAPI

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


    Every request is authenticated with an API key sent as `Authorization:
    Bearer saasybill_live_…`.

    Writes accept an `Idempotency-Key` header. It is required to create a
    subscription.

    Webhooks, errors, pagination and idempotency are covered in the guides
    alongside this reference.
servers:
  - url: https://app.saasybill.com/api
    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.
paths:
  /v1/subscriptions/{id}/units:
    post:
      tags:
        - Subscriptions
      summary: Change a subscription's units
      description: >-
        Sets the new total. The same classification as the Update Units dialog
        decides what happens: charged now on an invoice, deferred to the renewal
        invoice, or credited.
      operationId: post_v1_subscriptions_id_units
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: 9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33
          description: The Saasybill id of the subscription.
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            1 to 255 printable characters. A retry with the same key and body
            returns the first response.
          schema:
            type: string
            minLength: 1
            maxLength: 255
            example: signup_8f3a2c1d
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                units:
                  type: integer
                  minimum: 0
                  maximum: 999999999
                  description: The new total number of units, not a change.
                prorate:
                  description: Charge or credit for the rest of the period. Default false.
                  type: boolean
                proration_behaviour:
                  type: string
                  enum:
                    - charge_immediately
                    - charge_on_renewal
                effective_date:
                  description: Required to prorate.
                  type: string
                  pattern: ^\d{4}-\d{2}-\d{2}$
                document:
                  description: >-
                    Required exactly when the next period has already been
                    invoiced (inside the invoice window): amend the renewal
                    invoice, or bill the change on its own. Refused otherwise.
                    The error names the choices.
                  type: string
                  enum:
                    - amend
                    - separate
              required:
                - units
              additionalProperties: false
            examples:
              Increase, charged now:
                summary: Increase, charged now
                description: >-
                  Prorate the extra units from the effective date and invoice
                  them straight away.
                value:
                  units: 15
                  prorate: true
                  proration_behaviour: charge_immediately
                  effective_date: '2026-10-08'
              Increase, charged at renewal:
                summary: Increase, charged at renewal
                description: The prorated amount is added to the renewal invoice instead.
                value:
                  units: 15
                  prorate: true
                  proration_behaviour: charge_on_renewal
                  effective_date: '2026-10-08'
              No proration:
                summary: No proration
                description: >-
                  The new total takes effect at renewal, with no document raised
                  now. This is also how a decrease is made.
                value:
                  units: 8
              Inside the invoice window:
                summary: Inside the invoice window
                description: >-
                  The next period has already been invoiced, so document is
                  required: amend the renewal invoice, or bill the change on its
                  own.
                value:
                  units: 15
                  prorate: true
                  effective_date: '2026-10-08'
                  document: amend
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  object:
                    type: string
                    const: subscription
                  customer:
                    type: string
                  customer_code:
                    type:
                      - string
                      - 'null'
                  plan:
                    type: string
                  status:
                    type: string
                    enum:
                      - pending
                      - active
                      - complete
                      - ended
                  currency:
                    type: string
                  interval:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum:
                          - day
                          - week
                          - month
                          - year
                      count:
                        type: integer
                    required:
                      - unit
                      - count
                    additionalProperties: false
                  timezone:
                    type: string
                  start_date:
                    type: string
                    description: YYYY-MM-DD, in the subscription's own timezone.
                  renewal_date:
                    anyOf:
                      - type: string
                        description: YYYY-MM-DD, in the subscription's own timezone.
                      - type: 'null'
                  end_date:
                    anyOf:
                      - type: string
                        description: YYYY-MM-DD, in the subscription's own timezone.
                      - type: 'null'
                  units:
                    type: integer
                  minimum_units:
                    type: integer
                  discount_percent:
                    type: string
                    description: A decimal string, e.g. "19.9900".
                  cancel_at_period_end:
                    type: boolean
                  end_after_cycles:
                    anyOf:
                      - type: integer
                      - type: 'null'
                  label:
                    type:
                      - string
                      - 'null'
                  invoice_reference:
                    type:
                      - string
                      - 'null'
                  renewal_value:
                    type: string
                    description: A decimal string, e.g. "19.9900".
                  created:
                    type: string
                    format: date-time
                    description: ISO 8601, UTC.
                  change:
                    type: object
                    properties:
                      units:
                        type: integer
                      invoice:
                        anyOf:
                          - type: object
                            properties:
                              id:
                                type: string
                              object:
                                type: string
                                const: invoice
                              customer:
                                type: string
                              subscription:
                                type:
                                  - string
                                  - 'null'
                              number:
                                description: Xero's invoice number, once it is in Xero.
                                type:
                                  - string
                                  - 'null'
                              reference:
                                type:
                                  - string
                                  - 'null'
                              status:
                                type: string
                                enum:
                                  - draft
                                  - awaiting_approval
                                  - approved
                                  - paid
                                  - voided
                                  - deleted
                                  - scheduled
                                  - not_in_external
                              currency:
                                type: string
                              invoice_date:
                                type: string
                                format: date-time
                                description: ISO 8601, UTC.
                              due_date:
                                anyOf:
                                  - type: string
                                    format: date-time
                                    description: ISO 8601, UTC.
                                  - type: 'null'
                              subtotal:
                                type: string
                                description: Excluding tax.
                              total:
                                type: string
                                description: Including tax, as Xero returns it.
                              credit_note_amount:
                                type: string
                                description: A decimal string, e.g. "19.9900".
                              amount_paid:
                                anyOf:
                                  - type: string
                                    description: A decimal string, e.g. "19.9900".
                                  - type: 'null'
                              sent:
                                type: boolean
                              xero:
                                type: object
                                properties:
                                  sync_status:
                                    type: string
                                    enum:
                                      - synced
                                      - failed
                                      - pending
                                    description: >-
                                      `failed` means the invoice exists here and
                                      Xero refused it; the subscription that
                                      raised it was still created.
                                  invoice_id:
                                    type:
                                      - string
                                      - 'null'
                                  sync_error:
                                    type:
                                      - string
                                      - 'null'
                                required:
                                  - sync_status
                                  - invoice_id
                                  - sync_error
                                additionalProperties: false
                              lines:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                    type:
                                      anyOf:
                                        - type: string
                                          enum:
                                            - subscription
                                            - addon
                                            - charge
                                        - type: 'null'
                                    name:
                                      type:
                                        - string
                                        - 'null'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                    units:
                                      anyOf:
                                        - type: integer
                                        - type: 'null'
                                    amount:
                                      type: string
                                      description: A decimal string, e.g. "19.9900".
                                    discount_amount:
                                      type: string
                                      description: A decimal string, e.g. "19.9900".
                                    charge_amount:
                                      type: string
                                      description: >-
                                        What is billed: `amount` less
                                        `discount_amount`.
                                    effective_date:
                                      anyOf:
                                        - type: string
                                          format: date-time
                                          description: ISO 8601, UTC.
                                        - type: 'null'
                                  required:
                                    - id
                                    - type
                                    - name
                                    - description
                                    - units
                                    - amount
                                    - discount_amount
                                    - charge_amount
                                    - effective_date
                                  additionalProperties: false
                              created:
                                type: string
                                format: date-time
                                description: ISO 8601, UTC.
                            required:
                              - id
                              - object
                              - customer
                              - subscription
                              - number
                              - reference
                              - status
                              - currency
                              - invoice_date
                              - due_date
                              - subtotal
                              - total
                              - credit_note_amount
                              - amount_paid
                              - sent
                              - xero
                              - created
                            additionalProperties: false
                          - type: 'null'
                      renewal_invoice:
                        anyOf:
                          - type: object
                            properties:
                              id:
                                type: string
                              object:
                                type: string
                                const: invoice
                              customer:
                                type: string
                              subscription:
                                type:
                                  - string
                                  - 'null'
                              number:
                                description: Xero's invoice number, once it is in Xero.
                                type:
                                  - string
                                  - 'null'
                              reference:
                                type:
                                  - string
                                  - 'null'
                              status:
                                type: string
                                enum:
                                  - draft
                                  - awaiting_approval
                                  - approved
                                  - paid
                                  - voided
                                  - deleted
                                  - scheduled
                                  - not_in_external
                              currency:
                                type: string
                              invoice_date:
                                type: string
                                format: date-time
                                description: ISO 8601, UTC.
                              due_date:
                                anyOf:
                                  - type: string
                                    format: date-time
                                    description: ISO 8601, UTC.
                                  - type: 'null'
                              subtotal:
                                type: string
                                description: Excluding tax.
                              total:
                                type: string
                                description: Including tax, as Xero returns it.
                              credit_note_amount:
                                type: string
                                description: A decimal string, e.g. "19.9900".
                              amount_paid:
                                anyOf:
                                  - type: string
                                    description: A decimal string, e.g. "19.9900".
                                  - type: 'null'
                              sent:
                                type: boolean
                              xero:
                                type: object
                                properties:
                                  sync_status:
                                    type: string
                                    enum:
                                      - synced
                                      - failed
                                      - pending
                                    description: >-
                                      `failed` means the invoice exists here and
                                      Xero refused it; the subscription that
                                      raised it was still created.
                                  invoice_id:
                                    type:
                                      - string
                                      - 'null'
                                  sync_error:
                                    type:
                                      - string
                                      - 'null'
                                required:
                                  - sync_status
                                  - invoice_id
                                  - sync_error
                                additionalProperties: false
                              lines:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    id:
                                      type: string
                                    type:
                                      anyOf:
                                        - type: string
                                          enum:
                                            - subscription
                                            - addon
                                            - charge
                                        - type: 'null'
                                    name:
                                      type:
                                        - string
                                        - 'null'
                                    description:
                                      type:
                                        - string
                                        - 'null'
                                    units:
                                      anyOf:
                                        - type: integer
                                        - type: 'null'
                                    amount:
                                      type: string
                                      description: A decimal string, e.g. "19.9900".
                                    discount_amount:
                                      type: string
                                      description: A decimal string, e.g. "19.9900".
                                    charge_amount:
                                      type: string
                                      description: >-
                                        What is billed: `amount` less
                                        `discount_amount`.
                                    effective_date:
                                      anyOf:
                                        - type: string
                                          format: date-time
                                          description: ISO 8601, UTC.
                                        - type: 'null'
                                  required:
                                    - id
                                    - type
                                    - name
                                    - description
                                    - units
                                    - amount
                                    - discount_amount
                                    - charge_amount
                                    - effective_date
                                  additionalProperties: false
                              created:
                                type: string
                                format: date-time
                                description: ISO 8601, UTC.
                            required:
                              - id
                              - object
                              - customer
                              - subscription
                              - number
                              - reference
                              - status
                              - currency
                              - invoice_date
                              - due_date
                              - subtotal
                              - total
                              - credit_note_amount
                              - amount_paid
                              - sent
                              - xero
                              - created
                            additionalProperties: false
                          - type: 'null'
                      deferred_to_renewal:
                        type: boolean
                      credit_note:
                        type:
                          - string
                          - 'null'
                    required:
                      - units
                      - invoice
                      - renewal_invoice
                      - deferred_to_renewal
                      - credit_note
                    additionalProperties: false
                required:
                  - id
                  - object
                  - customer
                  - customer_code
                  - plan
                  - status
                  - currency
                  - interval
                  - timezone
                  - start_date
                  - renewal_date
                  - end_date
                  - units
                  - minimum_units
                  - discount_percent
                  - cancel_at_period_end
                  - end_after_cycles
                  - label
                  - invoice_reference
                  - renewal_value
                  - created
                  - change
                additionalProperties: false
              examples:
                Increase, charged now:
                  summary: Increase, charged now
                  value:
                    id: 9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33
                    object: subscription
                    customer: 3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11
                    customer_code: ACME-001
                    plan: b6c1e0a4-2f7d-4a61-8f0c-5d3e9a7b2c44
                    status: active
                    currency: AUD
                    interval:
                      unit: month
                      count: 1
                    timezone: Australia/Sydney
                    start_date: '2026-09-30'
                    renewal_date: '2026-10-30'
                    end_date: null
                    units: 15
                    minimum_units: 5
                    discount_percent: '10.00'
                    cancel_at_period_end: false
                    end_after_cycles: null
                    label: Acme – Team plan
                    invoice_reference: PO-4471
                    renewal_value: '162.0000'
                    created: '2026-09-30T04:12:00.000Z'
                    change:
                      units: 15
                      invoice:
                        id: 6a9b4d0e-2c37-4f15-8d8a-7e3f1c5b9a01
                        object: invoice
                        customer: 3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11
                        subscription: 9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33
                        number: INV-0043
                        reference: null
                        status: awaiting_approval
                        currency: AUD
                        invoice_date: '2026-09-29T14:00:00.000Z'
                        due_date: '2026-10-29T13:00:00.000Z'
                        subtotal: '39.1900'
                        total: '43.1100'
                        credit_note_amount: '0.0000'
                        amount_paid: null
                        sent: false
                        xero:
                          sync_status: synced
                          invoice_id: f0e9d8c7-b6a5-4f43-9210-fedcba987654
                          sync_error: null
                        lines:
                          - id: 2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e99
                            type: subscription
                            name: Team
                            description: >-
                              Team – 5 additional seats, prorated from 8 Oct
                              2026
                            units: 5
                            amount: '43.5500'
                            discount_amount: '4.3600'
                            charge_amount: '39.1900'
                            effective_date: '2026-10-07T13:00:00.000Z'
                        created: '2026-09-30T04:12:01.000Z'
                      renewal_invoice: null
                      deferred_to_renewal: false
                      credit_note: null
                Increase, charged at renewal:
                  summary: Increase, charged at renewal
                  value:
                    id: 9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33
                    object: subscription
                    customer: 3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11
                    customer_code: ACME-001
                    plan: b6c1e0a4-2f7d-4a61-8f0c-5d3e9a7b2c44
                    status: active
                    currency: AUD
                    interval:
                      unit: month
                      count: 1
                    timezone: Australia/Sydney
                    start_date: '2026-09-30'
                    renewal_date: '2026-10-30'
                    end_date: null
                    units: 15
                    minimum_units: 5
                    discount_percent: '10.00'
                    cancel_at_period_end: false
                    end_after_cycles: null
                    label: Acme – Team plan
                    invoice_reference: PO-4471
                    renewal_value: '162.0000'
                    created: '2026-09-30T04:12:00.000Z'
                    change:
                      units: 15
                      invoice: null
                      renewal_invoice: null
                      deferred_to_renewal: true
                      credit_note: null
                No document raised:
                  summary: No document raised
                  value:
                    id: 9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33
                    object: subscription
                    customer: 3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11
                    customer_code: ACME-001
                    plan: b6c1e0a4-2f7d-4a61-8f0c-5d3e9a7b2c44
                    status: active
                    currency: AUD
                    interval:
                      unit: month
                      count: 1
                    timezone: Australia/Sydney
                    start_date: '2026-09-30'
                    renewal_date: '2026-10-30'
                    end_date: null
                    units: 8
                    minimum_units: 5
                    discount_percent: '10.00'
                    cancel_at_period_end: false
                    end_after_cycles: null
                    label: Acme – Team plan
                    invoice_reference: PO-4471
                    renewal_value: '86.4000'
                    created: '2026-09-30T04:12:00.000Z'
                    change:
                      units: 8
                      invoice: null
                      renewal_invoice: null
                      deferred_to_renewal: false
                      credit_note: null
          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: subscription_not_found
                  message: There is no subscription 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:
            - subscriptions:write
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.)

````