Reonic Webhooks API
Webhooks notify your systems the moment something happens in Reonic. For example when a project is created or an offer is signed. Instead of repeatedly polling the API for changes, you give Reonic a URL and we send an HTTPS `POST` request to it whenever one of the events you selected occurs. The receiving URL does not have to be your own server. A webhook trigger from an automation tool works just as well. For example a "Webhooks by Zapier" trigger, an n8n Webhook node, or a Make "Custom webhook". ### Set up a webhook 1. Get the URL that should receive events — from your own service, or from your automation tool's webhook trigger step. It must be a public `https://` URL; URLs that resolve to private or internal addresses are rejected. 2. In the Reonic Portal, open the webhook settings (Settings > API / Developers > Webhooks), enter the URL, choose the events you want to receive, and save. 3. Send a test event from the same settings to confirm deliveries arrive (see [**Test events**](#webhooks-test-events) below). Saving also generates a signing secret (`whsec_…`), shown in the same settings. You only need it to verify signatures (recommended, see [**Verify signatures**](#webhooks-verify-signatures) below). The secret can be rotated there as well; rotation takes effect immediately and only one secret is valid at a time. Your endpoint must accept JSON `POST` requests (sent with `Content-Type: application/json`), must not redirect, and must respond within 5 seconds. Acknowledge first and process asynchronously if you need more time. ### Test events The Portal test action sends `X-Reonic-Event: test` with a `{ "message": … }` payload in the standard body shape (see [**Request format**](#webhooks-request-format) below). Use it to verify reachability and signature handling before enabling production events. Test deliveries are not retried and do not appear in the delivery log. Your endpoint's response is shown directly in the Portal instead. ### Request format Each delivery sends a JSON body with this shape: ```json { "version": 1, "type": "project_created", "occurredAt": "2026-01-01T12:00:00.000Z", "data": { /* event-specific payload, see the events below */ } } ``` Payloads are deliberately thin: they identify what happened and which resources were involved, but do not embed resource snapshots. Fetch the current state of an affected resource through the corresponding API v3 endpoint — for example, a `project_created` delivery carries a `projectId` to fetch via [**Residential Projects**](#tag/residential-projects) or [**Commercial Projects**](#tag/commercial-projects), depending on its `projectType`. Event metadata is also sent in headers: | Header | Meaning | |---|---| | `X-Reonic-Event` | Event type for this webhook delivery. Matches the `type` field in the body. | | `X-Reonic-Client-Id` | Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature. | | `X-Reonic-Event-Id` | Stable event id, identical across redeliveries of the same event. Use this as your idempotency key. | | `X-Reonic-Delivery-Id` | Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery. | | `X-Reonic-Timestamp` | Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`. | | `X-Reonic-Signature` | HMAC SHA-256 signature in the format `sha256=`, computed over `${timestamp}.${rawBody}`. | ### Verify signatures Verifying signatures is optional but strongly recommended: it proves a delivery was really sent by Reonic and not by someone who discovered your URL. If your tool cannot compute HMAC digests, keep your webhook URL secret and treat the data accordingly. Compute an HMAC SHA-256 digest with your webhook signing secret over `${timestamp}.${rawBody}`, then compare it to `X-Reonic-Signature`. Use the raw request body exactly as received, before JSON parsing. Reject deliveries whose `X-Reonic-Timestamp` is more than 5 minutes old to reduce replay risk — retries are signed freshly, so a legitimate delivery never carries an old timestamp. Code example: ```ts import { createHmac, timingSafeEqual } from "crypto"; const timestamp = request.headers["x-reonic-timestamp"]; const signature = request.headers["x-reonic-signature"]; const expected = Buffer.from("sha256=" + createHmac("sha256", secret) .update(`${timestamp}.${rawBody}`) .digest("hex")); const received = Buffer.from(signature); const isValid = expected.length === received.length && timingSafeEqual(expected, received); ``` ### Retries and idempotency Respond with any `2xx` status code once you have accepted the event — automation tools like Zapier and n8n do this for you. Every other response, as well as network errors and timeouts, is retried automatically, roughly 1 min, 5 min, 30 min, 2 h, 5 h, 12 h, 1 d, 2 d after the initial attempt. Delivery order is not guaranteed, and the same event may be delivered more than once, so store `X-Reonic-Event-Id` and ignore duplicates. > [!warning] > If all retries are exhausted, Reonic disables the webhook subscription and notifies your workspace's contact email. Re-enable it in the webhook settings once your endpoint is fixed. ### When deliveries fail The webhook settings in the Portal include a delivery log with every attempt, the response status or error we recorded, and the payload that was sent. Failed deliveries can be retried manually from there — including after you fix your endpoint and re-enable a disabled subscription. ### Compatibility The body's `version` (currently 1) only changes when the envelope shape itself — `version`, `type`, `occurredAt`, `data` — changes in a breaking way. New event types, new fields inside `data`, and new headers may appear without a version bump, so ignore anything you don't recognize.
Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Reonic REST Api v3 Webhooks 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: Webhooks
description: "Webhooks notify your systems the moment something happens in Reonic. For example when a project is created or an offer is signed. Instead of repeatedly polling the API for changes, you give Reonic a URL and we send an HTTPS `POST` request to it whenever one of the events you selected occurs.\n\nThe receiving URL does not have to be your own server. A webhook trigger from an automation tool works just as well. For example a \"Webhooks by Zapier\" trigger, an n8n Webhook node, or a Make \"Custom webhook\".\n\n### Set up a webhook\n\n1. Get the URL that should receive events — from your own service, or from your automation tool's webhook trigger step. It must be a public `https://` URL; URLs that resolve to private or internal addresses are rejected.\n2. In the Reonic Portal, open the webhook settings (Settings > API / Developers > Webhooks), enter the URL, choose the events you want to receive, and save.\n3. Send a test event from the same settings to confirm deliveries arrive (see [**Test events**](#webhooks-test-events) below).\n\nSaving also generates a signing secret (`whsec_…`), shown in the same settings. You only need it to verify signatures (recommended, see [**Verify signatures**](#webhooks-verify-signatures) below). The secret can be rotated there as well; rotation takes effect immediately and only one secret is valid at a time.\n\nYour endpoint must accept JSON `POST` requests (sent with `Content-Type: application/json`), must not redirect, and must respond within 5 seconds. Acknowledge first and process asynchronously if you need more time.\n\n<a id=\"webhooks-test-events\"></a>\n\n### Test events\n\nThe Portal test action sends `X-Reonic-Event: test` with a `{ \"message\": … }` payload in the standard body shape (see [**Request format**](#webhooks-request-format) below). Use it to verify reachability and signature handling before enabling production events. Test deliveries are not retried and do not appear in the delivery log. Your endpoint's response is shown directly in the Portal instead.\n\n<a id=\"webhooks-request-format\"></a>\n\n### Request format\n\nEach delivery sends a JSON body with this shape:\n\n```json\n{\n \"version\": 1,\n \"type\": \"project_created\",\n \"occurredAt\": \"2026-01-01T12:00:00.000Z\",\n \"data\": { /* event-specific payload, see the events below */ }\n}\n```\n\nPayloads are deliberately thin: they identify what happened and which resources were involved, but do not embed resource snapshots. Fetch the current state of an affected resource through the corresponding API v3 endpoint — for example, a `project_created` delivery carries a `projectId` to fetch via [**Residential Projects**](#tag/residential-projects) or [**Commercial Projects**](#tag/commercial-projects), depending on its `projectType`.\n\nEvent metadata is also sent in headers:\n\n| Header | Meaning |\n|---|---|\n| `X-Reonic-Event` | Event type for this webhook delivery. Matches the `type` field in the body. |\n| `X-Reonic-Client-Id` | Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature. |\n| `X-Reonic-Event-Id` | Stable event id, identical across redeliveries of the same event. Use this as your idempotency key. |\n| `X-Reonic-Delivery-Id` | Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery. |\n| `X-Reonic-Timestamp` | Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`. |\n| `X-Reonic-Signature` | HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`. |\n\n<a id=\"webhooks-verify-signatures\"></a>\n\n### Verify signatures\n\nVerifying signatures is optional but strongly recommended: it proves a delivery was really sent by Reonic and not by someone who discovered your URL. If your tool cannot compute HMAC digests, keep your webhook URL secret and treat the data accordingly.\n\nCompute an HMAC SHA-256 digest with your webhook signing secret over `${timestamp}.${rawBody}`, then compare it to `X-Reonic-Signature`. Use the raw request body exactly as received, before JSON parsing. Reject deliveries whose `X-Reonic-Timestamp` is more than 5 minutes old to reduce replay risk — retries are signed freshly, so a legitimate delivery never carries an old timestamp.\n\nCode example:\n\n```ts\nimport { createHmac, timingSafeEqual } from \"crypto\";\n\nconst timestamp = request.headers[\"x-reonic-timestamp\"];\nconst signature = request.headers[\"x-reonic-signature\"];\n\nconst expected = Buffer.from(\"sha256=\" + createHmac(\"sha256\", secret)\n .update(`${timestamp}.${rawBody}`)\n .digest(\"hex\"));\nconst received = Buffer.from(signature);\n\nconst isValid = expected.length === received.length && timingSafeEqual(expected, received);\n```\n\n### Retries and idempotency\n\nRespond with any `2xx` status code once you have accepted the event — automation tools like Zapier and n8n do this for you. Every other response, as well as network errors and timeouts, is retried automatically, roughly 1 min, 5 min, 30 min, 2 h, 5 h, 12 h, 1 d, 2 d after the initial attempt.\n\nDelivery order is not guaranteed, and the same event may be delivered more than once, so store `X-Reonic-Event-Id` and ignore duplicates.\n\n> [!warning]\n> If all retries are exhausted, Reonic disables the webhook subscription and notifies your workspace's contact email. Re-enable it in the webhook settings once your endpoint is fixed.\n\n### When deliveries fail\n\nThe webhook settings in the Portal include a delivery log with every attempt, the response status or error we recorded, and the payload that was sent. Failed deliveries can be retried manually from there — including after you fix your endpoint and re-enable a disabled subscription.\n\n### Compatibility\n\nThe body's `version` (currently 1) only changes when the envelope shape itself — `version`, `type`, `occurredAt`, `data` — changes in a breaking way. New event types, new fields inside `data`, and new headers may appear without a version bump, so ignore anything you don't recognize."
paths: {}
webhooks:
residentialProject_created:
post:
operationId: webhookV2_residentialProject_created
summary: Residential project created
description: 'Sent when a residential project is created.
**Deprecated** — subscribe to `project_created` instead: it covers both verticals and carries a `projectType`.'
deprecated: true
tags:
- Webhooks
parameters:
- schema:
type: string
enum:
- residentialProject_created
description: Event type for this webhook delivery. Matches the `type` field in the body.
required: true
description: Event type for this webhook delivery. Matches the `type` field in the body.
name: X-Reonic-Event
in: header
- schema:
type: string
format: uuid
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
name: X-Reonic-Client-Id
in: header
- schema:
type: string
format: uuid
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
name: X-Reonic-Event-Id
in: header
- schema:
type: string
format: uuid
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
name: X-Reonic-Delivery-Id
in: header
- schema:
type: string
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
example: '1710000000'
required: true
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
name: X-Reonic-Timestamp
in: header
- schema:
type: string
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
example: sha256=ecb03c3a8d08e7137151335708afb85d5ccd756dcdc0ce21245827a56976524e
required: true
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
name: X-Reonic-Signature
in: header
requestBody:
description: The message we send to your configured URL when this event happens.
content:
application/json:
schema:
type: object
properties:
version:
type: number
enum:
- 1
description: Version of the public webhook body contract.
example: 1
type:
type: string
enum:
- residentialProject_created
description: Event type for this delivery. Matches the `X-Reonic-Event` header.
example: residentialProject_created
occurredAt:
type: string
format: date-time
description: When the event occurred, as an ISO 8601 timestamp.
example: '2026-01-01T15:30:00.000Z'
data:
type: object
properties:
projectId:
type: string
format: uuid
description: ID of the project this event relates to. Fetch its current state via [**Residential Projects**](#tag/residential-projects).
example: 123e4567-e89b-12d3-a456-426614174000
required:
- projectId
required:
- version
- type
- occurredAt
- data
description: Webhook body for `residentialProject_created`.
responses:
2XX:
description: Return any 2xx status code to acknowledge successful receipt.
commercialProject_created:
post:
operationId: webhookV2_commercialProject_created
summary: Commercial project created
description: 'Sent when a commercial project is created.
**Deprecated** — subscribe to `project_created` instead: it covers both verticals and carries a `projectType`.'
deprecated: true
tags:
- Webhooks
parameters:
- schema:
type: string
enum:
- commercialProject_created
description: Event type for this webhook delivery. Matches the `type` field in the body.
required: true
description: Event type for this webhook delivery. Matches the `type` field in the body.
name: X-Reonic-Event
in: header
- schema:
type: string
format: uuid
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
name: X-Reonic-Client-Id
in: header
- schema:
type: string
format: uuid
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
name: X-Reonic-Event-Id
in: header
- schema:
type: string
format: uuid
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
name: X-Reonic-Delivery-Id
in: header
- schema:
type: string
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
example: '1710000000'
required: true
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
name: X-Reonic-Timestamp
in: header
- schema:
type: string
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
example: sha256=ecb03c3a8d08e7137151335708afb85d5ccd756dcdc0ce21245827a56976524e
required: true
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
name: X-Reonic-Signature
in: header
requestBody:
description: The message we send to your configured URL when this event happens.
content:
application/json:
schema:
type: object
properties:
version:
type: number
enum:
- 1
description: Version of the public webhook body contract.
example: 1
type:
type: string
enum:
- commercialProject_created
description: Event type for this delivery. Matches the `X-Reonic-Event` header.
example: commercialProject_created
occurredAt:
type: string
format: date-time
description: When the event occurred, as an ISO 8601 timestamp.
example: '2026-01-01T15:30:00.000Z'
data:
type: object
properties:
projectId:
type: string
format: uuid
description: ID of the project this event relates to. Fetch its current state via [**Commercial Projects**](#tag/commercial-projects).
example: 123e4567-e89b-12d3-a456-426614174000
required:
- projectId
required:
- version
- type
- occurredAt
- data
description: Webhook body for `commercialProject_created`.
responses:
2XX:
description: Return any 2xx status code to acknowledge successful receipt.
residentialOffer_signatureRequested:
post:
operationId: webhookV2_residentialOffer_signatureRequested
summary: Residential offer signature requested
description: Sent when a signature is requested for a residential offer.
tags:
- Webhooks
parameters:
- schema:
type: string
enum:
- residentialOffer_signatureRequested
description: Event type for this webhook delivery. Matches the `type` field in the body.
required: true
description: Event type for this webhook delivery. Matches the `type` field in the body.
name: X-Reonic-Event
in: header
- schema:
type: string
format: uuid
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
name: X-Reonic-Client-Id
in: header
- schema:
type: string
format: uuid
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
name: X-Reonic-Event-Id
in: header
- schema:
type: string
format: uuid
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
name: X-Reonic-Delivery-Id
in: header
- schema:
type: string
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
example: '1710000000'
required: true
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
name: X-Reonic-Timestamp
in: header
- schema:
type: string
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
example: sha256=ecb03c3a8d08e7137151335708afb85d5ccd756dcdc0ce21245827a56976524e
required: true
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
name: X-Reonic-Signature
in: header
requestBody:
description: The message we send to your configured URL when this event happens.
content:
application/json:
schema:
type: object
properties:
version:
type: number
enum:
- 1
description: Version of the public webhook body contract.
example: 1
type:
type: string
enum:
- residentialOffer_signatureRequested
description: Event type for this delivery. Matches the `X-Reonic-Event` header.
example: residentialOffer_signatureRequested
occurredAt:
type: string
format: date-time
description: When the event occurred, as an ISO 8601 timestamp.
example: '2026-01-01T15:30:00.000Z'
data:
type: object
properties:
projectId:
type: string
format: uuid
description: ID of the project this event relates to. Fetch its current state via [**Residential Projects**](#tag/residential-projects).
example: 123e4567-e89b-12d3-a456-426614174000
signatureRequestId:
type: string
format: uuid
description: ID of the signature request. Listed under `signatureRequests` on the [**Residential Projects**](#tag/residential-projects) detail response.
example: 123e4567-e89b-12d3-a456-426614174000
variantIds:
type: array
items:
type: string
format: uuid
description: The offer variants presented to the customer for signature.
example:
- 123e4567-e89b-12d3-a456-426614174000
- 123e4567-e89b-12d3-a456-426614174002
signatureOptions:
type: array
items:
type: object
properties:
variantId:
type: string
format: uuid
description: The offer variant this signature option belongs to.
example: 123e4567-e89b-12d3-a456-426614174000
paymentOptionId:
type:
- string
- 'null'
format: uuid
description: The payment option this signature option belongs to. `null` for legacy/default-payment documents.
example: 123e4567-e89b-12d3-a456-426614174002
required:
- variantId
- paymentOptionId
description: The variant/payment option combinations presented to the customer for signature.
required:
- projectId
- signatureRequestId
- variantIds
required:
- version
- type
- occurredAt
- data
description: Webhook body for `residentialOffer_signatureRequested`.
responses:
2XX:
description: Return any 2xx status code to acknowledge successful receipt.
residentialOffer_signed:
post:
operationId: webhookV2_residentialOffer_signed
summary: Residential offer signed
description: Sent when a residential offer is signed. A signed offer can still be withdrawn by the customer within the legal withdrawal period — also subscribe to `residentialOffer_signatureWithdrawn` if you act on this event.
tags:
- Webhooks
parameters:
- schema:
type: string
enum:
- residentialOffer_signed
description: Event type for this webhook delivery. Matches the `type` field in the body.
required: true
description: Event type for this webhook delivery. Matches the `type` field in the body.
name: X-Reonic-Event
in: header
- schema:
type: string
format: uuid
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Id of the sending client. Stable across deliveries. If one endpoint receives webhooks from multiple clients, use this to pick the matching signing secret before verifying the signature.
name: X-Reonic-Client-Id
in: header
- schema:
type: string
format: uuid
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Stable event id, identical across redeliveries of the same event. Use this as your idempotency key.
name: X-Reonic-Event-Id
in: header
- schema:
type: string
format: uuid
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
example: 123e4567-e89b-12d3-a456-426614174000
required: true
description: Unique id of this delivery attempt. Unlike the event id, it changes on every redelivery — reference it when reporting issues with a specific delivery.
name: X-Reonic-Delivery-Id
in: header
- schema:
type: string
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
example: '1710000000'
required: true
description: Unix timestamp in seconds at which this delivery was signed. Changes on every redelivery — verify signatures against this value, not the body's `occurredAt`.
name: X-Reonic-Timestamp
in: header
- schema:
type: string
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
example: sha256=ecb03c3a8d08e7137151335708afb85d5ccd756dcdc0ce21245827a56976524e
required: true
description: HMAC SHA-256 signature in the format `sha256=<hex>`, computed over `${timestamp}.${rawBody}`.
name: X-Reonic-Signature
in: header
requestBody:
description: The message we send to your configured URL when this event happens.
content:
application/json:
schema:
type: object
properties:
version:
type: number
enum:
- 1
description: Version of the public webhook body contract.
example: 1
type:
type: string
enum:
- residentialOffer_signed
description: Event type for this delivery. Matches the `X-Reonic-Event` header.
example: residentialOffer_signed
occurredAt:
type: string
format: date-time
description: When the event occurred, as an ISO 8601 timestamp.
example: '2026-01-01T15:30:00.000Z'
data:
type: object
properties:
projectId:
type: string
format: uuid
description: ID of the project this event relates to. Fetch its current state via [**Residential Projects**](#tag/residential-projects).
example: 123e4567-e89b-12d3-a456-426614174000
signatureRequestId:
type: string
format: uuid
description: ID of the signature request. Listed under `signatureRequests` on the [**Residential Projects**](#tag/residential-projects) detail response.
example: 123e4567-e89b-12d3-a456-426614174000
signedVariantId:
type: string
format: uuid
description: The offer variant the customer signed.
example: 123e4567-e89b-12d3-a456-426614174000
signedPaymentOptionId:
type:
- string
- 'null'
format: uuid
description: The payment option the customer signed. `null` for legacy/default-payment documents.
example: 123e4567-e89b-12d3-a456-426614174000
required:
- projectId
- signatureRequestId
- signedVariantId
required:
- version
- type
- occurredAt
- data
description: Webhook body for `residentialOffer_signed`.
responses:
2XX:
description: Return any
# --- truncated at 32 KB (105 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/reonic/refs/heads/main/openapi/reonic-webhooks-api-openapi.yml