diff --git a/docs/integrations/core-events.md b/docs/integrations/core-events.md
index 02edf5b..6df4e83 100644
--- a/docs/integrations/core-events.md
+++ b/docs/integrations/core-events.md
@@ -36,6 +36,8 @@ All events include these fields:
### Customer
+
+
### Billing Account
@@ -76,4 +78,4 @@ These events are triggered manually via automation.
-
\ No newline at end of file
+
diff --git a/docs/integrations/integration-toolkit/configuration.md b/docs/integrations/integration-toolkit/configuration.md
index 500764b..4d9a334 100644
--- a/docs/integrations/integration-toolkit/configuration.md
+++ b/docs/integrations/integration-toolkit/configuration.md
@@ -122,7 +122,7 @@ curl -X POST 'https://erp-integration.sls.epilot.io/v1/integrations/{integration
| `configuration` | object | Yes | Type-specific configuration (see sections below) |
:::info
-- `file_proxy` — On-demand file serving from external document systems. See the [File Proxy guide](./file-proxy.md).
+- `file_proxy` — On-demand file serving from external systems or outbound delivery of epilot files. See the [File Proxy](./file-proxy.md) and [Outbound File Delivery](./outbound-file-delivery.md) guides.
- `managed_call` — Synchronous external API calls with JSONata mapping. See [Managed Call Use Cases](#managed-call-use-cases).
- `secure_proxy` — Route requests through epilot's secure proxy for static IP or VPN access. See [Secure Proxy Use Cases](#secure-proxy-use-cases).
:::
@@ -181,11 +181,11 @@ curl -X POST 'https://erp-integration.sls.epilot.io/v1/integrations/{integration
| Property | Type | Required | Description |
|----------|------|----------|-------------|
-| `id` | string (UUID) | Yes | Unique identifier for the mapping |
+| `id` | string (UUID) | No | Unique identifier for the mapping; generated when omitted |
| `name` | string | Yes | Display name for the mapping |
| `enabled` | boolean | Yes | Whether this mapping is active |
-| `jsonata_expression` | string | For `webhook` delivery | JSONata expression to transform the event payload. Required for `webhook` delivery; ignored for `poll` delivery |
-| `delivery` | object | Yes | How the event is delivered — discriminated on `type`: `webhook` or `poll` |
+| `jsonata_expression` | string | For `webhook` delivery | JSONata expression to transform the event payload. Required for `webhook`, ignored for `poll`, and rejected for `file_proxy` delivery |
+| `delivery` | object | Yes | How the event is delivered — discriminated on `type`: `webhook`, `poll`, or `file_proxy` |
#### Delivery Types
@@ -228,6 +228,19 @@ curl -X POST 'https://erp-integration.sls.epilot.io/v1/integrations/{integration
Everything beyond the configuration contract — the polling and acknowledgement API, lease and ordering semantics, retention and expiry behavior, the dead-letter queue and operator actions, and poll-mode monitoring — is documented on the dedicated [Pollable Outbound](./pollable-outbound.md) page.
+**File proxy delivery (push):** points to an upload-direction `file_proxy` use case in the same integration. The referenced recipe owns fan-out, payload mapping, file selection, authentication, and HTTP steps. `jsonata_expression` is rejected on this mapping type. See [Outbound File Delivery](./outbound-file-delivery.md) for the complete setup and runtime behavior.
+
+```json
+"delivery": {
+ "type": "file_proxy",
+ "use_case_slug": "customer-request-document-upload"
+}
+```
+
+| Property | Type | Required | Description |
+| --- | --- | --- | --- |
+| `use_case_slug` | string | Yes | Slug of an upload-direction `file_proxy` use case in the same integration |
+
## Mapping Configuration Schema
### Version 2.0 Structure
diff --git a/docs/integrations/integration-toolkit/external-monitoring-events.md b/docs/integrations/integration-toolkit/external-monitoring-events.md
index 5f25fef..7214abf 100644
--- a/docs/integrations/integration-toolkit/external-monitoring-events.md
+++ b/docs/integrations/integration-toolkit/external-monitoring-events.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 7
+sidebar_position: 8
title: External Monitoring Events
description: Push monitoring events from an external system (e.g. an integration middleware) into epilot so the Integration Hub is your central monitoring point, with a cross-system event trace
slug: /integrations/integration-toolkit/external-monitoring-events
diff --git a/docs/integrations/integration-toolkit/file-proxy.md b/docs/integrations/integration-toolkit/file-proxy.md
index bdb3036..83566c9 100644
--- a/docs/integrations/integration-toolkit/file-proxy.md
+++ b/docs/integrations/integration-toolkit/file-proxy.md
@@ -7,6 +7,10 @@ slug: /integrations/integration-toolkit/file-proxy
# File Proxy
+:::info File direction
+This page covers files moving **into epilot on demand** from an external archive. To deliver files referenced by epilot events to an external API, see [Outbound File Delivery](./outbound-file-delivery.md).
+:::
+
The File Proxy enables epilot to serve files from external document systems (e.g., ERP document archives, document management systems) **on demand**, without migrating files into epilot's storage. During [inbound sync](./inbound/getting-started.md), file entities are created with a `custom_download_url` pointing to the file proxy. When a user views the file, epilot's file service verifies the request and the proxy fetches the document from the external system in real time.
Each file proxy configuration is stored as a **use case** with `type: 'file_proxy'` within an integration. The configuration describes how to authenticate, which HTTP calls to make, and how to extract the file from the response — all declaratively, without code changes for new integrations.
diff --git a/docs/integrations/integration-toolkit/outbound-file-delivery.md b/docs/integrations/integration-toolkit/outbound-file-delivery.md
new file mode 100644
index 0000000..7c60ad7
--- /dev/null
+++ b/docs/integrations/integration-toolkit/outbound-file-delivery.md
@@ -0,0 +1,312 @@
+---
+sidebar_position: 7
+title: Outbound File Delivery
+description: Deliver files referenced by epilot events to an external API with fan-out, mapping, retries, and monitoring
+slug: /integrations/integration-toolkit/outbound-file-delivery
+---
+
+# Outbound File Delivery
+
+Outbound file delivery sends files referenced by an epilot event to an external document API. The Integration Toolkit fetches each file from epilot, maps the event and file into the target API's format, and runs a declarative HTTP workflow.
+
+`CustomerRequestSubmitted` is the main example: one submitted request can contain several `event_attachments`, and each attachment is delivered and monitored independently.
+
+:::caution Attachment readiness
+
+`CustomerRequestSubmitted` is emitted when the ticket is created. In the standard Journey flow, the file entities already exist, but automation creates the ticket and copies its file relations in a second request. Event Catalog processes the ticket creation asynchronously and reads the current relation graph. The relation request usually finishes first, which is why the attachments are normally present, but this ordering is not guaranteed. The later relation write does not emit another `CustomerRequestSubmitted` or automatically replay an empty snapshot.
+
+Without an attachment-count `event_filter`, an empty fan-out records `FAN_OUT_EMPTY`. With the example `$count(event_attachments) > 0` filter below, the use case is filtered out before fan-out, so no delivery is enqueued and no `FAN_OUT_EMPTY` is emitted for that mapping.
+
+If the integration needs strict ordering after ticket creation, use a `FileUpdated` handoff after the workflow writes the ticket reference onto the file, or trigger a dedicated workflow event after all relations are complete.
+
+:::
+
+:::info Upload versus download
+This page covers files moving **out of epilot**. To serve files from an external archive when a user opens them in epilot, use the [download File Proxy](./file-proxy.md).
+:::
+
+## How it works
+
+The setup uses two use cases in the same integration:
+
+| Use case | Decides | Configuration |
+| --- | --- | --- |
+| `outbound` | **When** to deliver | Event Catalog event, optional event filter, and a pointer to the upload recipe |
+| `file_proxy` with `direction: "upload"` | **What and how** to deliver | Fan-out, file selection, mapping, authentication, HTTP steps, limits, and success criteria |
+
+```mermaid
+sequenceDiagram
+ participant Event as Event Catalog
+ participant Outbound as Outbound delivery
+ participant Queue as File delivery queue
+ participant File as epilot File API
+ participant Target as External document API
+
+ Event->>Outbound: CustomerRequestSubmitted
+ Outbound->>Outbound: Apply event_filter and fan_out
+ loop Each event attachment
+ Outbound->>Queue: Enqueue durable delivery
+ Queue->>File: Fetch entity_id + version_index
+ File-->>Queue: File bytes and metadata
+ Queue->>Queue: Evaluate lookups and params_mapping
+ Queue->>Target: Execute configured HTTP steps
+ Target-->>Queue: Result / external document ID
+ end
+```
+
+The outbound delivery is a pure pointer to the file-proxy use-case slug. The recipe is resolved at runtime, so you can create the two use cases in either order. A missing or disabled target is visible through monitoring and the outbound status endpoint.
+
+## Before you start
+
+You need:
+
+- an Integration Toolkit integration;
+- an Event Catalog event containing a file reference, such as [`CustomerRequestSubmitted`](/docs/integrations/core-events#customer);
+- an external HTTP endpoint that accepts the file; and
+- environment values for target URLs and credentials.
+
+The examples use the Integration Toolkit API at `https://integration-toolkit.sls.epilot.io`.
+
+## 1. Create the upload recipe
+
+Create a `file_proxy` use case with `direction: "upload"`:
+
+```bash
+curl -X POST 'https://integration-toolkit.sls.epilot.io/v1/integrations/{integrationId}/use-cases' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "name": "Customer request document upload",
+ "slug": "customer-request-document-upload",
+ "type": "file_proxy",
+ "enabled": true,
+ "configuration": {
+ "direction": "upload",
+ "fan_out": {
+ "enabled": true,
+ "split_expression": "event_attachments"
+ },
+ "lookups": {
+ "documentType": {
+ "source": "ticket._purpose[0]",
+ "entries": {
+ "termination": "CANCELLATION",
+ "complaint": "COMPLAINT"
+ },
+ "default": "OTHER",
+ "on_miss": "warn"
+ }
+ },
+ "constants": {
+ "sourceSystem": "epilot"
+ },
+ "params_mapping": "{ \"customerNumber\": contact.customer_number, \"filename\": $item.filename, \"mimeType\": $file.mime_type, \"fileData\": $file_base64, \"documentType\": $lookups.documentType, \"submittedAt\": $germanDate($now()) }",
+ "required_params": ["customerNumber", "filename", "fileData"],
+ "auth": {
+ "type": "oauth2_client_credentials",
+ "token_url": "\\{{env.DOCUMENT_TOKEN_URL}}",
+ "client_id": "\\{{env.DOCUMENT_CLIENT_ID}}",
+ "client_secret": "\\{{env.DOCUMENT_CLIENT_SECRET}}"
+ },
+ "steps": [
+ {
+ "method": "POST",
+ "url": "\\{{env.DOCUMENT_API_URL}}/documents",
+ "headers": {
+ "Authorization": "Bearer {{auth_token}}",
+ "Content-Type": "application/json",
+ "Idempotency-Key": "{{custom_key}}"
+ },
+ "body": "{\"customerNumber\":{{json params.customerNumber}},\"filename\":{{json params.filename}},\"mimeType\":{{json params.mimeType}},\"fileData\":{{json params.fileData}},\"documentType\":{{json params.documentType}},\"sourceSystem\":{{json params.sourceSystem}}}",
+ "response_type": "json"
+ }
+ ],
+ "upload": {
+ "max_file_bytes": 104857600,
+ "max_delivery_attempts": 8,
+ "success_when": "statusCode >= 200 and statusCode < 300",
+ "external_id": "steps[-1].body.documentId"
+ }
+ }
+ }'
+```
+
+### Upload configuration
+
+| Field | Required | Description |
+| --- | --- | --- |
+| `direction` | Yes | Must be `upload`. Omitting it means the existing download behavior. |
+| `steps` | Yes | One or more HTTP requests. Upload steps support `GET`, `POST`, `PUT`, and `PATCH`. |
+| `upload` | Yes | File-size limit, retry limit, optional success predicate, and external ID expression. |
+| `params_mapping` | Yes | JSONata expression returning the `params` object used by HTTP templates. |
+| `fan_out` | No | Splits one event into independent deliveries. Required for one upload per attachment. |
+| `file_source` | No | JSONata selecting the attachment-shaped file reference when the fan-out item is not itself an attachment. |
+| `lookups` | No | Named code translations evaluated before `params_mapping`. |
+| `constants` | No | Static values merged underneath the mapped parameters. |
+| `required_params` | No | Parameters that must not be absent, `null`, or empty before any HTTP request is sent. |
+| `auth` | No | OAuth2 client credentials or password authentication. |
+| `secure_proxy` | No | Routes the steps through a `secure_proxy` use case in the same integration. |
+
+Download-only fields such as `params`, `response`, `allowed_origins`, and `prevent_indirect_serving` are rejected for upload recipes.
+
+## 2. Subscribe to the event
+
+Create an outbound use case whose delivery points to the upload recipe's slug:
+
+```bash
+curl -X POST 'https://integration-toolkit.sls.epilot.io/v1/integrations/{integrationId}/use-cases' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "name": "Deliver customer request documents",
+ "slug": "deliver-customer-request-documents",
+ "type": "outbound",
+ "enabled": true,
+ "configuration": {
+ "event_catalog_event": "CustomerRequestSubmitted",
+ "event_filter": "$count(event_attachments) > 0",
+ "ack_tracking": "off",
+ "mappings": [
+ {
+ "name": "External document archive",
+ "enabled": true,
+ "delivery": {
+ "type": "file_proxy",
+ "use_case_slug": "customer-request-document-upload"
+ }
+ }
+ ]
+ }
+ }'
+```
+
+Do not add `jsonata_expression` to a `file_proxy` outbound mapping. The referenced recipe owns payload mapping, and the API rejects an expression that would otherwise be ignored. Mapping IDs and timestamps are generated when omitted.
+
+Use `ack_tracking: "off"` for a file-only outbound use case: durable delivery state is tracked per file. If a webhook mapping in the same outbound use case requires acknowledgements, keep acknowledgement tracking enabled or separate the webhook and file deliveries.
+
+Check target resolution with:
+
+```http
+GET /v1/integrations/{integrationId}/outbound-status
+```
+
+## Fan-out and file selection
+
+`fan_out.split_expression` runs once when the event is enqueued and must return an array. Every item becomes an independent delivery with its own status, retries, and idempotency record.
+
+For `CustomerRequestSubmitted`, use `event_attachments`. Each item already contains `entity_id` and `version_index`, so the worker recognizes it as a file reference without `file_source`.
+
+```json
+"fan_out": {
+ "enabled": true,
+ "split_expression": "event_attachments[$count(_tags[$ = 'customer-document']) > 0]"
+}
+```
+
+Use `event_filter` to decide whether the event should be handled at all. Use `fan_out.split_expression` only to select the items delivered from a handled event.
+
+- An empty, missing, or `null` result produces no deliveries and records `FAN_OUT_EMPTY`.
+- A non-array result fails with `FAN_OUT_INVALID_RESULT`.
+- With fan-out disabled, the event produces one delivery and `$item` is not bound.
+
+If you split over something other than attachments, set `file_source` to an expression that returns the corresponding attachment:
+
+```json
+"file_source": "event_attachments[entity_id = $item.file_id][0]"
+```
+
+If no file resolves, the workflow can still send metadata. Include the mapped file value in `required_params` when bytes are mandatory.
+
+## Mapping values
+
+The JSONata root is the complete event. Event fields such as `contact.customer_number` and `ticket._purpose` are read directly. Per-delivery values are `$`-prefixed bindings:
+
+| JSONata value | Contains |
+| --- | --- |
+| `$item` | Current fan-out item |
+| `$file_base64` | File content encoded as base64 |
+| `$file` | `filename`, `mime_type`, and `size_bytes` from the resolved file |
+| `$constants` | Configured static values |
+| `$lookups` | Resolved lookup results |
+| `$ack_id` | Triggering event acknowledgement ID, when present |
+| `$now()` | Current ISO timestamp |
+| `$germanDate(iso)` | An ISO timestamp formatted as a German date |
+
+:::warning JSONata bindings
+Write `$item.filename` and `$file_base64`, including the `$`. `item.filename` reads a root event property named `item` and silently produces no value.
+:::
+
+Lookups support `on_miss: "default"`, `"warn"`, or `"fail"`. Warning mode continues with the configured default and records `LOOKUP_UNMAPPED`; fail mode stops that delivery.
+
+## Building HTTP steps safely
+
+HTTP steps use Handlebars after JSONata has produced `params`. The template context provides `params.*`, `item`, `event.id`, `event.name`, `custom_key`, earlier `steps.N.*`, and `auth_token`.
+
+Always use the `json` helper for values inserted into JSON bodies:
+
+```handlebars
+{
+ "filename": {{json params.filename}},
+ "fileData": {{json params.fileData}}
+ {{#if params.customerNumber}},
+ "customerNumber": {{json params.customerNumber}}
+ {{/if}}
+}
+```
+
+Plain interpolation does not safely serialize quotes or control characters. `#if` is supported in JSON bodies; unsafe `#each` and `#with` blocks are rejected during validation.
+
+Environment values are resolved after Handlebars. In the JSON sent to the API, write `"\\{{env.NAME}}"`. The leading backslash preserves the placeholder through Handlebars and is removed before environment resolution.
+
+## Delivery behavior
+
+- Delivery is **at least once**. Normal queue redelivery is deduplicated by a durable per-file record retained for 30 days.
+- A failure after the target accepts a file but before epilot commits success can still repeat the request. Pass `{{custom_key}}` to the target and make it an idempotency key.
+- The upload recipe is read again for queued retries, subject to a short cache. Correcting configuration affects later attempts without replaying the source event.
+- `upload.max_delivery_attempts` defaults to 8 and supports 1–100 attempts with jittered backoff.
+- `upload.max_file_bytes` defaults to the platform maximum of 100 MiB. Known size is checked before fetch; the limit is always enforced while buffering.
+- `upload.success_when` can reject a nominally successful response, such as an HTTP 200 response containing an error envelope.
+- `upload.external_id` records the target document ID without failing an otherwise successful delivery if extraction is unsuccessful.
+- External HTTP `408`, `429`, and `5xx` responses are retried. Other `4xx` responses are terminal. Timeouts, OAuth refresh failures, and transient file-fetch failures are retried up to the configured attempt limit.
+- Configuration and data errors that will not improve on retry—such as a missing file, invalid mapping result, missing required parameter, or invalid step template—fail terminally. JSONata expressions and Handlebars syntax are also checked when the recipe is saved.
+- Terminal and exhausted deliveries are recorded as failed and completed without deliberately filling the dead-letter queue with permanent errors.
+
+## Monitoring
+
+Every per-file monitoring event uses the source Event Catalog `_event_id` as both `event_id` and `correlation_id`. Details include the use case, mapping, attachment, item index, attempt, and external ID where available.
+
+| Level | Code | Meaning |
+| --- | --- | --- |
+| Success | `FILE_PROXY_UPLOADED` | The target accepted the file workflow. |
+| Info | `FILE_PROXY_UPLOAD_ENQUEUED` | A per-file delivery was queued. |
+| Info | `FAN_OUT_EMPTY` | The event had no matching items. |
+| Warning | `FILE_PROXY_UPLOAD_RETRYING` | The delivery failed and will be attempted again. |
+| Warning / error | `LOOKUP_UNMAPPED` | A lookup missed; `warn` continues with a fallback, while `fail` stops the delivery. |
+| Error | `FILE_PROXY_UPLOAD_FAILED` | Delivery failed terminally or exhausted attempts. |
+| Error | `FILE_FETCH_FAILED` | File API did not return usable content. |
+| Error | `FILE_TOO_LARGE` | The file exceeded the recipe or platform limit. |
+| Error | `ATTACHMENT_NOT_FOUND` | The referenced file entity or version was not found. |
+| Error | `REQUIRED_PARAM_MISSING` | A required mapped parameter was absent. |
+| Error | `FAN_OUT_INVALID_RESULT` | The split expression returned a non-array value. |
+
+General configuration and mapping codes, including `USE_CASE_NOT_FOUND`, `USE_CASE_DISABLED`, and `MAPPING_EXPRESSION_FAILED`, can also apply. These are epilot-produced monitoring codes; they are separate from the `EXTERNAL_*` codes described in [External Monitoring Events](./external-monitoring-events.md).
+
+## Troubleshooting
+
+| Symptom | Check |
+| --- | --- |
+| Target is unresolved | The delivery's `use_case_slug` must match an enabled upload-direction `file_proxy` use case in the same integration. |
+| Mapped filename or bytes are empty | Per-item bindings require `$item` and `$file_base64`, including the `$`. |
+| Target URL or credentials are empty | Persist environment placeholders with a leading backslash: `\\{{env.NAME}}` in JSON. |
+| JSON body breaks for some filenames | Replace plain interpolation with `{{json params.filename}}`. |
+| Event succeeds without uploading | Inspect `FAN_OUT_EMPTY`, the split expression, and `event_filter`. |
+| File fetch fails | Verify `entity_id`, `version_index`, and the configured file-size limit. |
+| Target `4xx` is not retried | This is expected except for `408` and `429`; correct the request mapping or target configuration. |
+
+## Related documentation
+
+- [Core Events](/docs/integrations/core-events)
+- [Configuration](./configuration.md)
+- [File Proxy downloads](./file-proxy.md)
+- [External Monitoring Events](./external-monitoring-events.md)
+- [Pollable Outbound](./pollable-outbound.md)
diff --git a/docs/integrations/integration-toolkit/overview.md b/docs/integrations/integration-toolkit/overview.md
index 3c02db6..39ea430 100644
--- a/docs/integrations/integration-toolkit/overview.md
+++ b/docs/integrations/integration-toolkit/overview.md
@@ -35,6 +35,7 @@ The Integration Toolkit is composed of the following components. Each plays a sp
| **[Pollable Outbound](./pollable-outbound.md)** | Pull-based outbound delivery — ERPs poll a queue instead of receiving webhooks | In progress |
| **[JSONata Mapping](#jsonata-mapping)** | Transformation language for inbound and outbound data | Stable |
| **[File Proxy](./file-proxy.md)** | Serve files from external archives on demand without migrating them into epilot | Stable |
+| **[Outbound File Delivery](./outbound-file-delivery.md)** | Deliver files referenced by epilot events to external document APIs | Stable |
| **[Managed Calls](#managed-calls)** | Synchronous external API calls with JSONata mapping via connector integrations | Stable |
| **[Secure Proxy](#secure-proxy)** | Route HTTP requests through epilot's secure proxy for static IP egress or VPN access | Stable |
| **[Monitoring and ACKs](#monitoring-and-acks)** | Central logging, error tracking, and event replay | In progress |
@@ -87,6 +88,8 @@ See the [Use Cases](./use-cases.md) page for a complete list of inbound and outb
The [File Proxy](./file-proxy.md) enables epilot to serve files from external document systems (e.g., ERP archives, DMS) on demand. Instead of migrating file content during inbound sync, file entities are created with a `custom_download_url` pointing to the proxy. When a user views the file, the proxy fetches the document from the external system in real time using a declarative, multi-step HTTP configuration.
+The upload direction is documented separately as [Outbound File Delivery](./outbound-file-delivery.md). It subscribes to Event Catalog events, fans one event out into per-file deliveries, fetches the referenced epilot files, and runs a declarative external HTTP workflow with independent retries and monitoring.
+
### Managed Calls
Managed Calls enable synchronous API calls to external partner systems with built-in authentication, JSONata mapping, and optional inbound routing. They are configured as `managed_call` use cases within `connector`-type integrations.
@@ -152,7 +155,7 @@ Push epilot events to your ERP via webhooks. Typical flows:
- Self-service requests (IBAN changes, installment adjustments)
- Meter reading submissions
-Outbound events use [Core Events](/docs/integrations/core-events) and are delivered through [Webhooks](/docs/integrations/webhooks). JSONata transforms simplify payloads before delivery.
+Outbound events use [Core Events](/docs/integrations/core-events). They can be delivered through [Webhooks](/docs/integrations/webhooks), made available through [Pollable Outbound](./pollable-outbound.md), or used to [deliver referenced files](./outbound-file-delivery.md) to an external API. JSONata transforms simplify event and file payloads before delivery.
For ERPs that cannot receive webhooks (firewalled, on-prem, or batch-oriented systems), [Pollable Outbound](./pollable-outbound.md) offers a pull-based alternative: your middleware polls a queue inside the ERP Integration API on its own schedule and acknowledges items once consumed.
diff --git a/static/events/CustomerRequestSubmitted.config.json b/static/events/CustomerRequestSubmitted.config.json
new file mode 100644
index 0000000..2608f81
--- /dev/null
+++ b/static/events/CustomerRequestSubmitted.config.json
@@ -0,0 +1,209 @@
+{
+ "event_name": "CustomerRequestSubmitted",
+ "event_title": "Customer Request Submitted",
+ "event_description": "Triggered when a customer request ticket is created, including all files attached to the ticket",
+ "event_version": "1.0",
+ "event_tags": [
+ "builtin",
+ "erp",
+ "automation",
+ "ticket",
+ "attachment",
+ "customer-request"
+ ],
+ "schema_fields": {
+ "operation": {
+ "json_schema": {
+ "type": "string",
+ "enum": [
+ "createEntity"
+ ],
+ "description": "The entity operation type that triggered this event"
+ },
+ "required": true
+ },
+ "activity_id": {
+ "json_schema": {
+ "type": "string",
+ "description": "Activity ID associated with this operation (ULID)",
+ "example": "01F130Q52Q6MWSNS8N2AVXV4JN"
+ },
+ "required": false
+ },
+ "activity_type": {
+ "json_schema": {
+ "type": "string",
+ "description": "Activity type (e.g., EntityCreated, EntityUpdated)",
+ "example": "EntityUpdated"
+ },
+ "required": false
+ },
+ "trigger_entity": {
+ "json_schema": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Entity ID of the entity that triggered this event"
+ },
+ "required": true
+ },
+ "event_attachments": {
+ "json_schema": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entity_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Entity ID of the file"
+ },
+ "filename": {
+ "type": "string",
+ "description": "Name of the file"
+ },
+ "mime_type": {
+ "type": "string",
+ "description": "MIME type of the file (e.g., application/pdf)"
+ },
+ "size_bytes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "File size in bytes"
+ },
+ "s3ref": {
+ "type": "object",
+ "properties": {
+ "bucket": {
+ "type": "string",
+ "description": "S3 bucket name"
+ },
+ "key": {
+ "type": "string",
+ "description": "S3 object key"
+ }
+ },
+ "required": [
+ "bucket",
+ "key"
+ ],
+ "additionalProperties": false,
+ "description": "S3 reference for the file content"
+ },
+ "version_index": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Latest version index of the file (versions[].length - 1, or 0 if no versions array)"
+ },
+ "readable_size": {
+ "type": "string",
+ "description": "Human-readable file size (e.g., \"200 KB\")"
+ },
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Tags on the file entity (semantic labels set by uploader/automation)"
+ },
+ "relation_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Tags on the ticket→file relation (e.g. journey step label like \"_hidden_ Neuer Schritt - Nachweis\" plus the upload block's configured tags)"
+ },
+ "category": {
+ "type": "string",
+ "description": "File category select value (e.g., \"address-suggestions\", \"unknown\")"
+ },
+ "file_date": {
+ "type": "string",
+ "description": "User-provided file date"
+ },
+ "_created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the file entity was created — useful for time-window filtering"
+ }
+ },
+ "required": [
+ "entity_id",
+ "version_index"
+ ],
+ "additionalProperties": false
+ },
+ "description": "All files related to the ticket. A single submission can carry many documents across several upload blocks. Consumers identify a given upload via `relation_tags` / `_tags` and scope the use case via the `_purpose` taxonomy IDs on the ticket node (IDs only — resolving them to names is up to the consumer)."
+ },
+ "required": false,
+ "graph_source": "[ticket_files.{\"entity_id\": _id, \"filename\": filename, \"mime_type\": mime_type, \"size_bytes\": size_bytes, \"s3ref\": s3ref, \"version_index\": ($count(versions) > 0 ? $count(versions) - 1 : 0), \"readable_size\": readable_size, \"_tags\": _tags, \"relation_tags\": relation_tags, \"category\": category, \"file_date\": file_date, \"_created_at\": _created_at}]"
+ }
+ },
+ "entity_graph": {
+ "nodes": [
+ {
+ "id": "ticket",
+ "schema": "ticket",
+ "cardinality": "one"
+ },
+ {
+ "id": "submission",
+ "schema": "submission",
+ "cardinality": "one",
+ "fields": [
+ "_id"
+ ]
+ },
+ {
+ "id": "contact",
+ "schema": "contact",
+ "cardinality": "one"
+ },
+ {
+ "id": "contract",
+ "schema": "contract",
+ "cardinality": "one"
+ },
+ {
+ "id": "billing_account",
+ "schema": "billing_account",
+ "cardinality": "one"
+ },
+ {
+ "id": "ticket_files",
+ "schema": "file",
+ "cardinality": "many"
+ }
+ ],
+ "edges": [
+ {
+ "from": "ticket",
+ "to": "submission"
+ },
+ {
+ "from": "ticket",
+ "to": "contact"
+ },
+ {
+ "from": "ticket",
+ "to": "contract"
+ },
+ {
+ "from": "ticket",
+ "to": "billing_account"
+ },
+ {
+ "from": "ticket",
+ "to": "ticket_files"
+ }
+ ]
+ },
+ "entity_operation": {
+ "operation": [
+ "createEntity"
+ ],
+ "schema": [
+ "ticket"
+ ]
+ },
+ "automation_trigger": true
+}
\ No newline at end of file
diff --git a/static/events/CustomerRequestSubmitted.sample.json b/static/events/CustomerRequestSubmitted.sample.json
new file mode 100644
index 0000000..887d0d0
--- /dev/null
+++ b/static/events/CustomerRequestSubmitted.sample.json
@@ -0,0 +1,300 @@
+{
+ "_org_id": "123",
+ "_event_time": "1970-01-01T00:00:00.000Z",
+ "_event_id": "string",
+ "_event_name": "CustomerRequestSubmitted",
+ "_event_version": "1.0",
+ "_event_source": "string",
+ "_ack_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_trigger_source_type": "api",
+ "_trigger_source": "api_123456",
+ "_has_pending_changesets": true,
+ "_changeset_edit_modes": [
+ "string"
+ ],
+ "_changeset_attributes": [
+ "string"
+ ],
+ "_changeset_edit_modes_by_attribute": {},
+ "operation": "createEntity",
+ "activity_id": "01F130Q52Q6MWSNS8N2AVXV4JN",
+ "activity_type": "EntityUpdated",
+ "trigger_entity": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "event_attachments": [
+ {
+ "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "filename": "string",
+ "mime_type": "string",
+ "size_bytes": 0,
+ "s3ref": {
+ "bucket": "string",
+ "key": "string"
+ },
+ "version_index": 0,
+ "readable_size": "string",
+ "_tags": [
+ "string"
+ ],
+ "relation_tags": [
+ "string"
+ ],
+ "category": "string",
+ "file_date": "string",
+ "_created_at": "1970-01-01T00:00:00.000Z"
+ }
+ ],
+ "ticket": {
+ "_schema": "ticket",
+ "_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_org": "123",
+ "_title": "John Doe",
+ "_tags": [
+ "family:label"
+ ],
+ "_purpose": {},
+ "ticket_title": "string",
+ "customer": {},
+ "ticket_number": "string",
+ "status": "Open",
+ "payment": [
+ {
+ "type": "payment_sepa",
+ "data": {
+ "bank_name": "Deutsche Bank",
+ "iban": "DE89370400440532013000",
+ "bic_number": "DEUTDEFF",
+ "fullname": "John Doe"
+ }
+ }
+ ],
+ "source": {},
+ "workflows": {},
+ "_files": {},
+ "_created_at": "1970-01-01T00:00:00.000Z",
+ "_updated_at": "1970-01-01T00:00:00.000Z"
+ },
+ "submission": {
+ "_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_schema": "submission",
+ "_org": "123"
+ },
+ "contact": {
+ "_schema": "contact",
+ "_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_org": "123",
+ "_title": "John Doe",
+ "_tags": [
+ "family:label"
+ ],
+ "_purpose": {},
+ "salutation": "null",
+ "title": "null",
+ "first_name": "string",
+ "last_name": "string",
+ "customer_number": "string",
+ "birthdate": "2025-01-01",
+ "email": [
+ {
+ "_tags": [
+ "string"
+ ],
+ "email": "user@example.com"
+ }
+ ],
+ "phone": [
+ {
+ "_tags": [
+ "string"
+ ],
+ "phone": "+491234567890"
+ }
+ ],
+ "communication_preference": "postal",
+ "address": [
+ {
+ "_tags": [
+ "billing"
+ ],
+ "street": "Hauptstraße",
+ "street_number": "123",
+ "postal_code": "50668",
+ "city": "Cologne",
+ "country": "DE",
+ "additional_info": "string",
+ "company_name": "string",
+ "first_name": "string",
+ "last_name": "string",
+ "salutation": "string",
+ "title": "string",
+ "coordinates": "50.948484, 6.943147",
+ "plot_of_land": "string",
+ "plot_area": "string",
+ "start_date": "1970-01-01",
+ "end_date": "1970-01-01"
+ }
+ ],
+ "payment": [
+ {
+ "type": "payment_sepa",
+ "data": {
+ "bank_name": "Deutsche Bank",
+ "iban": "DE89370400440532013000",
+ "bic_number": "DEUTDEFF",
+ "fullname": "John Doe"
+ }
+ }
+ ],
+ "account": {},
+ "marketing_permission": true,
+ "contact_owner": {},
+ "consent_email_marketing": {},
+ "consent_sms_marketing": {},
+ "consent_phone_call": {},
+ "consent_print_marketing": {},
+ "portal_users": {},
+ "opportunities": {},
+ "orders": {},
+ "contracts": {},
+ "external_id": "string",
+ "workflows": {},
+ "_files": {},
+ "_created_at": "1970-01-01T00:00:00.000Z",
+ "_updated_at": "1970-01-01T00:00:00.000Z"
+ },
+ "contract": {
+ "_schema": "contract",
+ "_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_org": "123",
+ "_title": "John Doe",
+ "_tags": [
+ "family:label"
+ ],
+ "_purpose": {},
+ "contract_name": "string",
+ "contract_number": "string",
+ "assignee": {},
+ "payment": {},
+ "status": "draft",
+ "description": "string",
+ "billing_account": {},
+ "account_number": "string",
+ "branch": "power",
+ "move_in_date": "2025-01-01",
+ "move_out_date": "2025-01-01",
+ "billing_address": {},
+ "delivery_address": [
+ {
+ "_tags": [
+ "billing"
+ ],
+ "street": "Hauptstraße",
+ "street_number": "123",
+ "postal_code": "50668",
+ "city": "Cologne",
+ "country": "DE",
+ "additional_info": "string",
+ "company_name": "string",
+ "first_name": "string",
+ "last_name": "string",
+ "salutation": "string",
+ "title": "string",
+ "coordinates": "50.948484, 6.943147",
+ "plot_of_land": "string",
+ "plot_area": "string",
+ "start_date": "1970-01-01",
+ "end_date": "1970-01-01"
+ }
+ ],
+ "additional_addresses": {},
+ "termination_date": "2025-01-01",
+ "termination_reason": "string",
+ "start_date": "2025-01-01",
+ "end_date": "2025-01-01",
+ "customer": {},
+ "order": {},
+ "type": "one_time",
+ "billing_period": "weekly",
+ "billing_duration_amount": "string",
+ "billing_duration_unit": "weeks",
+ "notice_time_amount": "string",
+ "notice_time_unit": "weeks",
+ "termination_time_amount": "string",
+ "termination_time_unit": "weeks",
+ "renewal_duration_amount": "string",
+ "renewal_duration_unit": "weeks",
+ "billing_due_day": "string",
+ "installment_amount_currency": "EUR",
+ "installment_amount_decimal": "123.45",
+ "installment_amount": 0,
+ "balance_currency": "EUR",
+ "balance_decimal": "123.45",
+ "balance": 0,
+ "meters": {},
+ "last_sync_at": "2025-01-01",
+ "external_id": "string",
+ "workflows": {},
+ "line_items": {},
+ "total_details": {},
+ "_files": {},
+ "_created_at": "1970-01-01T00:00:00.000Z",
+ "_updated_at": "1970-01-01T00:00:00.000Z"
+ },
+ "billing_account": {
+ "_schema": "billing_account",
+ "_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_org": "123",
+ "_title": "John Doe",
+ "_tags": [
+ "family:label"
+ ],
+ "billing_account_number": "string",
+ "balance_currency": "EUR",
+ "balance_decimal": "123.45",
+ "balance": 0,
+ "billing_contact": {},
+ "billing_address": {},
+ "payment_method": [
+ {
+ "type": "payment_sepa",
+ "data": {
+ "bank_name": "Deutsche Bank",
+ "iban": "DE89370400440532013000",
+ "bic_number": "DEUTDEFF",
+ "fullname": "John Doe"
+ }
+ }
+ ],
+ "contracts": {},
+ "external_id": "string",
+ "workflows": {},
+ "_files": {},
+ "_created_at": "1970-01-01T00:00:00.000Z",
+ "_updated_at": "1970-01-01T00:00:00.000Z"
+ },
+ "ticket_files": [
+ {
+ "_schema": "file",
+ "_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "_org": "123",
+ "_title": "John Doe",
+ "_tags": [
+ "family:label"
+ ],
+ "_purpose": {},
+ "_thumbnail": {},
+ "filename": "string",
+ "mime_type": "string",
+ "type": "document",
+ "readable_size": "string",
+ "language": "de",
+ "alt_text": "string",
+ "access_control": "private",
+ "public_url": "string",
+ "shared_with_end_customer": true,
+ "category": "address-suggestions",
+ "_files": {},
+ "_created_at": "1970-01-01T00:00:00.000Z",
+ "_updated_at": "1970-01-01T00:00:00.000Z"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/static/events/CustomerRequestSubmitted.schema.json b/static/events/CustomerRequestSubmitted.schema.json
new file mode 100644
index 0000000..f7ced69
--- /dev/null
+++ b/static/events/CustomerRequestSubmitted.schema.json
@@ -0,0 +1,2398 @@
+{
+ "type": "object",
+ "properties": {
+ "_org_id": {
+ "type": "string",
+ "description": "epilot tenant/organization ID",
+ "example": "123"
+ },
+ "_event_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "ISO 8601 timestamp when event occurred"
+ },
+ "_event_id": {
+ "type": "string",
+ "description": "Unique event identifier (ULID)"
+ },
+ "_event_name": {
+ "type": "string",
+ "description": "Event name from catalog",
+ "example": "CustomerRequestSubmitted"
+ },
+ "_event_version": {
+ "type": "string",
+ "description": "Schema version number",
+ "example": "1.0"
+ },
+ "_event_source": {
+ "type": "string",
+ "description": "Source that triggered the event"
+ },
+ "_ack_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Acknowledgement ID for tracking event delivery (UUID)"
+ },
+ "_trigger_source_type": {
+ "type": "string",
+ "description": "The type of system that triggered the event. Examples: api, automation, operation, portal_user",
+ "example": "api"
+ },
+ "_trigger_source": {
+ "type": "string",
+ "description": "Identifier of the specific trigger source. Examples: user ID, automation execution ID, activity ID, portal user email",
+ "example": "api_123456"
+ },
+ "_has_pending_changesets": {
+ "type": "boolean",
+ "description": "True when the triggering entity (or meter counter) has at least one pending changeset"
+ },
+ "_changeset_edit_modes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Distinct edit modes across the PENDING changesets — only \"external\" (synced from an external system) or \"approval\" (awaiting approval). A \"direct\" write is applied immediately, is not a pending changeset, and so never appears here."
+ },
+ "_changeset_attributes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Keys identifying pending changesets. For attribute changesets these are attribute names (e.g. `billing_cycle`); for meter-reading changesets these are the changeset IDs from `meter._meter_readings_changeset`"
+ },
+ "_changeset_edit_modes_by_attribute": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "not": {}
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "description": "Per-key edit mode map; keys are a subset of _changeset_attributes (attribute names for entity changesets, changeset IDs for meter-reading changesets) — only those whose pending changeset has an \"external\" or \"approval\" mode. A \"direct\"/unrecognised mode is omitted here, though the key still appears in _changeset_attributes. Enables fine-grained webhook conditions such as `_changeset_edit_modes_by_attribute.billing_cycle equals approval`"
+ },
+ "operation": {
+ "type": "string",
+ "enum": [
+ "createEntity"
+ ],
+ "description": "The entity operation type that triggered this event"
+ },
+ "activity_id": {
+ "type": "string",
+ "description": "Activity ID associated with this operation (ULID)",
+ "example": "01F130Q52Q6MWSNS8N2AVXV4JN"
+ },
+ "activity_type": {
+ "type": "string",
+ "description": "Activity type (e.g., EntityCreated, EntityUpdated)",
+ "example": "EntityUpdated"
+ },
+ "trigger_entity": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Entity ID of the entity that triggered this event"
+ },
+ "event_attachments": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entity_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Entity ID of the file"
+ },
+ "filename": {
+ "type": "string",
+ "description": "Name of the file"
+ },
+ "mime_type": {
+ "type": "string",
+ "description": "MIME type of the file (e.g., application/pdf)"
+ },
+ "size_bytes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "File size in bytes"
+ },
+ "s3ref": {
+ "type": "object",
+ "properties": {
+ "bucket": {
+ "type": "string",
+ "description": "S3 bucket name"
+ },
+ "key": {
+ "type": "string",
+ "description": "S3 object key"
+ }
+ },
+ "required": [
+ "bucket",
+ "key"
+ ],
+ "additionalProperties": false,
+ "description": "S3 reference for the file content"
+ },
+ "version_index": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Latest version index of the file (versions[].length - 1, or 0 if no versions array)"
+ },
+ "readable_size": {
+ "type": "string",
+ "description": "Human-readable file size (e.g., \"200 KB\")"
+ },
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Tags on the file entity (semantic labels set by uploader/automation)"
+ },
+ "relation_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Tags on the ticket→file relation (e.g. journey step label like \"_hidden_ Neuer Schritt - Nachweis\" plus the upload block's configured tags)"
+ },
+ "category": {
+ "type": "string",
+ "description": "File category select value (e.g., \"address-suggestions\", \"unknown\")"
+ },
+ "file_date": {
+ "type": "string",
+ "description": "User-provided file date"
+ },
+ "_created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the file entity was created — useful for time-window filtering"
+ }
+ },
+ "required": [
+ "entity_id",
+ "version_index"
+ ],
+ "additionalProperties": false
+ },
+ "description": "All files related to the ticket. A single submission can carry many documents across several upload blocks. Consumers identify a given upload via `relation_tags` / `_tags` and scope the use case via the `_purpose` taxonomy IDs on the ticket node (IDs only — resolving them to names is up to the consumer)."
+ },
+ "ticket": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "required": [
+ "_schema"
+ ],
+ "properties": {
+ "_schema": {
+ "readOnly": true,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_-]+$",
+ "example": "ticket",
+ "description": "URL-friendly identifier for the entity schema"
+ },
+ "_id": {
+ "readOnly": true,
+ "type": "string",
+ "format": "uuid",
+ "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "description": "Unique identifier for the entity"
+ },
+ "_org": {
+ "type": "string",
+ "description": "Organization Id the entity belongs to",
+ "readOnly": true,
+ "example": "123"
+ },
+ "_title": {
+ "readOnly": true,
+ "type": "string",
+ "nullable": true,
+ "example": "John Doe",
+ "description": "Generated title for the entity based on schema title_template"
+ },
+ "_tags": {
+ "type": "array",
+ "nullable": true,
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "family:label"
+ ],
+ "description": "Entity Labels"
+ },
+ "_purpose": {
+ "$ref": "#/definitions/PurposeAttribute",
+ "description": "Purposes"
+ },
+ "ticket_title": {
+ "type": "string",
+ "description": "Ticket Title"
+ },
+ "customer": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Customer"
+ },
+ "ticket_number": {
+ "type": "string",
+ "description": "Ticket Number"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "Open",
+ "In Progress",
+ "Escalated",
+ "Closed",
+ "Canceled"
+ ],
+ "description": "Status"
+ },
+ "payment": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Payment method details",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "payment_sepa",
+ "payment_invoice",
+ "payment_cash"
+ ],
+ "example": "payment_sepa"
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "bank_name": {
+ "type": "string",
+ "example": "Deutsche Bank"
+ },
+ "iban": {
+ "type": "string",
+ "example": "DE89370400440532013000"
+ },
+ "bic_number": {
+ "type": "string",
+ "example": "DEUTDEFF"
+ },
+ "fullname": {
+ "type": "string",
+ "example": "John Doe"
+ }
+ }
+ }
+ }
+ },
+ "description": "Payment"
+ },
+ "source": {
+ "$ref": "#/definitions/LinkAttribute",
+ "description": "Source"
+ },
+ "workflows": {
+ "$ref": "#/definitions/WorkflowOverview"
+ },
+ "_files": {
+ "$ref": "#/definitions/BaseRelation"
+ },
+ "_created_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity creation"
+ },
+ "_updated_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity last update"
+ }
+ },
+ "description": "ticket entity (hydrated from entity graph)"
+ },
+ "submission": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "required": [
+ "_schema"
+ ],
+ "properties": {
+ "_id": {
+ "readOnly": true,
+ "type": "string",
+ "format": "uuid",
+ "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "description": "Unique identifier for the entity"
+ },
+ "_schema": {
+ "readOnly": true,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_-]+$",
+ "example": "submission",
+ "description": "URL-friendly identifier for the entity schema"
+ },
+ "_org": {
+ "type": "string",
+ "description": "Organization Id the entity belongs to",
+ "readOnly": true,
+ "example": "123"
+ }
+ },
+ "description": "submission entity (hydrated from entity graph)"
+ },
+ "contact": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "required": [
+ "_schema"
+ ],
+ "properties": {
+ "_schema": {
+ "readOnly": true,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_-]+$",
+ "example": "contact",
+ "description": "URL-friendly identifier for the entity schema"
+ },
+ "_id": {
+ "readOnly": true,
+ "type": "string",
+ "format": "uuid",
+ "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "description": "Unique identifier for the entity"
+ },
+ "_org": {
+ "type": "string",
+ "description": "Organization Id the entity belongs to",
+ "readOnly": true,
+ "example": "123"
+ },
+ "_title": {
+ "readOnly": true,
+ "type": "string",
+ "nullable": true,
+ "example": "John Doe",
+ "description": "Generated title for the entity based on schema title_template"
+ },
+ "_tags": {
+ "type": "array",
+ "nullable": true,
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "family:label"
+ ],
+ "description": "Entity Labels"
+ },
+ "_purpose": {
+ "$ref": "#/definitions/PurposeAttribute",
+ "description": "Purposes"
+ },
+ "salutation": {
+ "type": "string",
+ "enum": [
+ "null",
+ "Mr.",
+ "Ms. / Mrs.",
+ "Company",
+ "Contact Person",
+ "Company/Contact Person",
+ "Spouse",
+ "Family",
+ "Ownership",
+ "Assembly",
+ "Other"
+ ],
+ "description": "Salutation"
+ },
+ "title": {
+ "type": "string",
+ "enum": [
+ "null",
+ "Dr.",
+ "Prof.",
+ "Prof. Dr."
+ ],
+ "description": "Title"
+ },
+ "first_name": {
+ "type": "string",
+ "description": "First Name"
+ },
+ "last_name": {
+ "type": "string",
+ "description": "Last Name"
+ },
+ "customer_number": {
+ "type": "string",
+ "description": "Customer Number"
+ },
+ "birthdate": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "Date of Birth"
+ },
+ "email": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "email": {
+ "type": "string",
+ "format": "email"
+ }
+ },
+ "required": [
+ "email"
+ ]
+ },
+ "description": "Email"
+ },
+ "phone": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "phone": {
+ "type": "string",
+ "example": "+491234567890"
+ }
+ },
+ "required": [
+ "phone"
+ ]
+ },
+ "description": "Phone"
+ },
+ "communication_preference": {
+ "type": "string",
+ "enum": [
+ "postal",
+ "portal"
+ ],
+ "description": "Standard communication method"
+ },
+ "address": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Address attribute",
+ "additionalProperties": true,
+ "properties": {
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "billing"
+ ]
+ },
+ "street": {
+ "type": "string",
+ "description": "The first line of the address. Typically the street address or PO Box number.",
+ "nullable": true,
+ "example": "Hauptstraße"
+ },
+ "street_number": {
+ "type": "string",
+ "description": "The second line of the address. Typically the number of the apartment, suite, or unit.",
+ "nullable": true,
+ "example": "123"
+ },
+ "postal_code": {
+ "type": "string",
+ "description": "The postal code for the address.",
+ "nullable": true,
+ "example": "50668"
+ },
+ "city": {
+ "type": "string",
+ "description": "The name of the city, district, village, or town.",
+ "nullable": true,
+ "example": "Cologne"
+ },
+ "country": {
+ "type": "string",
+ "description": "The two-letter code for the country of the address.",
+ "nullable": true,
+ "example": "DE"
+ },
+ "additional_info": {
+ "type": "string",
+ "description": "An additional description for the address",
+ "nullable": true
+ },
+ "company_name": {
+ "type": "string",
+ "description": "the company name, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "first_name": {
+ "type": "string",
+ "description": "the first name of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "last_name": {
+ "type": "string",
+ "description": "the last name of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "salutation": {
+ "type": "string",
+ "description": "the salutation of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "title": {
+ "type": "string",
+ "description": "the title of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "coordinates": {
+ "type": "string",
+ "description": "Geographical coordinates (latitude, longitude)",
+ "nullable": true,
+ "example": "50.948484, 6.943147"
+ },
+ "plot_of_land": {
+ "type": "string",
+ "description": "Plot of land information",
+ "nullable": true
+ },
+ "plot_area": {
+ "type": "string",
+ "description": "Area of the plot",
+ "nullable": true
+ },
+ "start_date": {
+ "type": "string",
+ "description": "Start date for the address",
+ "format": "date",
+ "nullable": true
+ },
+ "end_date": {
+ "type": "string",
+ "description": "End date for the address",
+ "format": "date",
+ "nullable": true
+ }
+ }
+ },
+ "description": "Address"
+ },
+ "payment": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Payment method details",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "payment_sepa",
+ "payment_invoice",
+ "payment_cash"
+ ],
+ "example": "payment_sepa"
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "bank_name": {
+ "type": "string",
+ "example": "Deutsche Bank"
+ },
+ "iban": {
+ "type": "string",
+ "example": "DE89370400440532013000"
+ },
+ "bic_number": {
+ "type": "string",
+ "example": "DEUTDEFF"
+ },
+ "fullname": {
+ "type": "string",
+ "example": "John Doe"
+ }
+ }
+ }
+ }
+ },
+ "description": "Payment"
+ },
+ "account": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Account"
+ },
+ "marketing_permission": {
+ "type": "boolean",
+ "description": "Marketing Permission"
+ },
+ "contact_owner": {
+ "$ref": "#/definitions/User",
+ "description": "Contact Owner"
+ },
+ "consent_email_marketing": {
+ "$ref": "#/definitions/ConsentAttribute",
+ "description": "Email Marketing"
+ },
+ "consent_sms_marketing": {
+ "$ref": "#/definitions/ConsentAttribute",
+ "description": "SMS Marketing"
+ },
+ "consent_phone_call": {
+ "$ref": "#/definitions/ConsentAttribute",
+ "description": "Direct Phone Marketing"
+ },
+ "consent_print_marketing": {
+ "$ref": "#/definitions/ConsentAttribute",
+ "description": "Print Marketing"
+ },
+ "portal_users": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Portal Users"
+ },
+ "opportunities": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Opportunities"
+ },
+ "orders": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Orders"
+ },
+ "contracts": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Contracts"
+ },
+ "external_id": {
+ "type": "string",
+ "description": "External ID"
+ },
+ "workflows": {
+ "$ref": "#/definitions/WorkflowOverview"
+ },
+ "_files": {
+ "$ref": "#/definitions/BaseRelation"
+ },
+ "_created_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity creation"
+ },
+ "_updated_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity last update"
+ }
+ },
+ "description": "contact entity (hydrated from entity graph)"
+ },
+ "contract": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "required": [
+ "_schema",
+ "type",
+ "billing_period",
+ "installment_amount",
+ "balance"
+ ],
+ "properties": {
+ "_schema": {
+ "readOnly": true,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_-]+$",
+ "example": "contract",
+ "description": "URL-friendly identifier for the entity schema"
+ },
+ "_id": {
+ "readOnly": true,
+ "type": "string",
+ "format": "uuid",
+ "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "description": "Unique identifier for the entity"
+ },
+ "_org": {
+ "type": "string",
+ "description": "Organization Id the entity belongs to",
+ "readOnly": true,
+ "example": "123"
+ },
+ "_title": {
+ "readOnly": true,
+ "type": "string",
+ "nullable": true,
+ "example": "John Doe",
+ "description": "Generated title for the entity based on schema title_template"
+ },
+ "_tags": {
+ "type": "array",
+ "nullable": true,
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "family:label"
+ ],
+ "description": "Entity Labels"
+ },
+ "_purpose": {
+ "$ref": "#/definitions/PurposeAttribute",
+ "description": "Purposes"
+ },
+ "contract_name": {
+ "type": "string",
+ "description": "Contract Name"
+ },
+ "contract_number": {
+ "type": "string",
+ "description": "Contract Number"
+ },
+ "assignee": {
+ "$ref": "#/definitions/User",
+ "description": "Assignee"
+ },
+ "payment": {
+ "$ref": "#/definitions/BaseRelationRef",
+ "description": "Payment Details"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "draft",
+ "in_approval_process",
+ "approved",
+ "active",
+ "deactivated",
+ "revoked",
+ "terminated",
+ "expired"
+ ],
+ "description": "Status"
+ },
+ "description": {
+ "type": "string",
+ "description": "Description"
+ },
+ "billing_account": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Billing Account"
+ },
+ "account_number": {
+ "type": "string",
+ "description": "Account Number"
+ },
+ "branch": {
+ "type": "string",
+ "enum": [
+ "power",
+ "gas",
+ "water",
+ "waste_water",
+ "district_heating"
+ ],
+ "description": "Branch"
+ },
+ "move_in_date": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "Move In Date"
+ },
+ "move_out_date": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "Move Out Date"
+ },
+ "billing_address": {
+ "$ref": "#/definitions/BaseRelationRef",
+ "description": "Billing Address"
+ },
+ "delivery_address": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Address attribute",
+ "additionalProperties": true,
+ "properties": {
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "billing"
+ ]
+ },
+ "street": {
+ "type": "string",
+ "description": "The first line of the address. Typically the street address or PO Box number.",
+ "nullable": true,
+ "example": "Hauptstraße"
+ },
+ "street_number": {
+ "type": "string",
+ "description": "The second line of the address. Typically the number of the apartment, suite, or unit.",
+ "nullable": true,
+ "example": "123"
+ },
+ "postal_code": {
+ "type": "string",
+ "description": "The postal code for the address.",
+ "nullable": true,
+ "example": "50668"
+ },
+ "city": {
+ "type": "string",
+ "description": "The name of the city, district, village, or town.",
+ "nullable": true,
+ "example": "Cologne"
+ },
+ "country": {
+ "type": "string",
+ "description": "The two-letter code for the country of the address.",
+ "nullable": true,
+ "example": "DE"
+ },
+ "additional_info": {
+ "type": "string",
+ "description": "An additional description for the address",
+ "nullable": true
+ },
+ "company_name": {
+ "type": "string",
+ "description": "the company name, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "first_name": {
+ "type": "string",
+ "description": "the first name of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "last_name": {
+ "type": "string",
+ "description": "the last name of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "salutation": {
+ "type": "string",
+ "description": "the salutation of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "title": {
+ "type": "string",
+ "description": "the title of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "coordinates": {
+ "type": "string",
+ "description": "Geographical coordinates (latitude, longitude)",
+ "nullable": true,
+ "example": "50.948484, 6.943147"
+ },
+ "plot_of_land": {
+ "type": "string",
+ "description": "Plot of land information",
+ "nullable": true
+ },
+ "plot_area": {
+ "type": "string",
+ "description": "Area of the plot",
+ "nullable": true
+ },
+ "start_date": {
+ "type": "string",
+ "description": "Start date for the address",
+ "format": "date",
+ "nullable": true
+ },
+ "end_date": {
+ "type": "string",
+ "description": "End date for the address",
+ "format": "date",
+ "nullable": true
+ }
+ }
+ },
+ "description": "Delivery Address"
+ },
+ "additional_addresses": {
+ "$ref": "#/definitions/BaseRelationRef",
+ "description": "Additional Addresses"
+ },
+ "termination_date": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "Date of Termination"
+ },
+ "termination_reason": {
+ "type": "string",
+ "description": "Reason For Termination"
+ },
+ "start_date": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "Start Date"
+ },
+ "end_date": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "End Date"
+ },
+ "customer": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Customer"
+ },
+ "order": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Order"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "one_time",
+ "recurring"
+ ],
+ "description": "Type"
+ },
+ "billing_period": {
+ "type": "string",
+ "enum": [
+ "weekly",
+ "monthly",
+ "every_quarter",
+ "every_6_months",
+ "yearly"
+ ],
+ "description": "Billing Period"
+ },
+ "billing_duration_amount": {
+ "type": "string",
+ "description": "Billing Duration"
+ },
+ "billing_duration_unit": {
+ "type": "string",
+ "enum": [
+ "weeks",
+ "months",
+ "years"
+ ],
+ "description": "Billing Duration Unit"
+ },
+ "notice_time_amount": {
+ "type": "string",
+ "description": "Notice Time"
+ },
+ "notice_time_unit": {
+ "type": "string",
+ "enum": [
+ "weeks",
+ "months",
+ "years"
+ ],
+ "description": "Notice Time Unit"
+ },
+ "termination_time_amount": {
+ "type": "string",
+ "description": "Termination Time"
+ },
+ "termination_time_unit": {
+ "type": "string",
+ "enum": [
+ "weeks",
+ "months",
+ "years"
+ ],
+ "description": "Termination Time Unit"
+ },
+ "renewal_duration_amount": {
+ "type": "string",
+ "description": "Renewal Duration"
+ },
+ "renewal_duration_unit": {
+ "type": "string",
+ "enum": [
+ "weeks",
+ "months",
+ "years"
+ ],
+ "description": "Renewal Duration Unit"
+ },
+ "billing_due_day": {
+ "type": "string",
+ "description": "Billing Due Day"
+ },
+ "installment_amount_currency": {
+ "type": "string",
+ "description": "Three-letter ISO currency code, in lowercase. Must be a supported currency.",
+ "example": "EUR"
+ },
+ "installment_amount_decimal": {
+ "type": "string",
+ "description": "The currency value as a decimal string",
+ "example": "123.45"
+ },
+ "installment_amount": {
+ "type": "number",
+ "description": "Installment Currency"
+ },
+ "balance_currency": {
+ "type": "string",
+ "description": "Three-letter ISO currency code, in lowercase. Must be a supported currency.",
+ "example": "EUR"
+ },
+ "balance_decimal": {
+ "type": "string",
+ "description": "The currency value as a decimal string",
+ "example": "123.45"
+ },
+ "balance": {
+ "type": "number",
+ "description": "Currency"
+ },
+ "meters": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Meters"
+ },
+ "last_sync_at": {
+ "type": "string",
+ "format": "date",
+ "example": "2025-01-01",
+ "description": "Last Sync At"
+ },
+ "external_id": {
+ "type": "string",
+ "description": "External ID"
+ },
+ "workflows": {
+ "$ref": "#/definitions/WorkflowOverview"
+ },
+ "line_items": {
+ "$ref": "#/definitions/LineItems"
+ },
+ "total_details": {
+ "$ref": "#/definitions/TotalDetails"
+ },
+ "_files": {
+ "$ref": "#/definitions/BaseRelation"
+ },
+ "_created_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity creation"
+ },
+ "_updated_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity last update"
+ }
+ },
+ "description": "contract entity (hydrated from entity graph)"
+ },
+ "billing_account": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "required": [
+ "_schema"
+ ],
+ "properties": {
+ "_schema": {
+ "readOnly": true,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_-]+$",
+ "example": "billing_account",
+ "description": "URL-friendly identifier for the entity schema"
+ },
+ "_id": {
+ "readOnly": true,
+ "type": "string",
+ "format": "uuid",
+ "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "description": "Unique identifier for the entity"
+ },
+ "_org": {
+ "type": "string",
+ "description": "Organization Id the entity belongs to",
+ "readOnly": true,
+ "example": "123"
+ },
+ "_title": {
+ "readOnly": true,
+ "type": "string",
+ "nullable": true,
+ "example": "John Doe",
+ "description": "Generated title for the entity based on schema title_template"
+ },
+ "_tags": {
+ "type": "array",
+ "nullable": true,
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "family:label"
+ ],
+ "description": "Entity Labels"
+ },
+ "billing_account_number": {
+ "type": "string",
+ "description": "Billing Account Number"
+ },
+ "balance_currency": {
+ "type": "string",
+ "description": "Three-letter ISO currency code, in lowercase. Must be a supported currency.",
+ "example": "EUR"
+ },
+ "balance_decimal": {
+ "type": "string",
+ "description": "The currency value as a decimal string",
+ "example": "123.45"
+ },
+ "balance": {
+ "type": "number",
+ "description": "Account Balance"
+ },
+ "billing_contact": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Billing Contact"
+ },
+ "billing_address": {
+ "$ref": "#/definitions/AddressAttribute",
+ "description": "Billing Address"
+ },
+ "payment_method": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Payment method details",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "payment_sepa",
+ "payment_invoice",
+ "payment_cash"
+ ],
+ "example": "payment_sepa"
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "bank_name": {
+ "type": "string",
+ "example": "Deutsche Bank"
+ },
+ "iban": {
+ "type": "string",
+ "example": "DE89370400440532013000"
+ },
+ "bic_number": {
+ "type": "string",
+ "example": "DEUTDEFF"
+ },
+ "fullname": {
+ "type": "string",
+ "example": "John Doe"
+ }
+ }
+ }
+ }
+ },
+ "description": "Payment Method"
+ },
+ "contracts": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Contracts"
+ },
+ "external_id": {
+ "type": "string",
+ "description": "External ID"
+ },
+ "workflows": {
+ "$ref": "#/definitions/WorkflowOverview"
+ },
+ "_files": {
+ "$ref": "#/definitions/BaseRelation"
+ },
+ "_created_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity creation"
+ },
+ "_updated_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity last update"
+ }
+ },
+ "description": "billing_account entity (hydrated from entity graph)"
+ },
+ "ticket_files": {
+ "type": "array",
+ "description": "Array of file entities (hydrated from entity graph)",
+ "items": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "required": [
+ "_schema",
+ "filename",
+ "language"
+ ],
+ "properties": {
+ "_schema": {
+ "readOnly": true,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_-]+$",
+ "example": "file",
+ "description": "URL-friendly identifier for the entity schema"
+ },
+ "_id": {
+ "readOnly": true,
+ "type": "string",
+ "format": "uuid",
+ "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "description": "Unique identifier for the entity"
+ },
+ "_org": {
+ "type": "string",
+ "description": "Organization Id the entity belongs to",
+ "readOnly": true,
+ "example": "123"
+ },
+ "_title": {
+ "readOnly": true,
+ "type": "string",
+ "nullable": true,
+ "example": "John Doe",
+ "description": "Generated title for the entity based on schema title_template"
+ },
+ "_tags": {
+ "type": "array",
+ "nullable": true,
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "family:label"
+ ],
+ "description": "Entity Labels"
+ },
+ "_purpose": {
+ "$ref": "#/definitions/PurposeAttribute",
+ "description": "Purposes"
+ },
+ "_thumbnail": {
+ "$ref": "#/definitions/BaseRelation",
+ "description": "Thumbnail"
+ },
+ "filename": {
+ "type": "string",
+ "description": "File Name"
+ },
+ "mime_type": {
+ "type": "string",
+ "description": "MIME Type"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "document",
+ "document_template",
+ "text",
+ "image",
+ "video",
+ "audio",
+ "spreadsheet",
+ "presentation",
+ "font",
+ "archive",
+ "application",
+ "unknown"
+ ],
+ "description": "File Type"
+ },
+ "readable_size": {
+ "type": "string",
+ "description": "Size"
+ },
+ "language": {
+ "type": "string",
+ "enum": [
+ "de",
+ "en"
+ ],
+ "description": "Language"
+ },
+ "alt_text": {
+ "type": "string",
+ "description": "Alt text"
+ },
+ "access_control": {
+ "type": "string",
+ "enum": [
+ "private",
+ "public-read"
+ ],
+ "description": "Access Control"
+ },
+ "public_url": {
+ "type": "string",
+ "description": "Public URL"
+ },
+ "shared_with_end_customer": {
+ "type": "boolean",
+ "description": "Shared with End Customer"
+ },
+ "category": {
+ "type": "string",
+ "enum": [
+ "address-suggestions",
+ "unknown"
+ ],
+ "description": "Category"
+ },
+ "_files": {
+ "$ref": "#/definitions/BaseRelation"
+ },
+ "_created_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity creation"
+ },
+ "_updated_at": {
+ "readOnly": true,
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "description": "Timestamp of entity last update"
+ }
+ }
+ }
+ }
+ },
+ "required": [
+ "_org_id",
+ "_event_time",
+ "_event_id",
+ "_event_name",
+ "_event_version",
+ "_event_source",
+ "_ack_id",
+ "operation",
+ "trigger_entity"
+ ],
+ "additionalProperties": true,
+ "definitions": {
+ "PurposeAttribute": {
+ "type": "array",
+ "description": "List of purpose ids",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "7675dc56-fd1b-46ee-9c35-defe0667b32e"
+ ]
+ },
+ "LinkAttribute": {
+ "type": "object",
+ "description": "Link with title and href",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "link"
+ ]
+ },
+ "title": {
+ "type": "string",
+ "example": "Visit Website"
+ },
+ "href": {
+ "type": "string",
+ "format": "uri",
+ "example": "https://example.com"
+ }
+ }
+ },
+ "BaseUUID": {
+ "type": "string",
+ "format": "uuid",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "BaseTags": {
+ "type": "array",
+ "nullable": true,
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "example"
+ ]
+ },
+ "BaseRelation": {
+ "type": "object",
+ "nullable": true,
+ "description": "Relation to another entity",
+ "properties": {
+ "$relation": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entity_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "_tags": {
+ "$ref": "#/definitions/BaseTags"
+ }
+ }
+ }
+ }
+ }
+ },
+ "WorkflowStatus": {
+ "type": "string",
+ "enum": [
+ "STARTED",
+ "DONE",
+ "CLOSED"
+ ]
+ },
+ "StepType": {
+ "type": "string",
+ "enum": [
+ "MANUAL",
+ "AUTOMATION"
+ ]
+ },
+ "StepStatus": {
+ "type": "string",
+ "enum": [
+ "UNASSIGNED",
+ "ASSIGNED",
+ "COMPLETED",
+ "SKIPPED",
+ "IN_PROGRESS"
+ ]
+ },
+ "PhaseInEntity": {
+ "type": "object",
+ "description": "Workflow phase information",
+ "properties": {
+ "phase_id": {
+ "type": "string"
+ },
+ "phase_name": {
+ "type": "string"
+ },
+ "phase_progress": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "phase_id",
+ "phase_name",
+ "phase_progress"
+ ]
+ },
+ "WorkflowInEntity": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "definition_id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "status": {
+ "$ref": "#/definitions/WorkflowStatus"
+ },
+ "assignees": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "progress": {
+ "type": "number"
+ },
+ "phases_in_progress": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PhaseInEntity"
+ }
+ },
+ "last_update_time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "upcoming_tasks_assignees": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "task_id": {
+ "type": "string"
+ },
+ "task_name": {
+ "type": "string"
+ },
+ "task_assignees": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "task_duedate": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "task_execution_type": {
+ "$ref": "#/definitions/StepType"
+ },
+ "task_status": {
+ "$ref": "#/definitions/StepStatus"
+ },
+ "phase_id": {
+ "type": "string"
+ },
+ "phase_name": {
+ "type": "string"
+ },
+ "phase_assignees": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "phase_progress": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "id",
+ "definition_id",
+ "name",
+ "status",
+ "assignees",
+ "last_update_time"
+ ]
+ },
+ "WorkflowOverview": {
+ "type": "object",
+ "properties": {
+ "primary": {
+ "$ref": "#/definitions/WorkflowInEntity"
+ }
+ },
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/WorkflowInEntity"
+ }
+ }
+ },
+ "ConsentAttribute": {
+ "type": "object",
+ "description": "Consent Management",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "consent"
+ ]
+ },
+ "topic": {
+ "type": "string"
+ },
+ "identifiers": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "topic"
+ ]
+ },
+ "UserId": {
+ "description": "User's unique identifier",
+ "type": "string",
+ "readOnly": true
+ },
+ "OrganizationId": {
+ "description": "Organization unique identifier",
+ "type": "string",
+ "readOnly": true,
+ "example": "123"
+ },
+ "User": {
+ "type": "object",
+ "description": "User information",
+ "properties": {
+ "id": {
+ "$ref": "#/definitions/UserId"
+ },
+ "organization_id": {
+ "$ref": "#/definitions/OrganizationId"
+ },
+ "email": {
+ "type": "string",
+ "format": "email",
+ "example": "user@example.com"
+ },
+ "display_name": {
+ "type": "string",
+ "example": "John Doe",
+ "deprecated": true
+ },
+ "name": {
+ "type": "string",
+ "example": "John Doe",
+ "deprecated": true
+ },
+ "preferred_language": {
+ "type": "string",
+ "example": "de",
+ "description": "ISO 639-1 language code"
+ },
+ "signature": {
+ "type": "string",
+ "example": "Best regards,
John Doe
",
+ "description": "HTML email signature"
+ },
+ "roles": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "example": "Owner"
+ },
+ "deprecated": true,
+ "description": "Deprecated! Please use Permissions API instead"
+ },
+ "image_uri": {
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "original": {
+ "type": "string",
+ "format": "uri",
+ "example": "https://account-profile-images.epilot.cloud/1/avatar.png"
+ },
+ "thumbnail_32": {
+ "type": "string",
+ "format": "uri",
+ "example": "https://account-profile-images.epilot.cloud/1/avatar_32x32.png"
+ }
+ },
+ "nullable": true
+ },
+ "properties": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "profileImageName"
+ },
+ "value": {
+ "type": "string",
+ "example": "avatar.png"
+ }
+ },
+ "required": [
+ "name",
+ "value"
+ ]
+ }
+ }
+ },
+ "required": [
+ "id",
+ "organization_id",
+ "email",
+ "name",
+ "preferred_language",
+ "roles",
+ "properties"
+ ]
+ },
+ "BaseRelationRef": {
+ "type": "object",
+ "nullable": true,
+ "description": "Reference to a specific property of another entity",
+ "properties": {
+ "$relation_ref": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entity_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "path": {
+ "type": "string",
+ "example": "address",
+ "description": "The property of the entity (pointed by entity_id) to be used as the reference"
+ },
+ "_tags": {
+ "$ref": "#/definitions/BaseTags"
+ },
+ "_id": {
+ "type": "string",
+ "example": "xHcOoJCa07eysJ1GaQeSb"
+ }
+ }
+ }
+ }
+ }
+ },
+ "TaxBreakdownInfo": {
+ "type": "object",
+ "properties": {
+ "rate": {
+ "type": "number"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "VAT",
+ "GST",
+ "Custom"
+ ]
+ },
+ "_id": {
+ "type": "string"
+ }
+ }
+ },
+ "TaxAmountBreakdown": {
+ "type": "object",
+ "description": "A tax amount associated with a specific tax rate.",
+ "readOnly": true,
+ "properties": {
+ "amount": {
+ "type": "integer"
+ },
+ "rate": {
+ "type": "string",
+ "description": "The tax rate applied. With the release of the tax manager feature this field is being deprecated in favor of the tax field.",
+ "deprecated": true
+ },
+ "rateValue": {
+ "type": "number",
+ "description": "The tax rate value applied. With the release of the tax manager feature this field is being deprecated in favor of the tax field.",
+ "deprecated": true
+ },
+ "tax": {
+ "$ref": "#/definitions/TaxBreakdownInfo"
+ }
+ }
+ },
+ "Amounts": {
+ "type": "object",
+ "properties": {
+ "amount_subtotal": {
+ "type": "integer"
+ },
+ "amount_subtotal_decimal": {
+ "type": "string"
+ },
+ "amount_total": {
+ "type": "integer"
+ },
+ "amount_total_decimal": {
+ "type": "string"
+ }
+ }
+ },
+ "Currency": {
+ "type": "string",
+ "description": "Three-letter ISO currency code, in lowercase. Must be a supported currency.",
+ "example": "EUR"
+ },
+ "RecurrenceAmount": {
+ "type": "object",
+ "description": "An amount associated with a specific recurrence.",
+ "readOnly": true,
+ "allOf": [
+ {
+ "$ref": "#/definitions/Amounts"
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "billing_period": {
+ "type": "string",
+ "enum": [
+ "weekly",
+ "monthly",
+ "every_quarter",
+ "every_6_months",
+ "yearly"
+ ]
+ },
+ "unit_amount_gross": {
+ "type": "integer"
+ },
+ "unit_amount_net": {
+ "type": "integer"
+ },
+ "amount_tax": {
+ "type": "integer"
+ },
+ "currency": {
+ "$ref": "#/definitions/Currency"
+ }
+ },
+ "required": [
+ "amount_subtotal",
+ "amount_total",
+ "amount_subtotal_decimal",
+ "amount_total_decimal"
+ ]
+ },
+ "RecurrenceAmountWithTax": {
+ "type": "object",
+ "description": "An amount associated with a specific recurrence.",
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "billing_period": {
+ "type": "string",
+ "enum": [
+ "weekly",
+ "monthly",
+ "every_quarter",
+ "every_6_months",
+ "yearly"
+ ]
+ },
+ "amount_total": {
+ "type": "integer"
+ },
+ "amount_subtotal": {
+ "type": "integer"
+ },
+ "amount_tax": {
+ "type": "integer"
+ },
+ "tax": {
+ "$ref": "#/definitions/TaxAmountBreakdown"
+ }
+ },
+ "required": [
+ "amount_subtotal",
+ "amount_total"
+ ]
+ },
+ "TotalDetails": {
+ "type": "object",
+ "description": "The total details with tax (and discount) aggregated totals.",
+ "readOnly": true,
+ "properties": {
+ "amount_shipping": {
+ "type": "integer",
+ "description": "This is the sum of all the price item shipping amounts."
+ },
+ "amount_tax": {
+ "type": "integer",
+ "description": "This is the sum of all the price item tax amounts."
+ },
+ "breakdown": {
+ "type": "object",
+ "description": "Breakdown of individual tax (and discount) amounts that add up to the totals.",
+ "properties": {
+ "taxes": {
+ "type": "array",
+ "description": "The aggregated price items tax amount per rate.",
+ "items": {
+ "$ref": "#/definitions/TaxAmountBreakdown"
+ }
+ },
+ "recurrences": {
+ "type": "array",
+ "description": "The aggregated price items tax amount per rate.",
+ "items": {
+ "$ref": "#/definitions/RecurrenceAmount"
+ }
+ },
+ "recurrencesByTax": {
+ "type": "array",
+ "description": "The aggregated price items recurrences by tax rate",
+ "items": {
+ "$ref": "#/definitions/RecurrenceAmountWithTax"
+ }
+ }
+ }
+ }
+ }
+ },
+ "LineItems": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "price_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "product_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "quantity": {
+ "type": "integer"
+ },
+ "description": {
+ "type": "string"
+ },
+ "unit_amount": {
+ "type": "integer"
+ },
+ "unit_amount_decimal": {
+ "type": "string"
+ },
+ "pricing_model": {
+ "type": "string",
+ "enum": [
+ "per_unit"
+ ]
+ },
+ "_price": {
+ "type": "object",
+ "properties": {
+ "_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "_title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "unit_amount": {
+ "type": "integer"
+ },
+ "unit_amount_decimal": {
+ "type": "string"
+ },
+ "unit_amount_currency": {
+ "type": "string"
+ },
+ "active": {
+ "type": "boolean"
+ },
+ "sales_tax": {
+ "type": "string"
+ },
+ "tax_behavior": {
+ "type": "string"
+ },
+ "price_display_in_journeys": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "billing_period": {
+ "type": "string"
+ },
+ "billing_duration_unit": {
+ "type": "string"
+ },
+ "notice_time_unit": {
+ "type": "string"
+ },
+ "termination_time_unit": {
+ "type": "string"
+ },
+ "renewal_duration_unit": {
+ "type": "string"
+ },
+ "internal_description": {
+ "type": "string"
+ },
+ "pricing_model": {
+ "type": "string"
+ },
+ "is_tax_inclusive": {
+ "type": "boolean"
+ },
+ "headline": {
+ "type": "string"
+ },
+ "subHeadline": {
+ "type": "string"
+ },
+ "group": {
+ "type": "string"
+ }
+ }
+ },
+ "_product": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "product"
+ ]
+ },
+ "_title": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "price_options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "_title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "unit_amount": {
+ "type": "integer"
+ },
+ "unit_amount_decimal": {
+ "type": "string"
+ },
+ "unit_amount_currency": {
+ "type": "string"
+ },
+ "active": {
+ "type": "boolean"
+ },
+ "_schema": {
+ "type": "string"
+ },
+ "_org": {
+ "type": "string"
+ },
+ "_created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "_updated_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "sales_tax": {
+ "type": "string"
+ },
+ "tax_behavior": {
+ "type": "string"
+ },
+ "price_display_in_journeys": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "billing_period": {
+ "type": "string"
+ },
+ "billing_duration_unit": {
+ "type": "string"
+ },
+ "notice_time_unit": {
+ "type": "string"
+ },
+ "termination_time_unit": {
+ "type": "string"
+ },
+ "renewal_duration_unit": {
+ "type": "string"
+ },
+ "internal_description": {
+ "type": "string"
+ },
+ "_owners": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "org_id": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "pricing_model": {
+ "type": "string"
+ },
+ "is_tax_inclusive": {
+ "type": "boolean"
+ },
+ "_acl": {
+ "type": "object",
+ "properties": {
+ "view": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "edit": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "delete": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "$relation": {
+ "type": "object",
+ "properties": {
+ "entity_id": {
+ "$ref": "#/definitions/BaseUUID"
+ },
+ "_schema": {
+ "type": "string"
+ },
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "_id": {
+ "$ref": "#/definitions/BaseUUID"
+ }
+ }
+ },
+ "taxes": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "rate": {
+ "type": "string"
+ },
+ "rateValue": {
+ "type": "integer"
+ },
+ "amount": {
+ "type": "integer"
+ }
+ }
+ }
+ },
+ "currency": {
+ "type": "string"
+ },
+ "unit_amount_net": {
+ "type": "integer"
+ },
+ "unit_amount_net_decimal": {
+ "type": "string"
+ },
+ "unit_amount_gross": {
+ "type": "integer"
+ },
+ "unit_amount_gross_decimal": {
+ "type": "string"
+ },
+ "amount_subtotal": {
+ "type": "integer"
+ },
+ "amount_total": {
+ "type": "integer"
+ },
+ "amount_tax": {
+ "type": "integer"
+ },
+ "is_tax_inclusive": {
+ "type": "boolean"
+ },
+ "amount_subtotal_decimal": {
+ "type": "string"
+ },
+ "amount_total_decimal": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "AddressAttribute": {
+ "type": "object",
+ "description": "Address attribute",
+ "additionalProperties": true,
+ "properties": {
+ "_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "billing"
+ ]
+ },
+ "street": {
+ "type": "string",
+ "description": "The first line of the address. Typically the street address or PO Box number.",
+ "nullable": true,
+ "example": "Hauptstraße"
+ },
+ "street_number": {
+ "type": "string",
+ "description": "The second line of the address. Typically the number of the apartment, suite, or unit.",
+ "nullable": true,
+ "example": "123"
+ },
+ "postal_code": {
+ "type": "string",
+ "description": "The postal code for the address.",
+ "nullable": true,
+ "example": "50668"
+ },
+ "city": {
+ "type": "string",
+ "description": "The name of the city, district, village, or town.",
+ "nullable": true,
+ "example": "Cologne"
+ },
+ "country": {
+ "type": "string",
+ "description": "The two-letter code for the country of the address.",
+ "nullable": true,
+ "example": "DE"
+ },
+ "additional_info": {
+ "type": "string",
+ "description": "An additional description for the address",
+ "nullable": true
+ },
+ "company_name": {
+ "type": "string",
+ "description": "the company name, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "first_name": {
+ "type": "string",
+ "description": "the first name of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "last_name": {
+ "type": "string",
+ "description": "the last name of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "salutation": {
+ "type": "string",
+ "description": "the salutation of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "title": {
+ "type": "string",
+ "description": "the title of the recipient, usually used as extra delivery instructions",
+ "nullable": true
+ },
+ "coordinates": {
+ "type": "string",
+ "description": "Geographical coordinates (latitude, longitude)",
+ "nullable": true,
+ "example": "50.948484, 6.943147"
+ },
+ "plot_of_land": {
+ "type": "string",
+ "description": "Plot of land information",
+ "nullable": true
+ },
+ "plot_area": {
+ "type": "string",
+ "description": "Area of the plot",
+ "nullable": true
+ },
+ "start_date": {
+ "type": "string",
+ "description": "Start date for the address",
+ "format": "date",
+ "nullable": true
+ },
+ "end_date": {
+ "type": "string",
+ "description": "End date for the address",
+ "format": "date",
+ "nullable": true
+ }
+ }
+ }
+ }
+}
\ No newline at end of file