Reonic Planning Packages API

Standard offer packages for PV, storage, heat pumps, and EV chargers, built from common [**Components**](#tag/components) and service combinations.

OpenAPI Specification

reonic-planning-packages-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Reonic REST Api v3 Activities Planning Packages API
  description: 'The Reonic REST API v3 provides programmatic access to create and manage resources. The API follows REST principles and returns responses in JSON format. Authentication is required via an API key passed in the X-Authorization header.


    ## Errors


    All endpoints return errors with the same JSON shape:


    ```json

    { "message": "human-readable description" }

    ```


    `400` responses additionally include an `errors` field with per-field validation details.


    The HTTP status code identifies the cause:


    | Status  | Meaning | When |

    |--------|---------|------|

    | `400` | Bad Request | Path params, query string, or request body failed validation. Inspect `errors` for the field-level breakdown. |

    | `401` | Unauthorized | The `X-Authorization` header is missing, malformed, does not match an active API key, or belongs to a different API version. The response never indicates which check failed; check that the key matches the endpoint version. API v3 endpoints require a v3 key with the `rnc_v3_` prefix. |

    | `403` | Forbidden | The API key is read-only and the request targeted a write endpoint (`POST`). Issue a key with write access. |

    | `404` | Not Found | A resource referenced by a path id does not exist or is not visible to your workspace. |

    | `429` | Too Many Requests | The per-client rate limit was exceeded. See **Rate limiting** below. |

    | `500` | Internal Server Error | Unexpected failure. Safe to retry once; if it persists, contact support. |

    | `503` | Service Unavailable | A backing dependency is temporarily unavailable. Retry with exponential backoff. |


    ## Rate limiting


    Limits are shared across all API keys you hold and reset on a 1-minute window. Two buckets:


    | Bucket | Limit | Applies to |

    |--------|-------|------------|

    | `cached` | 500 / min | `GET` requests served from the response cache |

    | `uncached` | 30 / min | Cache misses, `GET` requests sent with `Reonic-Cache-Control: no-cache`, and all `POST` requests |


    Every response includes:


    - `X-RateLimit-Bucket` — `cached` or `uncached`

    - `X-RateLimit-Limit` — the bucket''s ceiling (`500` or `30`)

    - `X-RateLimit-Remaining` — calls left in the current window

    - `X-RateLimit-Reset` — Unix epoch seconds at which the window resets

    - `X-RateLimit-Policy` — `<limit>;w=60`


    `429` responses additionally set `Retry-After` (in seconds). Wait at least that long before retrying.


    ## Caching and Reonic-Cache-Control


    `GET` responses are cached for up to 1 hour. Identical requests (same path and query) on the same API key return the cached result. To force a fresh read, send `Reonic-Cache-Control: no-cache`; the response is then refreshed and re-cached. Forced refreshes count against the `uncached` rate-limit bucket.


    The standard `Cache-Control` header is not honored. Use `Reonic-Cache-Control` to control caching behavior.


    ## Authentication


    Every request must include your API key in the `X-Authorization` header:


    ```

    X-Authorization: <your-api-key>

    ```


    API keys are issued from the Reonic web app and look like `rnc_v3_…`. Send the full value, including the prefix.

    '
  version: 3.2.0
  contact:
    email: kontakt@reonic.de
    url: https://reonic.com
    name: Reonic GmbH
servers:
- url: '{apiBaseUrl}/rest/v3/'
security:
- X-Authorization: []
tags:
- name: Planning Packages
  description: Standard offer packages for PV, storage, heat pumps, and EV chargers, built from common [**Components**](#tag/components) and service combinations.
paths:
  /planningPackages:
    get:
      summary: List planning packages
      description: 'List planning packages. Planning packages are standard offer packages for PV, storage, heat pumps, and EV chargers, built from common component and service combinations.


        **Allowed API keys:** Read-only, Read and Write'
      tags:
      - Planning Packages
      parameters:
      - schema:
          type: string
          enum:
          - residential
          - commercial
          description: Filter by the project domain a planning packages can be used in.
        required: false
        description: Filter by the project domain a planning packages can be used in.
        name: projectDomain
        in: query
      - schema:
          type: array
          items:
            type: string
            enum:
            - solar
            - evCharger
            - batteryStorage
            - heatPump
            - optionalComponents
            - additionalComponents
          description: Filter by target sections
        required: false
        description: Filter by target sections
        style: form
        explode: false
        name: target
        in: query
      - schema:
          type: string
          enum:
          - exclude
          - include
          - only
          default: exclude
          description: 'Controls whether inactive planning packages appear in results. Default: exclude.'
        required: false
        description: 'Controls whether inactive planning packages appear in results. Default: exclude.'
        name: inactive
        in: query
      - schema:
          type: integer
          minimum: 1
          default: 1
          description: 'Page number, starting from 1. Default: 1.'
        required: false
        description: 'Page number, starting from 1. Default: 1.'
        name: page
        in: query
      - schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
          description: 'Number of items per page. Default: 50. Max: 200.'
        required: false
        description: 'Number of items per page. Default: 50. Max: 200.'
        name: itemsPerPage
        in: query
      - schema:
          type: string
          example: no-cache
        required: false
        name: Reonic-Cache-Control
        in: header
        description: Set to 'no-cache' to bypass the 1-hour response cache and force a fresh read. The fresh response is then written back to the cache for subsequent callers. Forced refreshes count against the uncached rate-limit bucket (30/min); only cache hits count against the cached bucket (500/min).
      responses:
        '200':
          description: Paginated list of planning packages
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlanningPackage'
                  pagination:
                    type: object
                    properties:
                      page:
                        type: integer
                        minimum: 1
                        description: Current page number
                      perPage:
                        type: integer
                        minimum: 1
                        description: Number of items per page
                      total:
                        type: integer
                        minimum: 0
                        description: Total number of items across all pages
                      totalPages:
                        type: integer
                        minimum: 1
                      next:
                        type:
                        - string
                        - 'null'
                        description: Path to the next page, or null if there is no next page
                      prev:
                        type:
                        - string
                        - 'null'
                        description: Path to the previous page, or null if there is no previous page
                    required:
                    - page
                    - perPage
                    - total
                    - totalPages
                    - next
                    - prev
                required:
                - data
                - pagination
  /planningPackages/{packageId}:
    get:
      summary: Get planning package
      description: 'Get a single planning package by its ID.


        **Allowed API keys:** Read-only, Read and Write'
      tags:
      - Planning Packages
      parameters:
      - schema:
          type: string
          format: uuid
        required: true
        name: packageId
        in: path
      - schema:
          type: string
          example: no-cache
        required: false
        name: Reonic-Cache-Control
        in: header
        description: Set to 'no-cache' to bypass the 1-hour response cache and force a fresh read. The fresh response is then written back to the cache for subsequent callers. Forced refreshes count against the uncached rate-limit bucket (30/min); only cache hits count against the cached bucket (500/min).
      responses:
        '200':
          description: The planning package
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanningPackage'
  /planningPackages/create:
    post:
      summary: Create planning package
      description: 'Create a new planning package.


        **Allowed API keys:** Read and Write'
      tags:
      - Planning Packages
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanningPackageCreate'
      responses:
        '201':
          description: The newly created planning package
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanningPackage'
  /planningPackages/{packageId}/update:
    post:
      summary: Update planning package
      description: 'Update an existing planning package. Omit a field to leave it unchanged.


        **Allowed API keys:** Read and Write'
      tags:
      - Planning Packages
      parameters:
      - schema:
          type: string
          format: uuid
        required: true
        name: packageId
        in: path
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanningPackageUpdate'
      responses:
        '200':
          description: The updated planning package
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanningPackage'
  /planningPackages/{packageId}/delete:
    post:
      summary: Delete planning package
      description: 'Delete a planning package by its ID.


        **Allowed API keys:** Read and Write'
      tags:
      - Planning Packages
      parameters:
      - schema:
          type: string
          format: uuid
        required: true
        name: packageId
        in: path
      responses:
        '200':
          description: The deleted planning package ID
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 123e4567-e89b-12d3-a456-426614174000
                    required:
                    - id
                required:
                - data
components:
  schemas:
    PlanningPackageCustomItemInput:
      type: object
      properties:
        componentSource:
          type: string
          enum:
          - custom
          description: 'Inline-create a package-specific custom component as part of this item. A custom component stores only commercial fields (name, description, price, VAT, quantity) — it has no technical specifications. It therefore contributes nothing to the system-size and simulation figures the Portal derives from components (e.g. kWp peak power, storage capacity, yield) and those values will appear empty there. If you need a component to feed into system size or simulation, reference a catalog component with `componentSource: "catalog"` instead.'
        componentType:
          type: string
          enum:
          - module
          - inverter
          - microinverter
          - optimizer
          - virtualBattery
          - batteryStorage
          - evCharger
          - heatPump
          - airHeatPump
          - hotWaterHeatPump
          - heatingStorage
          - hotWaterStorage
          - heatingRod
          - radiator
          - indoorUnitAirHeatPump
          - accessoryToEvCharger
          - accessoryToHeatPump
          - accessoryToModule
          - accessoryToInverter
          - accessoryToBatteryStorage
          - other
          - moduleFrameConstruction
          - serviceFee
          - installationFee
          default: other
          description: Category of the inline component; sets how it is grouped in offers (e.g. `module` → solar, `batteryStorage` → storage). Defaults to `other`. This only affects grouping — it does not give the custom component the technical specs of that category (see `componentSource`).
        name:
          type: string
          minLength: 1
          maxLength: 500
        description:
          type:
          - string
          - 'null'
          maxLength: 5000
        quantity:
          type: number
          exclusiveMinimum: 0
        visibleToCustomer:
          type: boolean
          default: true
        salesPrice:
          type: number
          minimum: 0
          description: Effective unit price charged to the end customer, net (excluding VAT).
        vatRate:
          type: number
          minimum: 0
          maximum: 1
          description: VAT rate as a fraction (e.g. 0.19 for 19%).
      required:
      - componentSource
      - name
      - quantity
      - salesPrice
      - vatRate
      additionalProperties: false
    PlanningPackageCatalogItemInput:
      type: object
      properties:
        componentSource:
          type: string
          enum:
          - catalog
          description: Reference an existing entry from [**Components**](#tag/components) by ID.
        componentId:
          type: string
          format: uuid
          description: ID of the [**Components**](#tag/components) entry to add. The latest component version is used.
          example: 123e4567-e89b-12d3-a456-426614174000
        quantity:
          type: number
          exclusiveMinimum: 0
        visibleToCustomer:
          type: boolean
          default: true
        salesPrice:
          type: number
          minimum: 0
          description: Unit price charged to the end customer, net (excluding VAT). Omit (together with `vatRate`) to snapshot the catalog component's current price. The value is pinned on this item — later edits to the catalog component do not propagate.
        vatRate:
          type: number
          minimum: 0
          maximum: 1
          description: VAT rate as a fraction (e.g. 0.19 for 19%). Omit (together with `salesPrice`) to snapshot the catalog component's current VAT rate. The value is pinned on this item — later edits to the catalog component do not propagate.
      required:
      - componentSource
      - componentId
      - quantity
      additionalProperties: false
    PlanningPackageUpdate:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 500
        description:
          type: string
          maxLength: 5000
        active:
          type: boolean
          description: Whether the planning package can be imported into an offer.
        projectDomains:
          type: array
          items:
            type: string
            enum:
            - residential
            - commercial
          description: Project domains this package can be used in. Providing an array replaces the existing set; `[]` clears it; omit to leave unchanged.
        items:
          type: array
          items:
            oneOf:
            - $ref: '#/components/schemas/PlanningPackageCatalogItemInput'
            - $ref: '#/components/schemas/PlanningPackageCustomItemInput'
            discriminator:
              propertyName: componentSource
              mapping:
                catalog: '#/components/schemas/PlanningPackageCatalogItemInput'
                custom: '#/components/schemas/PlanningPackageCustomItemInput'
          description: 'Provided array fully replaces the existing items; `[]` removes all items; omit to leave items unchanged. Array order becomes the planning package item order. Each item references either a catalog component (`componentSource: "catalog"`) or inline-creates a package-specific custom component (`componentSource: "custom"`). Custom components hold commercial data only and do not feed into the system-size or simulation figures shown in the Portal — see `componentSource`.'
      additionalProperties: false
    PlanningPackage:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
        name:
          type: string
        description:
          type: string
        active:
          type: boolean
          description: Determines if the planning package can be imported into an offer or not.
        projectDomains:
          type: array
          items:
            type: string
            enum:
            - residential
            - commercial
          description: Which project domains this can be used in.
        target:
          type: string
          enum:
          - solar
          - evCharger
          - batteryStorage
          - heatPump
          - optionalComponents
          - additionalComponents
          description: Planning section where this package can be applied.
        items:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
                description: Identifier for this Planning Package Item. For the linked Component's ID, see `component.id`.
                example: 123e4567-e89b-12d3-a456-426614174000
              component:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: Reference to [**Components**](#tag/components)
                    example: 123e4567-e89b-12d3-a456-426614174000
                  versionId:
                    type: string
                    format: uuid
                    description: Exact component version referenced by the planning package.
                    example: 123e4567-e89b-12d3-a456-426614174000
                  source:
                    type: string
                    enum:
                    - catalog
                    - custom
                    description: '`catalog` for reusable components from the component catalog; `custom` for package-specific custom components.'
                required:
                - id
                - versionId
                - source
              quantity:
                type: number
              purchasePrice:
                type:
                - number
                - 'null'
                description: Cost paid to acquire the component, net (excluding VAT). Null when not tracked.
              salesPrice:
                type: number
                description: Unit price charged to the end customer, net (excluding VAT). Pinned on this item; later edits to the catalog component do not propagate.
              vatRate:
                type: number
                minimum: 0
                maximum: 1
                description: VAT rate as a fraction (e.g. 0.19 for 19%). Pinned on this item; later edits to the catalog component do not propagate.
              salesPriceSource:
                type: string
                enum:
                - component
                - planningPackage
                description: 'How `salesPrice` was set when this item was created or last updated: `component` if it was snapshotted from the catalog component''s price at that time, `planningPackage` if it was set explicitly on this item. Both values are equally pinned afterwards.'
              position:
                type: number
                description: Order of the item within the planning package.
              visibleToCustomer:
                type: boolean
            required:
            - id
            - component
            - quantity
            - purchasePrice
            - salesPrice
            - vatRate
            - salesPriceSource
            - position
            - visibleToCustomer
      required:
      - id
      - name
      - description
      - active
      - projectDomains
      - target
      - items
    PlanningPackageCreate:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 500
        description:
          type: string
          maxLength: 5000
        active:
          type: boolean
          default: false
          description: Whether the planning package can be imported into an offer.
        target:
          type: string
          enum:
          - solar
          - evCharger
          - batteryStorage
          - heatPump
          - optionalComponents
          - additionalComponents
          description: Planning section where this package can be applied. Cannot be changed after creation.
        projectDomains:
          type: array
          items:
            type: string
            enum:
            - residential
            - commercial
          description: Project domains this package can be used in.
        items:
          type: array
          items:
            oneOf:
            - $ref: '#/components/schemas/PlanningPackageCatalogItemInput'
            - $ref: '#/components/schemas/PlanningPackageCustomItemInput'
            discriminator:
              propertyName: componentSource
              mapping:
                catalog: '#/components/schemas/PlanningPackageCatalogItemInput'
                custom: '#/components/schemas/PlanningPackageCustomItemInput'
          description: 'Full initial item list. Array order becomes the planning package item order. Omit to create the package without items. Each item references either an existing catalog component (`componentSource: "catalog"`) or inline-creates a package-specific custom component (`componentSource: "custom"`). Custom components hold commercial data only and do not feed into the system-size or simulation figures shown in the Portal — see `componentSource`.'
      required:
      - name
      - target
      additionalProperties: false
  securitySchemes:
    X-Authorization:
      type: apiKey
      in: header
      name: X-Authorization
x-tagGroups:
- name: People
  tags:
  - Contacts
  - Users
  - Teams
- name: Projects
  tags:
  - Residential Projects
  - Commercial Projects
- name: Working on a project
  tags:
  - Notes
  - Tasks
  - Files
  - File Folders
  - Activities
  - Time Tracking
  - Checklists
  - Checklist Templates
  - Signature Requests
- name: Calendar
  tags:
  - Calendars
  - Calendar Categories
  - Appointments
- name: Catalog
  tags:
  - Components
  - Planning Templates
  - Planning Packages
  - Offer Templates
- name: Workspace setup
  tags:
  - Kanban Boards
  - Kanban Columns
  - Tags
  - Lead Sources
- name: Wiki
  tags:
  - Wiki
- name: Services
  tags:
  - Photogrammetry
- name: API helpers
  tags:
  - Upload
  - Links
- name: Integrations
  tags:
  - Webhooks
- name: Guides
  tags:
  - Migrating from API v2 to v3
  - Changelog