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

# Preview Plan Change

> The proration a plan change would produce — credit for unused time, prorated charge, tax, and the next invoice amount — computed with the same math as the update, without applying it.

Returns the proration breakdown for switching a subscription to another plan
**before** anything is charged or persisted. It runs the exact function
[`PUT /v1/subscriptions/{id}`](/api-reference/subscriptions/update) uses, so
the preview matches the invoice or credit note the real change would post.
The plan must exist in your tenant — see
[Get Plan](/api-reference/plans/get).

All amounts are minor units in the subscription's currency.

## Query Parameters

| Parameter | Type          | Required | Description                       |
| --------- | ------------- | -------- | --------------------------------- |
| `plan_id` | string (uuid) | Yes      | The plan to preview switching to. |

## Example Request

```bash theme={null}
curl "https://api.recurso.dev/v1/subscriptions/b9071c55-0e14-4720-80f3-665613ceb7de/preview-change?plan_id=2f4d1a6e-8c3b-4e77-9a10-5d6b7c8e9f01" \
  -H "Authorization: Bearer $API_KEY"
```

## Response

```json theme={null}
{
  "data": {
    "subscription_id": "b9071c55-0e14-4720-80f3-665613ceb7de",
    "current_plan_id": "7c0e2b91-3f5a-4d8c-a2b4-1e9f0d6c5a83",
    "new_plan_id": "2f4d1a6e-8c3b-4e77-9a10-5d6b7c8e9f01",
    "currency": "INR",
    "credit_amount": 45161,
    "charge_amount": 96774,
    "net_amount": 51613,
    "tax_amount": 9290,
    "total_amount": 60903,
    "effective_date": "2026-09-04T10:30:00Z",
    "next_invoice_amount": 236000,
    "is_upgrade": true
  }
}
```

## Fields

| Field                 | Type               | Description                                                                                                                                                                                                                                                                                  |
| --------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `subscription_id`     | string (uuid)      | The subscription previewed                                                                                                                                                                                                                                                                   |
| `current_plan_id`     | string (uuid)      | The plan the subscription is on today                                                                                                                                                                                                                                                        |
| `new_plan_id`         | string (uuid)      | The plan passed as `plan_id`                                                                                                                                                                                                                                                                 |
| `currency`            | string             | Currency of every amount below                                                                                                                                                                                                                                                               |
| `credit_amount`       | integer (int64)    | Credit for unused time on the current plan, minor units                                                                                                                                                                                                                                      |
| `charge_amount`       | integer (int64)    | Prorated charge for the remaining period on the new plan, minor units                                                                                                                                                                                                                        |
| `net_amount`          | integer (int64)    | `charge_amount - credit_amount`, before tax                                                                                                                                                                                                                                                  |
| `tax_amount`          | integer (int64)    | Tax netted across both sides: GST collected on the new-plan charge (at the new plan's rate/HSN) minus GST reversed on the old-plan credit (at the old plan's rate/HSN). Positive on an upgrade, negative on a downgrade credit; equals tax on `net_amount` only when both plans share a rate |
| `total_amount`        | integer (int64)    | `net_amount + tax_amount` — the immediate proration invoice total (positive) or credit (negative)                                                                                                                                                                                            |
| `effective_date`      | string (date-time) | When the change would take effect (now)                                                                                                                                                                                                                                                      |
| `next_invoice_amount` | integer (int64)    | Full new-plan charge including tax at the next renewal                                                                                                                                                                                                                                       |
| `is_upgrade`          | boolean            | `true` when the new plan costs more than the current one                                                                                                                                                                                                                                     |

<Note>
  Read-only and side-effect free — no invoice, credit note, or ledger entry is
  created. Apply the change with
  [Update Subscription](/api-reference/subscriptions/update).
</Note>

## Errors

| Status | Code                | When                                                                                                  | Fix                                                                               |
| ------ | ------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| 400    | `validation_failed` | `id` is not a valid UUID, `plan_id` is missing, or `plan_id` is not a valid UUID.                     | Pass the subscription's UUID in the path and the target plan's UUID as `plan_id`. |
| 401    | `unauthorized`      | API key missing or invalid (`invalid_api_key`), or a live/test mode mismatch (`key_mode_mismatch`).   | Send `Authorization: Bearer <api_key>` with a key for the right mode.             |
| 404    | `not_found`         | The subscription or the target plan does not exist in your tenant (cross-tenant IDs also return 404). | Verify both IDs with `GET /v1/subscriptions/{id}` and `GET /v1/plans/{id}`.       |

Errors use the standard envelope — see [Errors](/api-reference/errors).


## OpenAPI

````yaml GET /v1/subscriptions/{id}/preview-change
openapi: 3.1.0
info:
  title: Recurso API
  version: 1.0.0
  description: |
    The Recurso billing engine REST API.

    Authenticate by passing your API key as a bearer token:

        Authorization: Bearer <api_key>

    Obtain an API key by registering a tenant via `POST /auth/register`.
    All authenticated endpoints live under the `/v1` prefix. Mutating
    endpoints support idempotency via the `Idempotency-Key` header.
  license:
    name: MIT
    identifier: MIT
