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

# Preview a Stripe migration

> See what moving your Stripe Billing subscribers onto Ledger would import and refuse, without changing anything.

Reads the Stripe account connected to the key's environment and answers what a migration would do. It changes nothing in Stripe or Ledger. [`ledger migrate stripe`](https://docs.integrateledger.com/migrate-from-stripe) runs on it.

* `prices`: each Stripe Price that a subscription Stripe still bills is on, with `openSubscriptions` and `importableSubscriptions`. `ledgerPlanId` is set when the Price is one of your plans' own synced Prices (a subscription Ledger already moved). `refusal` is set when no subscription on it can be imported: `not_monthly`, `metered_price`, a non-USD `price_mismatch`, or a free Price (`plan_not_paid`).
* `subscriptions`: each open subscription, with the Stripe customer's `customerMetadata` (to choose your own customer ID from), the next renewal (`currentPeriodEnd`), `importedAs` when Ledger already holds it, and `refusal`: the code [Import a Stripe subscription](https://docs.integrateledger.com/api-reference/billing/import.md) would answer, or `null` when it would be imported. A customer whose Ledger metadata names another workspace or environment is `stripe_customer_owned_elsewhere`.

The preview runs the import's own checks against a plan priced like the subscription's Price, except two it leaves to the import: pending invoice items, and a Ledger customer that already has a plan. In Sandbox it includes subscriptions on test clocks. It reads up to 1,000 open subscriptions; `truncated: true` means there are more, so migrate these and preview again.

It needs a saved Stripe connection (`502 stripe_not_configured`), but not a healthy webhook, so you can preview before fixing one. The key needs the `customers:read` permission.


## OpenAPI

````yaml openapi.json GET /v1/migrate/stripe/preview
openapi: 3.1.0
info:
  title: Ledger API
  version: 0.1.0
servers:
  - url: https://api.integrateledger.com
    description: Hosted Ledger API
security: []
paths:
  /v1/migrate/stripe/preview:
    get:
      tags:
        - Billing
      summary: Preview a migration from Stripe Billing
      description: Or run the whole migration with npx integrateledger-cli migrate stripe.
      operationId: previewStripeMigration
      responses:
        '200':
          description: What a migration would import and refuse
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MigrationPreview'
        '401':
          description: Missing or invalid Ledger API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MigrationError'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          description: >-
            Unexpected error in Ledger. It has been logged with the request ID;
            retry, or quote request_id when reporting it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InternalError'
        '502':
          description: >-
            No Stripe connection for this environment or its key is invalid
            (stripe_not_configured), or Stripe unavailable
            (stripe_preview_failed)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MigrationError'
      security:
        - ApiKey: []
      x-codeSamples:
        - lang: python
          label: Python SDK
          source: |-
            import os
            from integrateledger import ledger

            client = ledger(api_key=os.environ["LEDGER_API_KEY"])
            client.preview_stripe_migration()
        - lang: bash
          label: cURL
          source: >-
            curl --request GET
            'https://api.integrateledger.com/v1/migrate/stripe/preview' \
              -H "Authorization: Bearer $LEDGER_API_KEY"
        - lang: typescript
          label: TypeScript SDK
          source: >-
            import ledger from "integrateledger";


            const client = new ledger({ apiKey: process.env.LEDGER_API_KEY ?? ""
            });

            await client.previewStripeMigration();
components:
  schemas:
    MigrationPreview:
      type: object
      properties:
        prices:
          type: array
          items:
            $ref: '#/components/schemas/MigrationPrice'
        subscriptions:
          type: array
          items:
            $ref: '#/components/schemas/MigrationSubscription'
        truncated:
          type: boolean
          description: >-
            More open subscriptions exist than one preview reads (1,000). Import
            these, then preview again.
      required:
        - prices
        - subscriptions
        - truncated
    MigrationError:
      type: object
      properties:
        error:
          type: string
      required:
        - error
    InternalError:
      type: object
      properties:
        error:
          type: string
          example: internal_error
        request_id:
          type: string
          nullable: true
      required:
        - error
        - request_id
    MigrationPrice:
      type: object
      properties:
        priceId:
          type: string
        productId:
          type: string
        productName:
          type: string
        unitAmountCents:
          type: integer
          nullable: true
        currency:
          type: string
        interval:
          type: string
          nullable: true
        intervalCount:
          type: integer
          nullable: true
        openSubscriptions:
          type: integer
          description: Subscriptions on this Price that Stripe still bills.
        importableSubscriptions:
          type: integer
          description: >-
            Of those, the ones an import would accept and Ledger doesn't hold
            yet.
        ledgerPlanId:
          type: string
          nullable: true
          description: >-
            Set when this Price is the synced Stripe Price of one of your Ledger
            plans.
        refusal:
          $ref: '#/components/schemas/MigrationRefusal'
      required:
        - priceId
        - productId
        - productName
        - unitAmountCents
        - currency
        - interval
        - intervalCount
        - openSubscriptions
        - importableSubscriptions
        - ledgerPlanId
        - refusal
    MigrationSubscription:
      type: object
      properties:
        stripeSubscriptionId:
          type: string
        stripeCustomerId:
          type: string
        customerMetadata:
          type: object
          additionalProperties:
            type: string
          description: The Stripe customer's metadata, to choose your own customer ID from.
        priceId:
          type: string
          nullable: true
        status:
          type: string
        currentPeriodEnd:
          type: string
          nullable: true
          format: date-time
          description: The next renewal.
        cancelAtPeriodEnd:
          type: boolean
        importedAs:
          type: object
          nullable: true
          properties:
            customerId:
              type: string
            planId:
              type: string
          required:
            - customerId
            - planId
          description: Set when Ledger already holds it.
        refusal:
          $ref: '#/components/schemas/MigrationRefusal'
      required:
        - stripeSubscriptionId
        - stripeCustomerId
        - customerMetadata
        - priceId
        - status
        - currentPeriodEnd
        - cancelAtPeriodEnd
        - importedAs
        - refusal
    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: rate_limited
      required:
        - error
    MigrationRefusal:
      type: object
      nullable: true
      properties:
        error:
          type: string
          description: >-
            The code POST /v1/billing/import would answer, such as
            unsupported_subscription or multiple_subscriptions.
        reason:
          type: string
          description: >-
            For unsupported_subscription: what Ledger can't bill yet, such as
            not_monthly, metered_price or discount.
      required:
        - error
      description: >-
        Set when no subscription on this Price can be imported: a yearly,
        metered, free or non-USD Price.
  responses:
    RateLimited:
      description: >-
        Too many requests. Wait Retry-After seconds, then retry. See the rate
        limits guide.
      headers:
        Retry-After:
          description: Seconds until a request is allowed again
          schema:
            type: integer
        RateLimit-Limit:
          description: 'The burst: requests allowed at once'
          schema:
            type: integer
        RateLimit-Remaining:
          description: Requests left right now
          schema:
            type: integer
        RateLimit-Reset:
          description: Seconds until the full burst is back
          schema:
            type: integer
        RateLimit-Policy:
          description: >-
            The sustained rate per second and the burst, such as
            200;w=1;burst=1000
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitError'
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer

````

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