Reonic Residential Projects API
Residential customer projects across the request, offer, and installation lifecycle stages.
Residential customer projects across the request, offer, and installation lifecycle stages.
openapi: 3.1.0
info:
title: Reonic REST Api v3 Activities Residential Projects 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: Residential Projects
description: Residential customer projects across the request, offer, and installation lifecycle stages.
paths:
/residentialProjects:
get:
summary: List residential projects
description: 'List residential projects across all lifecycle stages (request, offer, installation) in a paginated format. Use the `stage` query param to restrict to one or more stages; omit to span all three.
**Examples:**
- Most recent offers: `GET /residentialProjects?stage=offer&sort=-offerCreatedAt&page=1`
- Open offers: `GET /residentialProjects?stage=offer&dealState=Open`
- Projects assigned to specific Kanban columns: `GET /residentialProjects?kanbanColumnIds=<uuid>&kanbanColumnIds=<uuid>`
**Allowed API keys:** Read-only, Read and Write'
tags:
- Residential Projects
parameters:
- schema:
type:
- array
- 'null'
items:
type: string
enum:
- request
- offer
- installation
maxItems: 3
description: 'Filter by lifecycle stages: request, offer, installation. Omit to include all stages.'
examples:
- request
- offer,installation
required: false
description: 'Filter by lifecycle stages: request, offer, installation. Omit to include all stages.'
name: stage
in: query
- schema:
type:
- array
- 'null'
items:
type: string
enum:
- Open
- Won
- Lost
maxItems: 3
description: Filter by deal state. Omit to include all. Pass `null` to return only projects that have no deal state.
examples:
- Open
- Won,Lost
required: false
description: Filter by deal state. Omit to include all. Pass `null` to return only projects that have no deal state.
name: dealState
in: query
- schema:
type: string
enum:
- exclude
- include
- only
default: exclude
description: 'Controls whether archived projects appear in results. Default: exclude.'
required: false
description: 'Controls whether archived projects appear in results. Default: exclude.'
name: archived
in: query
- schema:
type:
- array
- 'null'
items:
type: string
format: uuid
maxItems: 50
description: Filter projects that are tagged with any of the specified tag IDs. Pass `null` to return only projects that have no tags.
required: false
description: Filter projects that are tagged with any of the specified tag IDs. Pass `null` to return only projects that have no tags.
name: tagIds
in: query
- schema:
type:
- array
- 'null'
items:
type: string
format: uuid
maxItems: 50
description: Filter projects that have a lead source with any of the specified IDs. Pass `null` to return only projects that have no lead source.
required: false
description: Filter projects that have a lead source with any of the specified IDs. Pass `null` to return only projects that have no lead source.
name: leadSourceIds
in: query
- schema:
type:
- array
- 'null'
items:
type: string
format: uuid
maxItems: 50
description: Filter projects that are in any of the specified Kanban boards. Pass `null` to return only projects that are not assigned to any Kanban board. Mutually exclusive with `kanbanColumnIds`.
required: false
description: Filter projects that are in any of the specified Kanban boards. Pass `null` to return only projects that are not assigned to any Kanban board. Mutually exclusive with `kanbanColumnIds`.
name: kanbanBoardIds
in: query
- schema:
type:
- array
- 'null'
items:
type: string
format: uuid
maxItems: 50
description: Filter projects that are in any of the specified Kanban columns. Pass `null` to return only projects that have no status assigned (the "no status" column). Mutually exclusive with `kanbanBoardIds`.
required: false
description: Filter projects that are in any of the specified Kanban columns. Pass `null` to return only projects that have no status assigned (the "no status" column). Mutually exclusive with `kanbanBoardIds`.
name: kanbanColumnIds
in: query
- schema:
type: string
minLength: 1
maxLength: 1000
description: Filter projects by their exact internal customer number (e.g. from your CRM or ERP).
required: false
description: Filter projects by their exact internal customer number (e.g. from your CRM or ERP).
name: customerNumber
in: query
- schema:
type: string
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
description: Filter projects whose customer contact has this ID. Reference to [**Contacts**](#tag/contacts)
required: false
description: Filter projects whose customer contact has this ID. Reference to [**Contacts**](#tag/contacts)
name: contactId
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where projectCreatedAt is after this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where projectCreatedAt is after this datetime (exclusive)
name: projectCreatedAt.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where projectCreatedAt is before this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where projectCreatedAt is before this datetime (exclusive)
name: projectCreatedAt.lt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where requestCreatedAt is after this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where requestCreatedAt is after this datetime (exclusive)
name: requestCreatedAt.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where requestCreatedAt is before this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where requestCreatedAt is before this datetime (exclusive)
name: requestCreatedAt.lt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where offerCreatedAt is after this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where offerCreatedAt is after this datetime (exclusive)
name: offerCreatedAt.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where offerCreatedAt is before this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where offerCreatedAt is before this datetime (exclusive)
name: offerCreatedAt.lt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where installationCreatedAt is after this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where installationCreatedAt is after this datetime (exclusive)
name: installationCreatedAt.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where installationCreatedAt is before this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where installationCreatedAt is before this datetime (exclusive)
name: installationCreatedAt.lt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where updatedAt is after this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where updatedAt is after this datetime (exclusive)
name: updatedAt.gt
in: query
- schema:
type:
- string
- 'null'
format: date-time
description: Filter records where updatedAt is before this datetime (exclusive)
example: '2026-01-01T15:30:00.000Z'
required: false
description: Filter records where updatedAt is before this datetime (exclusive)
name: updatedAt.lt
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
- 'null'
default: -projectCreatedAt
description: 'Sort order. Use field names for ascending (e.g. "createdAt"), minus sign for descending (e.g. "-createdAt"). Chain with commas (e.g. "createdAt,editedAt"). Sortable fields: projectCreatedAt, requestCreatedAt, offerCreatedAt, installationCreatedAt, updatedAt. Defaults to -projectCreatedAt.'
examples:
- -projectCreatedAt
- offerCreatedAt
- -updatedAt
required: false
description: 'Sort order. Use field names for ascending (e.g. "createdAt"), minus sign for descending (e.g. "-createdAt"). Chain with commas (e.g. "createdAt,editedAt"). Sortable fields: projectCreatedAt, requestCreatedAt, offerCreatedAt, installationCreatedAt, updatedAt. Defaults to -projectCreatedAt.'
name: sort
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 residential projects
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/ResidentialProject'
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
/residentialProjects/{projectId}:
get:
summary: Get residential project
description: 'Get a single residential project by its ID. Works for any stage (request, offer, or installation).
**Allowed API keys:** Read-only, Read and Write'
tags:
- Residential Projects
parameters:
- schema:
type: string
format: uuid
required: true
name: projectId
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 residential project
content:
application/json:
schema:
$ref: '#/components/schemas/ResidentialProjectDetail'
/residentialProjects/create:
post:
summary: Create residential project
description: 'Create a residential project at a given lifecycle stage.
**Allowed API keys:** Read and Write, Lead creation only'
tags:
- Residential Projects
requestBody:
content:
application/json:
schema:
type: object
properties:
stage:
type: string
enum:
- request
- offer
- installation
latLng:
type: object
properties:
lat:
type: number
minimum: -90
maximum: 90
example: 48.363767359
lng:
type: number
minimum: -180
maximum: 180
example: 10.888136991
required:
- lat
- lng
additionalProperties: false
description: Coordinates of the installation site. Provide either `latLng` or `address` (exactly one). The project's `address` in the response is reverse-geocoded from these coordinates. Note that this is independent of the customer contact's address — if you also send `customerContact.address`, that address is stored on the contact and may differ from the geocoded installation address (e.g. when the customer's residence differs from the installation site).
address:
type: object
properties:
street:
type: string
minLength: 1
maxLength: 1000
example: Hauptstraße
houseNumber:
type: string
minLength: 1
maxLength: 1000
example: '12'
postcode:
type: string
minLength: 1
maxLength: 1000
example: '86150'
city:
type: string
minLength: 1
maxLength: 1000
example: Augsburg
country:
type: string
enum:
- Austria
- Switzerland
- Germany
- Liechtenstein
- Luxembourg
- Czechia
- Slovakia
- Hungary
- Poland
- Slovenia
- France
- Belgium
- Netherlands
- Monaco
- Andorra
- Italy
- SanMarino
- VaticanCity
- Malta
- Spain
- Portugal
- Gibraltar
- Denmark
- Sweden
- Norway
- Finland
- Iceland
- FaroeIslands
- Greenland
- Albania
- Armenia
- Azerbaijan
- Belarus
- BosniaAndHerzegovina
- Bulgaria
- Croatia
- Cyprus
- Estonia
- Georgia
- Greece
- Kazakhstan
- Kosovo
- Latvia
- Lithuania
- Moldova
- Montenegro
- NorthMacedonia
- Romania
- Russia
- Serbia
- Turkey
- Ukraine
- UnitedKingdom
- Jersey
- Ireland
- Martinique
- Guadeloupe
- Reunion
- SaintMartin
- SaintBarthelemy
- SaintPierreAndMiquelon
- FrenchGuiana
- Bahamas
- Barbados
- Dominica
- Grenada
- Jamaica
- SaintKittsAndNevis
- SaintLucia
- SaintVincentAndTheGrenadines
- TrinidadAndTobago
- AntiguaAndBarbuda
- Aruba
- Curacao
- Bermuda
- CaymanIslands
- TurksAndCaicosIslands
- Anguilla
- Montserrat
- BritishVirginIslands
- USVirginIslands
- SintMaarten
- BonaireSintEustatiusSaba
- Argentina
- Bolivia
- Belize
- Brazil
- Chile
- Colombia
- CostaRica
- Cuba
- DominicanRepublic
- Ecuador
- ElSalvador
- Guatemala
- Guyana
- Honduras
- Haiti
- Mexico
- Nicaragua
- Panama
- Paraguay
- Peru
- Suriname
- Uruguay
- Venezuela
- FalklandIslands
- UnitedStates
- Morocco
- SouthAfrica
example: Germany
required:
- street
- postcode
- city
- country
additionalProperties: false
description: Installation site address, geocoded into coordinates. Provide either `latLng` or `address` (exactly one). Only a precise, street-level match whose resolved postcode equals the `postcode` you sent sets the coordinates; if the address can only be resolved approximately (e.g. to a city, postcode, or country), resolves to a different postcode, or cannot be geocoded at all, the coordinates default to `0, 0`.
customerContact:
anyOf:
- $ref: '#/components/schemas/ContactReference'
- $ref: '#/components/schemas/ContactCreate'
description: Either reference an existing contact by `id` or provide full contact details to create a new one.
name:
type: string
minLength: 2
maxLength: 500
description: If omitted defaults to customer contacts `firstName` + `lastName`
example: Test Project
customerNumber:
type: string
maxLength: 1000
description: Internal customer reference, e.g. from your CRM or ERP.
example: C-1042
meterNumber:
type: string
maxLength: 1000
description: Electricity meter number at the customer's property.
example: 1APA0123456789
kanbanBoardId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
description: ID of the Kanban board this project should be placed on. Has to match `stage`. The project is placed in the board's first column. Mutually exclusive with `kanbanColumnId`.
kanbanColumnId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
description: ID of the project's current Kanban column. Has to match `stage`. Reference to [**Kanban Columns**](#tag/kanban-columns). Mutually exclusive with `kanbanBoardId`.
leadSourceId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
tagIds:
type: array
items:
type: string
format: uuid
maxItems: 50
description: IDs of the tags to assign to this project. Reference to [**Tags**](#tag/tags)
example:
- 123e4567-e89b-12d3-a456-426614174000
- 123e4567-e89b-12d3-a456-426614174002
packages:
type: object
properties:
solarPackageId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
batteryStoragePackageId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
evChargerPackageId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
heatingPackageId:
type:
- string
- 'null'
format: uuid
example: 123e4567-e89b-12d3-a456-426614174000
additionalProperties: false
integrations:
type: object
properties:
hubspotDealId:
type:
- string
- 'null'
maxLength: 1000
pipedriveDealId:
type:
- integer
- 'null'
minimum: 1
maximum: 9007199254740991
weclappOpportunityId:
type:
- string
- 'null'
format: uuid
bitrixDealId:
type:
- string
- 'null'
maxLength: 1000
photovateDealId:
type:
- string
- 'null'
format: uuid
additionalProperties: false
description: IDs of this project in third-party systems.
required:
- stage
- customerContact
additionalProperties: false
responses:
'201':
description: The created residential project
content:
application/json:
schema:
$ref: '#/components/schemas/ResidentialProjectDetail'
/residentialProjects/{projectId}/update:
post:
summary: Update residential project
description: 'Update fields of a residential project. Stage-agnostic — the same fields are editable at any lifecycle stage. If you want to update contact details, use the dedicated endpoint — see [**Contacts**](#tag/contacts) for more details on that.
**Allowed API keys:** Read and Write'
tags:
- Residential Projects
parameters:
- schema:
type: string
format: uuid
required: true
name: projectId
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
stage:
type: string
enum:
- request
- offer
- installation
latLng:
type: object
properties:
lat:
type: number
minimum: -90
maximum: 90
example: 48.363767359
lng:
type: number
minimum: -180
maximum: 180
example: 10.888136991
required:
- lat
- lng
additionalProperties: false
description: Updates the coordinates of the installation site. The project's `address` in the response is reverse-geocoded from these coordinates and will reflect the new location on subsequent reads. The customer contact's own address is stored separately and is not affected by this update.
name:
type: string
minLength: 2
maxLength: 500
customerNumber:
type:
- string
- 'null'
maxLength: 1000
description: Internal customer reference, e.g. from your CRM or ERP. Pass `null` to clear.
example: C-1042
meterNumber:
type:
- string
- 'null'
maxLength: 1000
description: Electricity meter number at the customer's property. Pass `null` to clear.
example: 1APA0123456789
targetSignatureDate:
type:
- string
- 'null'
format: date-time
example: '2026-01-01T15:30:00.000Z'
description: Target date by which the offer should be signed. Pass `null` to clear.
closedAt:
type:
- string
# --- truncated at 32 KB (93 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/reonic/refs/heads/main/openapi/reonic-residential-projects-api-openapi.yml