servers:
  - url: https://billing.example.com
    description: >-
      Example deployment — substitute the base URL of your own Recurso
      deployment.
security:
  - bearerAuth: []
tags:
  - name: System
    description: Health, version, and API metadata
  - name: Auth
    description: Tenant registration
  - name: Plans
    description: Product catalog plans
  - name: Customers
    description: Customer management
  - name: Subscriptions
    description: Subscription lifecycle
  - name: Invoices
    description: Invoices, PDFs, and Indian GST e-invoicing
  - name: Coupons
    description: Discounts
  - name: Usage
    description: Metered usage events
  - name: Credit Notes
    description: Customer credits
  - name: Quotes
    description: Quote-to-invoice lifecycle
  - name: Webhooks
    description: Webhook endpoint management and event feed
  - name: Analytics
    description: Revenue analytics
  - name: Checkout
    description: Public hosted checkout for invoices
  - name: Payments
    description: Payment order creation
  - name: Inbound Webhooks
    description: Receivers for payment-gateway callbacks (Razorpay, Stripe)
  - name: Customer Portal
    description: Customer-facing portal — magic-link auth and session-scoped data
  - name: Developer
    description: API key management
  - name: Account
    description: Tenant account settings
  - name: Finance
    description: Ledger accounts, entries, reconciliation, and revenue recognition
  - name: Settings
    description: Tax (GST) and e-invoicing (IRP) configuration
  - name: Consents
    description: Consent records for RBI-compliant recurring billing
  - name: Referrals
    description: Customer referral program
  - name: Gifts
    description: Gift subscriptions
  - name: Mandates
    description: UPI Autopay mandates
  - name: Offline Payments
    description: Virtual accounts and manually recorded payments
  - name: Organizations
    description: Multi-entity organizations grouping several tenants
  - name: Accounting
    description: QuickBooks / Xero accounting integrations
  - name: Churn
    description: Churn risk scoring and alerts
  - name: Cancel Flows
    description: Configurable retention flows shown at cancellation time
  - name: Dunning
    description: Dunning analytics and multi-channel dunning campaigns
paths:
  /v1/subscriptions/{id}/preview-change:
    get:
      tags:
        - Subscriptions
      summary: Preview proration for a plan change (nothing is applied)
      description: >-
        Computes the credit for unused time on the current plan, the prorated
        charge for the new plan, the net amount, tax, effective date, and the
        resulting next-invoice amount — using the same proration math as PUT
        /v1/subscriptions/{id}. Nothing is charged or persisted.
      operationId: previewPlanChange
      parameters:
        - $ref: '#/components/parameters/PathID'
        - name: plan_id
          in: query
          required: true
          description: The plan to preview switching to.
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Proration breakdown.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PlanChangePreview'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    PathID:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid
  schemas:
    PlanChangePreview:
      type: object
      description: >-
        Read-only proration breakdown for a subscription plan change. Monetary
        fields are in the currency's smallest unit (e.g. paise/cents).
      properties:
        subscription_id:
          type: string
          format: uuid
        current_plan_id:
          type: string
          format: uuid
        new_plan_id:
          type: string
          format: uuid
        currency:
          type: string
        credit_amount:
          type: integer
          format: int64
          description: Credit for unused time on the current plan.
        charge_amount:
          type: integer
          format: int64
          description: Prorated charge for the remaining period on the new plan.
        net_amount:
          type: integer
          format: int64
          description: charge_amount - credit_amount, before tax.
        tax_amount:
          type: integer
          format: int64
          description: >-
            Tax netted across both sides: GST collected on the new-plan charge
            (at the new plan's rate/HSN) minus GST reversed on the old-plan
            credit (at the old plan's rate/HSN). Positive on an upgrade,
            negative on a downgrade credit.
        total_amount:
          type: integer
          format: int64
          description: net_amount + tax_amount; the immediate proration invoice total.
        effective_date:
          type: string
          format: date-time
        next_invoice_amount:
          type: integer
          format: int64
          description: Full new-plan charge incl. tax at the next renewal.
        is_upgrade:
          type: boolean
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          description: Structured error detail.
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable machine-readable error code.
              examples:
                - validation_failed
                - unauthorized
                - forbidden
                - not_found
                - conflict
                - rate_limited
                - internal_error
                - invalid_api_key
                - key_mode_mismatch
                - over_refund
                - invoice_not_paid
                - invoice_already_paid
            message:
              type: string
              description: Human-readable explanation.
  responses:
    BadRequest:
      description: The request body or parameters are invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid credentials (API key or session cookie).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The requested resource does not exist.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: >-
        Tenant API key obtained from `POST /auth/register` or `POST
        /v1/developer/keys`.

````