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

# Publish an organization's catalog

> Publish an entire desired catalog for declarative sync. Items omitted from the input are archived.

Publishes the complete desired catalog for the environment selected by the API key in one request. Supply `schemaVersion: 1`, `environment: "sandbox"` with a test key or `environment: "live"` with a live key, `currency: "usd"`, at least one plan and one feature, any add-ons, and `policy.onInsufficientCredits: "block"`. A mismatched environment is rejected. This is a declarative replacement: active items omitted from the submitted lists are archived.

> [!NOTE]
>
> The examples in the request panel use Sandbox. For Live, use a `ledger_live_` key and change the body to `"environment": "live"`.

Ledger changes only rows whose values differ. The response reports `changed: false` for an identical catalog and a `stripeSync` state for paid plan prices after the database commit. Changed plans create new versions; existing subscriptions retain their referenced plan versions. Feature and add-on values update in place. A Stripe sync failure does not roll back an accepted catalog.

If an add-on has a pending purchase, changing its price or credit amount returns `409 purchase_pending`; complete the payment or wait for Stripe's signed `checkout.session.expired` event to clear it before publishing the new value. A browser cancel redirect alone does not expire Checkout. An invalid catalog returns `400 invalid_catalog` with `issues` that identify fields and validation errors. Use [Create a plan](https://docs.integrateledger.com/api-reference/plans/create.md), [Create a feature](https://docs.integrateledger.com/api-reference/features/create.md), and [Create an add-on](https://docs.integrateledger.com/api-reference/add-ons/create.md) for incremental onboarding without replacing unrelated items. See [Catalog](https://docs.integrateledger.com/catalog.md) for the tradeoffs.


## OpenAPI

````yaml openapi.json PUT /v1/catalog
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/catalog:
    put:
      tags:
        - Catalog
      summary: Publish an organization's catalog
      operationId: publishCatalog
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CatalogInput'
      responses:
        '200':
          description: >-
            Catalog accepted. changed is false when the Ledger catalog is
            unchanged. stripeSync reports paid-plan Stripe Product sync after
            commit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogPublishResponse'
        '400':
          description: Invalid catalog
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogError'
        '401':
          description: Missing or invalid Ledger API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogError'
        '409':
          description: An add-on with a pending Checkout cannot change credits or price
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogError'
      security:
        - ApiKey: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl --request PUT 'https://api.integrateledger.com/v1/catalog' \
              -H "Authorization: Bearer $LEDGER_API_KEY" \
              -H 'Content-Type: application/json' \
              --data '{"schemaVersion":1,"environment":"sandbox","currency":"usd","plans":[{"id":"starter","name":"Starter","monthlyCredits":100,"monthlyPriceCents":1900}],"features":[{"id":"api_call","name":"API call","creditCost":1}],"addOns":[],"policy":{"onInsufficientCredits":"block"}}'
        - lang: python
          label: Python SDK (source only)
          source: >-
            import os

            from ledger_sdk import Ledger


            ledger = Ledger(api_key=os.environ["LEDGER_API_KEY"])

            ledger.publish_catalog({"schemaVersion": 1, "environment":
            "sandbox", "currency": "usd", "plans": [{"id": "starter", "name":
            "Starter", "monthlyCredits": 100, "monthlyPriceCents": 1900}],
            "features": [{"id": "api_call", "name": "API call", "creditCost":
            1}], "addOns": [], "policy": {"onInsufficientCredits": "block"}})
        - lang: typescript
          label: TypeScript SDK (source only)
          source: >-
            import { Ledger } from "@ledger/sdk";


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

            await ledger.publishCatalog({ schemaVersion: 1, environment:
            "sandbox", currency: "usd", plans: [{ id: "starter", name:
            "Starter", monthlyCredits: 100, monthlyPriceCents: 1900 }],
            features: [{ id: "api_call", name: "API call", creditCost: 1 }],
            addOns: [], policy: { onInsufficientCredits: "block" } });
components:
  schemas:
    CatalogInput:
      type: object
      properties:
        schemaVersion:
          type: integer
          enum:
            - 1
        environment:
          type: string
          enum:
            - sandbox
            - live
        currency:
          type: string
          enum:
            - usd
        plans:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                minLength: 1
                maxLength: 100
                pattern: ^[a-zA-Z0-9_-]+$
              name:
                type: string
                minLength: 1
                maxLength: 120
              monthlyCredits:
                type: integer
                exclusiveMinimum: 0
                maximum: 2147483647
              monthlyPriceCents:
                type: integer
                minimum: 0
                maximum: 2147483647
            required:
              - id
              - name
              - monthlyCredits
              - monthlyPriceCents
            additionalProperties: false
          minItems: 1
        features:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                minLength: 1
                maxLength: 100
                pattern: ^[a-zA-Z0-9_-]+$
              name:
                type: string
                minLength: 1
                maxLength: 120
              creditCost:
                type: integer
                exclusiveMinimum: 0
                maximum: 2147483647
            required:
              - id
              - name
              - creditCost
            additionalProperties: false
          minItems: 1
        addOns:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                minLength: 1
                maxLength: 100
                pattern: ^[a-zA-Z0-9_-]+$
              name:
                type: string
                minLength: 1
                maxLength: 120
              type:
                type: string
                enum:
                  - credit_pack
              creditAmount:
                type: integer
                exclusiveMinimum: 0
                maximum: 2147483647
              priceCents:
                type: integer
                exclusiveMinimum: 0
                maximum: 2147483647
            required:
              - id
              - name
              - type
              - creditAmount
              - priceCents
            additionalProperties: false
        policy:
          type: object
          properties:
            onInsufficientCredits:
              type: string
              enum:
                - block
          required:
            - onInsufficientCredits
          additionalProperties: false
      required:
        - schemaVersion
        - environment
        - currency
        - plans
        - features
        - addOns
        - policy
      additionalProperties: false
    CatalogPublishResponse:
      type: object
      properties:
        changed:
          type: boolean
        stripeSync:
          type: string
          enum:
            - synced
            - pending
            - failed
            - awaiting_connection
      required:
        - changed
        - stripeSync
    CatalogError:
      type: object
      properties:
        error:
          type: string
        issues:
          type: array
          items:
            type: object
            properties:
              path:
                type: string
              message:
                type: string
            required:
              - path
              - message
      required:
        - error
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer

````

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