ERP Integration Mapping Specification v2.0
Overview​
The ERP Integration Mapping v2.0 provides a powerful and flexible way to transform ERP system events (customer updates, contract changes, etc.) into epilot entity updates. This document explains how to configure mappings to extract, transform, and structure data from your ERP system.
Table of Contents​
- Key Concepts
- Basic Structure
- Field Mapping Types
- Entity-Level Processing
- Relations
- Meter Readings
- Array Attribute Operations
- Complete Examples
- Best Practices
Key Concepts​
Events vs. Objects​
Version 2.0 uses an event-based approach instead of object-based:
- Events represent changes in your ERP system (e.g., "CustomerChanged", "ContractUpdated")
- Each event can map to multiple entities in epilot, also multiples of the same type
- Each entity mapping can be invoked multiple times from array data
Mapping Flow​
ERP Event Payload
↓
Entity-level JSONata (optional pre-processing)
↓
Field Mappings (extract attributes)
↓
Entity Updates (ready for epilot)
Basic Structure​
{
"version": "2.0",
"mapping": {
"events": {
"EventName": {
"entities": [
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"jsonataExpression": "...", // Optional
"enabled": true, // Optional (boolean or JSONata string)
"fields": [...]
}
]
}
}
}
}
Configuration Elements​
version: Must be"2.0"events: Object with event names as keysentities: Array of entity configurations for each evententity_schema: The epilot entity schema (e.g., "contact", "contract", "billing_account", see Core Entities)unique_ids: Array of attribute names that uniquely identify this entityjsonataExpression: Optional JSONata expression to pre-process the event dataenabled: Optional boolean or JSONata expression to conditionally enable/disable entity processing (defaults totrue)fields: Array of field mappings
Field Mapping Types​
1. Simple Field Mapping​
Direct mapping from event field to entity attribute.
Configuration:
{
"attribute": "first_name",
"field": "firstName"
}
Input:
{
"firstName": "John",
"lastName": "Doe"
}
Output:
{
"entity_slug": "contact",
"unique_identifiers": {...},
"attributes": {
"first_name": "John"
}
}
2. JSONPath Field Mapping​
Use JSONPath queries to extract nested data. Fields starting with $ are treated as JSONPath expressions.
Configuration:
{
"attribute": "street",
"field": "$.address.street"
}
Input:
{
"customerId": "12345",
"address": {
"street": "Main Street 42",
"city": "Berlin"
}
}
Output:
{
"attributes": {
"street": "Main Street 42"
}
}
3. JSONata Expression Mapping​
Transform data using JSONata expressions.
Configuration:
{
"attribute": "full_name",
"jsonataExpression": "firstName & ' ' & lastName"
}
Input:
{
"firstName": "John",
"lastName": "Doe"
}
Output:
{
"attributes": {
"full_name": "John Doe"
}
}
4. Constant Value Mapping​
Set a fixed value regardless of input data. Useful for setting tags, purposes, etc.
Configuration:
{
"attribute": "source",
"constant": "ERP_IMPORT"
}
Output:
{
"attributes": {
"source": "ERP_IMPORT"
}
}
Field-Level Processing Control​
Using enabled for Conditional Fields​
The enabled property allows you to conditionally include or exclude individual field mappings based on runtime conditions. This provides fine-grained control over which attributes are mapped without modifying your configuration structure.
Use Cases:
- Enable/disable specific fields without removing the configuration
- Conditionally map fields based on data presence or values
- Test or gradually roll out new field mappings
- Skip optional fields when data is missing or invalid
Value Types:
- Boolean (
true/false): Directly control whether the field is processed - String (JSONata expression): Dynamic evaluation based on the input data
- Undefined/omitted: Defaults to
true(field is always processed)
Important Notes:
- The
enabledproperty is evaluated for each field independently - When
enabledevaluates tofalse, the field value is never extracted or evaluated - Works with all field types: simple fields, JSONata expressions, constants, and relations
Example 1: Static Enable/Disable​
Control field processing with boolean values.
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"CustomerChanged": {
"entities": [
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"fields": [
{
"attribute": "customer_number",
"field": "customerId"
// No enabled - defaults to true
},
{
"attribute": "email",
"field": "email",
"enabled": true
// Explicitly enabled
},
{
"attribute": "internal_notes",
"field": "notes",
"enabled": false
// Disabled - will be skipped
}
]
}
]
}
}
}
}
Input:
{
"customerId": "12345",
"email": "user@example.com",
"notes": "Internal only"
}
Result:
{
"entity_slug": "contact",
"uniqueIdentifiers": {
"customer_number": "12345"
},
"attributes": {
"customer_number": "12345",
"email": "user@example.com"
// internal_notes is NOT included (disabled)
}
}
Example 2: Conditional with JSONata​
Use JSONata expressions to dynamically enable fields based on the input data.
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"CustomerChanged": {
"entities": [
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"fields": [
{
"attribute": "customer_number",
"field": "customerId"
},
{
"attribute": "phone",
"field": "phone",
"enabled": "$exists(phone) and phone != ''"
// Only map if phone exists and is not empty
},
{
"attribute": "mobile",
"field": "mobile",
"enabled": "$exists(mobile)"
// Only map if mobile field exists
},
{
"attribute": "vip_status",
"constant": "VIP",
"enabled": "vipFlag = true"
// Only set VIP status if vipFlag is true
}
]
}
]
}
}
}
}
Input:
{
"customerId": "12345",
"phone": "",
"mobile": "555-1234",
"vipFlag": true
}
Result:
{
"entity_slug": "contact",
"uniqueIdentifiers": {
"customer_number": "12345"
},
"attributes": {
"customer_number": "12345",
"mobile": "555-1234",
"vip_status": "VIP"
// phone is NOT included (empty string)
}
}
Explanation:
customer_number: Noenabledspecified → defaults totrue→ mappedphone:enabledevaluates tofalse(empty string) → not mappedmobile:enabledevaluates totrue(field exists) → mappedvip_status:enabledevaluates totrue(vipFlag is true) → mapped
Example 3: Conditional Relations​
Field-level enabled also works with relation mappings, allowing you to conditionally create entity relationships.
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"ContractChanged": {
"entities": [
{
"entity_schema": "contract",
"unique_ids": ["contract_number"],
"fields": [
{
"attribute": "contract_number",
"field": "number"
},
{
"attribute": "billing_account",
"enabled": "$exists(billingAccountId) and billingAccountId != ''",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "billing_account",
"unique_ids": [
{
"attribute": "external_id",
"field": "billingAccountId"
}
]
}
]
}
},
{
"attribute": "primary_contact",
"enabled": false,
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "contact",
"unique_ids": [
{
"attribute": "email",
"field": "contactEmail"
}
]
}
]
}
// This relation is disabled - won't be created
}
]
}
]
}
}
}
}
Input with billing account:
{
"number": "CTR-001",
"billingAccountId": "ACC-999",
"contactEmail": "john@example.com"
}
Result:
{
"entity_slug": "contract",
"uniqueIdentifiers": {
"contract_number": "CTR-001"
},
"attributes": {
"contract_number": "CTR-001",
"billing_account": {
"$relation": {
"_set": [
{
"$entity_unique_ids": {
"external_id": "ACC-999"
},
"_schema": "billing_account"
}
]
}
}
// primary_contact is NOT included (explicitly disabled)
}
}
Input without billing account:
{
"number": "CTR-002",
"billingAccountId": "",
"contactEmail": "jane@example.com"
}
Result:
{
"entity_slug": "contract",
"uniqueIdentifiers": {
"contract_number": "CTR-002"
},
"attributes": {
"contract_number": "CTR-002"
// billing_account is NOT included (enabled evaluated to false)
// primary_contact is NOT included (explicitly disabled)
}
}
Combining Field-Level and Entity-Level enabled​
Both entity-level and field-level enabled properties work together. The entity must be enabled first, then individual fields within that entity are evaluated.
Evaluation Order:
- Entity-level
enabledis checked → iffalse, entire entity is skipped - Entity-level
jsonataExpressionis applied (if present) - For each field:
- Field-level
enabledis checked → iffalse, field is skipped - Field value is extracted/evaluated (if enabled)
- Field-level
Configuration:
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"enabled": "$exists(customerId)",
"fields": [
{
"attribute": "customer_number",
"field": "customerId"
},
{
"attribute": "email",
"field": "email",
"enabled": "$exists(email)"
}
]
}
In this example:
- If
customerIddoesn't exist → entire entity is skipped (entity-levelenabled) - If
customerIdexists butemaildoesn't → entity is created with justcustomer_number
Entity-Level Processing​
Entity-level JSONata expressions pre-process data before field mappings are applied. This is powerful for:
- Transforming data structures
- Creating multiple entities from arrays
- Normalizing inconsistent data formats
Example: Array to Multiple Entities​
Configuration:
{
"entity_schema": "meter",
"unique_ids": ["meter_number"],
"jsonataExpression": "meters.{\n \"number\": number,\n \"type\": type = \"E\" ? \"electricity\" : type = \"G\" ? \"gas\" : type\n}",
"fields": [
{
"attribute": "meter_number",
"field": "number"
},
{
"attribute": "meter_type",
"field": "type"
}
]
}
Input:
{
"contractId": "CTR-001",
"meters": [
{ "number": "M-001", "type": "E" },
{ "number": "M-002", "type": "G" }
]
}
Output: (2 separate entity updates)
[
{
"entity_slug": "meter",
"unique_identifiers": { "meter_number": "M-001" },
"attributes": {
"meter_number": "M-001",
"meter_type": "electricity"
}
},
{
"entity_slug": "meter",
"unique_identifiers": { "meter_number": "M-002" },
"attributes": {
"meter_number": "M-002",
"meter_type": "gas"
}
}
]
Conditional Entity Processing with enabled​
The enabled field allows you to conditionally include or exclude entity mappings based on runtime conditions. This is useful when:
- You want to enable/disable specific entities without removing the configuration
- You need to conditionally create entities based on data presence or values
- You're testing or gradually rolling out new entity mappings
Value Types:
- Boolean (
true/false): Directly control whether the entity is processed - String (JSONata expression): Dynamic evaluation based on the data
- Undefined/omitted: Defaults to
true(entity is processed)
Important: If you use a JSONata expression for enabled, it's evaluated after the entity-level jsonataExpression (if present). This means you can use the pre-processed data in your condition.
Example: Static Enable/Disable​
Configuration:
{
"entities": [
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"enabled": true, // Explicitly enabled (same as omitting)
"fields": [...]
},
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"enabled": false, // Disabled - will be skipped
"fields": [...]
}
]
}
Example: Conditional with JSONata​
Configuration:
{
"entities": [
{
"entity_schema": "contract",
"unique_ids": ["contract_number"],
"enabled": "$exists(contract_number) and status = 'active'",
"fields": [
{
"attribute": "contract_number",
"field": "contract_number"
},
{
"attribute": "status",
"field": "status"
}
]
}
]
}
Input:
{
"contract_number": "CTR-123",
"status": "active"
}
Result: Entity is created because the condition evaluates to true.
Input:
{
"contract_number": "CTR-456",
"status": "inactive"
}
Result: Entity is not created because the condition evaluates to false.
Example: Combining with Entity-Level JSONata​
When using both jsonataExpression and enabled, the evaluation order is:
- Evaluate
jsonataExpression(pre-process data) - Evaluate
enabledagainst the pre-processed data - If enabled, process field mappings
Configuration:
{
"entity_schema": "meter",
"unique_ids": ["meter_number"],
"jsonataExpression": "meters[type='electricity']",
"enabled": "$count($) > 0", // Only process if array is not empty
"fields": [
{
"attribute": "meter_number",
"field": "number"
}
]
}
Input with electricity meters:
{
"contractId": "CTR-001",
"meters": [
{ "number": "M-001", "type": "electricity" },
{ "number": "M-002", "type": "gas" }
]
}
Result: Entity is created for the electricity meter because:
jsonataExpressionfilters to[{ "number": "M-001", "type": "electricity" }]enabledevaluates$count([...]) > 0→true
Input without electricity meters:
{
"contractId": "CTR-001",
"meters": [
{ "number": "M-002", "type": "gas" }
]
}
Result: No entity created because:
jsonataExpressionfilters to[](empty array)enabledevaluates$count([]) > 0→false
Relations​
Relations link entities together. v2.0 provides flexible relation configurations based on unique identifiers, which are resolved at the time of entity creation.
Relation Operations​
Relations support two operations that control how relation values are applied to entities:
_set Operation​
The _set operation replaces the entire relation attribute with the specified items. This is the default operation and is used when you want to completely overwrite any existing relations.
Behavior:
- Replaces all existing relation items with the new items
- If the entity doesn't exist yet, creates it with the specified relations
- Subsequent
_setoperations will completely replace previous values
Example:
{
"attribute": "billing_account",
"relations": {
"operation": "_set",
"items": [...]
}
}
Use Cases:
- Setting the initial relation when creating an entity
- Completely replacing a relation (e.g., changing primary contact)
- When the ERP system provides the complete, authoritative list of relations
_append Operation​
The _append operation adds new unique relation items to the end of existing ones (with automatic deduplication). This is useful for incremental updates where you want to preserve existing relations while adding new ones.
Behavior:
- Fetches the existing entity to retrieve current relation values
- Appends only NEW items to the end of the existing relation array (duplicates by
entity_idare filtered out) - If the entity doesn't exist, behaves the same as
_set(creates new entity with specified relations) - Preserves the order of existing items
Example:
{
"attribute": "contacts",
"relations": {
"operation": "_append",
"items": [
{
"entity_schema": "contact",
"_tags": ["NEW_CONTACT"],
"unique_ids": [...]
}
]
}
}
Example Scenario:
Initial entity state:
{
"contacts": {
"$relation": [
{ "entity_id": "existing-1", "_schema": "contact", "_tags": ["EXISTING"] }
]
}
}
After applying _append operation with entity_id "existing-1" and "new-1":
{
"contacts": {
"$relation": [
{ "entity_id": "existing-1", "_schema": "contact", "_tags": ["EXISTING"] },
{ "entity_id": "new-1", "_schema": "contact", "_tags": ["NEW_CONTACT"] }
]
}
}
Note: If "existing-1" was in the append list, it would be filtered out as a duplicate.
Use Cases:
- Adding additional contacts or billing accounts to an existing contract
- Incremental updates where the ERP system sends individual relation changes
- Preserving manually added relations while allowing ERP updates
Important Notes:
_appendrequires an additional database lookup to fetch the existing entity- Automatic deduplication - relations with the same
entity_idare NOT added again - The operation applies to both relation attributes and regular array attributes (like
_tags)
_append_all Operation​
The _append_all operation adds all relation items to the end of existing ones (without deduplication). Use this when you explicitly want to allow duplicate relations.
Behavior:
- Fetches the existing entity to retrieve current relation values
- Appends ALL items to the end of the existing relation array (duplicates ARE allowed)
- If the entity doesn't exist, behaves the same as
_set(creates new entity with specified relations) - Preserves the order of existing items
Example:
{
"attribute": "contacts",
"relations": {
"operation": "_append_all",
"items": [
{
"entity_schema": "contact",
"_tags": ["NEW_CONTACT"],
"unique_ids": [...]
}
]
}
}
Example Scenario:
Initial entity state:
{
"contacts": {
"$relation": [
{ "entity_id": "existing-1", "_schema": "contact", "_tags": ["EXISTING"] }
]
}
}
After applying _append_all operation with entity_id "existing-1" and "new-1":
{
"contacts": {
"$relation": [
{ "entity_id": "existing-1", "_schema": "contact", "_tags": ["EXISTING"] },
{ "entity_id": "existing-1", "_schema": "contact", "_tags": ["DUPLICATE"] },
{ "entity_id": "new-1", "_schema": "contact", "_tags": ["NEW_CONTACT"] }
]
}
}
Note: "existing-1" IS duplicated because _append_all skips deduplication.
Use Cases:
- When you explicitly need duplicate relations (rare use case)
- When deduplication behavior is not desired
Important Notes:
_append_allrequires an additional database lookup to fetch the existing entity- No deduplication - duplicate relations ARE added
- Use
_appendinstead if you want to prevent duplicate relations
Basic Relation with Items​
Configuration:
{
"attribute": "billing_account",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "billing_account",
"_tags": ["PRIMARY"],
"unique_ids": [
{
"attribute": "external_id",
"field": "accountId"
}
]
}
]
}
}
Input:
{
"contractNumber": "CTR-001",
"accountId": "ACC-999"
}
Final Entity State: (after relation resolution)
{
"entity_slug": "contract",
"attributes": {
"billing_account": {
"$relation": [{
"entity_id": "019a0c06-7190-7509-91c4-ff5bbe3680d8", // Resolved entity ID
"_schema": "billing_account",
"_tags": ["PRIMARY"]
}]
}
}
}
Multiple Relations​
Configuration:
{
"attribute": "contacts",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "contact",
"_tags": ["BILLING"],
"unique_ids": [
{
"attribute": "email",
"field": "billingEmail"
}
]
},
{
"entity_schema": "contact",
"_tags": ["TECHNICAL"],
"unique_ids": [
{
"attribute": "email",
"field": "technicalEmail"
}
]
}
]
}
}
Input:
{
"billingEmail": "billing@example.com",
"technicalEmail": "tech@example.com"
}
Final Entity State:
{
"contacts": {
"$relation": [
{
"entity_id": "019a0c06-1111-1111-1111-aaaaaaaaaaaa", // Resolved entity ID
"_schema": "contact",
"_tags": ["BILLING"]
},
{
"entity_id": "019a0c06-2222-2222-2222-bbbbbbbbbbbb", // Resolved entity ID
"_schema": "contact",
"_tags": ["TECHNICAL"]
}
]
}
}
Dynamic Relations with JSONata​
Use JSONata to dynamically generate relation items.
Configuration:
{
"attribute": "related_persons",
"relations": {
"operation": "_set",
"jsonataExpression": "persons.{\n \"entity_schema\": \"contact\",\n \"unique_ids\": [\n {\n \"attribute\": \"email\",\n \"constant\": email\n }\n ],\n \"_tags\": [role]\n}"
}
}
Input:
{
"persons": [
{ "email": "john@example.com", "role": "OWNER" },
{ "email": "jane@example.com", "role": "USER" }
]
}
Final Entity State:
{
"related_persons": {
"$relation": [
{
"entity_id": "019a0c06-3333-3333-3333-cccccccccccc", // Resolved entity ID
"_schema": "contact",
"_tags": ["OWNER"]
},
{
"entity_id": "019a0c06-4444-4444-4444-dddddddddddd", // Resolved entity ID
"_schema": "contact",
"_tags": ["USER"]
}
]
}
}
Relation Unique ID Options​
Relation unique IDs support three value sources, similar to field mappings:
1. Field:
{
"attribute": "customer_number",
"field": "customerNo"
}
2. JSONata Expression:
{
"attribute": "full_name",
"jsonataExpression": "firstName & ' ' & lastName"
}
3. Constant:
{
"attribute": "source",
"constant": "ERP"
}
Relation References​
Relation references ($relation_ref) allow you to link to a specific item within a repeatable attribute on a related entity. This is commonly used for addresses, where you want to reference not just a contact entity, but a specific address within that contact's address list.
Basic Concept​
While $relation links to an entity, $relation_ref links to:
- A related entity (by its
entity_id) - A specific attribute path on that entity (e.g.,
"address") - Optionally, a specific item within a repeatable attribute (by its
_id)
Configuration Structure​
{
"attribute": "billing_address",
"relation_refs": {
"operation": "_set", // or "_append"
"items": [
{
"entity_schema": "contact",
"unique_ids": [
{
"attribute": "customer_number",
"field": "CustomerNumber"
}
],
"path": "address", // Attribute path on the related entity
"value": {
"attribute": "address",
"operation": "_append", // Optional: operation for the attribute value
"jsonataExpression": "{\n \"street\": BillingStreet,\n \"city\": BillingCity,\n \"country\": 'DE',\n \"postal_code\": BillingPostalCode,\n \"street_number\": $string(BillingStreetNumber)\n}"
}
}
]
}
}
How It Works​
- Find or create the related entity: Uses
unique_idsto find/create the contact - Set the attribute value: Upserts the
addressattribute on the contact with the provided value - Preserve
_idvalues: Automatically matches existing address items by their content and preserves their_idto avoid regeneration - Create the reference: Links the main entity to the specific address item using
$relation_ref
Example: Billing Address Reference​
Configuration:
{
"version": "2.0",
"object_type": "Invoice",
"entities": [
{
"entity_schema": "opportunity",
"unique_ids": ["invoice_number"],
"fields": [
{
"attribute": "invoice_number",
"field": "InvoiceNumber"
},
{
"attribute": "billing_address",
"relation_refs": {
"operation": "_set",
"items": [
{
"entity_schema": "contact",
"unique_ids": [
{
"attribute": "customer_number",
"field": "CustomerNumber"
}
],
"path": "address",
"value": {
"attribute": "address",
"operation": "_append",
"jsonataExpression": "{\n \"street\": BillingStreet,\n \"city\": BillingCity,\n \"country\": 'DE',\n \"postal_code\": BillingPostalCode,\n \"street_number\": $string(BillingStreetNumber)\n}"
}
}
]
}
}
]
}
]
}
Input:
{
"InvoiceNumber": "INV-001",
"CustomerNumber": "CUST-123",
"BillingStreet": "Main Street",
"BillingStreetNumber": 42,
"BillingCity": "Berlin",
"BillingPostalCode": "10115"
}
Processing Flow:
- System finds or creates contact with
customer_number: "CUST-123" - Appends the address to the contact's address attribute:
{
"customer_number": "CUST-123",
"address": [
{
"_id": "abc123", // Auto-generated by Entity API
"street": "Main Street",
"street_number": "42",
"city": "Berlin",
"postal_code": "10115",
"country": "DE"
}
]
} - Creates the relation_ref on the opportunity:
{
"invoice_number": "INV-001",
"billing_address": {
"$relation_ref": [
{
"entity_id": "019a0c06-1234-5678-9abc-def012345678", // Contact entity ID
"path": "address",
"_id": "abc123" // Specific address item ID
}
]
}
}
_id Preservation​
The system automatically preserves _id values when updating repeatable attributes to avoid regenerating them:
- When setting or appending values, the system fetches the existing entity
- It matches new items with existing items using deep equality (excluding
_id) - If a match is found, the existing
_idis preserved - This ensures stable references even when data is updated
Example:
If the contact already has an address:
{
"address": [
{
"_id": "xyz789",
"street": "Old Street",
"city": "Munich"
}
]
}
And you update it with matching content:
{
"street": "Old Street",
"city": "Munich"
}
The system will preserve _id: "xyz789" instead of generating a new one.
Operations​
Relation references support three operations:
_set Operation​
Replaces all existing relation_refs with new ones:
{
"relation_refs": {
"operation": "_set",
"items": [...]
}
}
_append Operation​
Adds new unique relation_refs to existing ones (with automatic deduplication by entity_id + _id):
{
"relation_refs": {
"operation": "_append",
"items": [...]
}
}
Note: If a relation_ref with the same entity_id and _id combination already exists, it will NOT be added again.
_append_all Operation​
Adds all relation_refs to existing ones (without deduplication):
{
"relation_refs": {
"operation": "_append_all",
"items": [...]
}
}
Note: Duplicate relation_refs ARE allowed with _append_all. Use this when you explicitly need to allow duplicates.
Value Configuration​
The value field supports the same configuration options as regular field mappings:
Field Reference:
{
"attribute": "address",
"field": "AddressData"
}
JSONata Expression:
{
"attribute": "address",
"jsonataExpression": "{\n \"street\": street,\n \"city\": city\n}"
}
Constant:
{
"attribute": "type",
"constant": "BILLING"
}
All-or-Nothing Strategy​
Like regular relations, relation_refs use an all-or-nothing strategy:
- If ANY related entity in a relation_ref attribute cannot be found, the ENTIRE attribute is deferred to post_actions
- Post_actions will create the missing entities first
- Then the system retries the update with all entities available
- This ensures data integrity and proper ordering of entity creation
Multiple Relation References​
You can reference multiple items in a single attribute:
{
"attribute": "addresses",
"relation_refs": {
"operation": "_set",
"items": [
{
"entity_schema": "contact",
"unique_ids": [...],
"path": "address",
"value": {...}
},
{
"entity_schema": "contact",
"unique_ids": [...],
"path": "address",
"value": {...}
}
]
}
}
Meter Readings​
Meter readings are a special type of mapping that allows you to extract and transform meter reading data from ERP events. Unlike entity mappings, meter readings are stored as time-series data points associated with specific meters and optionally meter counters.
Overview​
Meter readings mappings enable you to:
- Extract meter reading data from ERP events
- Link readings to specific meters using unique identifiers
- Optionally specify meter counters for multi-tariff meters
- Transform and validate reading data before storage
Basic Structure​
{
"version": "2.0",
"mapping": {
"events": {
"MeterReadingsChanged": {
"meter_readings": [
{
"jsonataExpression": "$.readings",
"meter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "meter_id"
}
]
},
"meter_counter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "counter_id"
}
]
},
"fields": [
{
"attribute": "external_id",
"field": "reading_id"
},
{
"attribute": "timestamp",
"field": "read_at"
},
{
"attribute": "source",
"constant": "ERP"
},
{
"attribute": "value",
"field": "reading_value"
}
]
}
]
}
}
}
}
Required Elements​
Each meter_readings configuration must include:
meter: Configuration for identifying the meterunique_ids: Array of unique identifier mappings (at least one required)
fields: Array of field mappings with these required attributes:external_id: Unique identifier for this specific readingtimestamp: When the reading was taken (ISO 8601 format)source: Origin of the reading (e.g., "ERP", "ECP", "MANUAL")value: The actual meter reading value
Optional elements:
jsonataExpression: JSONata expression to extract reading data from the payload. If not provided, the entire payload is used as the reading data. Useful when you need to extract an array of readings from a nested structure.meter_counter: For multi-tariff meters, identifies the specific counterunique_ids: Array of unique identifier mappings (at least one if specified)
Unique Identifier Mappings​
Both meter and meter_counter unique identifiers support three value sources:
1. Field Mapping:
{
"attribute": "external_id",
"field": "meter_id"
}
2. JSONata Expression:
{
"attribute": "external_id",
"jsonataExpression": "$string(meter_number)"
}
3. Constant Value:
{
"attribute": "meter_type",
"constant": "electricity"
}
Field Attributes​
The fields array supports the same mapping types as entity fields:
Simple Field:
{
"attribute": "value",
"field": "reading_value"
}
JSONata Expression:
{
"attribute": "reason",
"jsonataExpression": "reading_type = 'REGULAR' ? 'regular' : 'irregular'"
}
Constant Value:
{
"attribute": "source",
"constant": "ERP"
}
Example 1: Basic Meter Readings​
Extract meter readings from an array in the event payload.
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"MeterReadingsChanged": {
"meter_readings": [
{
"jsonataExpression": "$.readings",
"meter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "meter_id"
}
]
},
"fields": [
{
"attribute": "external_id",
"field": "reading_id"
},
{
"attribute": "timestamp",
"field": "read_at"
},
{
"attribute": "source",
"constant": "ERP"
},
{
"attribute": "value",
"field": "reading_value"
},
{
"attribute": "direction",
"constant": "feed-in"
}
]
}
]
}
}
}
}
Input Event:
{
"readings": [
{
"meter_id": "M-001",
"reading_id": "R-001",
"read_at": "2025-01-15T10:00:00Z",
"reading_value": 12345.6
},
{
"meter_id": "M-001",
"reading_id": "R-002",
"read_at": "2025-01-15T11:00:00Z",
"reading_value": 12346.2
}
]
}
Output:
{
"meter_readings_updates": [
{
"meter": {
"$entity_unique_ids": {
"external_id": "M-001"
}
},
"attributes": {
"external_id": "R-001",
"timestamp": "2025-01-15T10:00:00Z",
"source": "ERP",
"value": 12345.6,
"direction": "feed-in"
}
},
{
"meter": {
"$entity_unique_ids": {
"external_id": "M-001"
}
},
"attributes": {
"external_id": "R-002",
"timestamp": "2025-01-15T11:00:00Z",
"source": "ERP",
"value": 12346.2,
"direction": "feed-in"
}
}
]
}
Example 2: Meter Readings with Counter​
For multi-tariff meters where each reading belongs to a specific counter (e.g., day/night tariffs).
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"MeterReadingsChanged": {
"meter_readings": [
{
"jsonataExpression": "$.readings",
"meter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "meter_id"
}
]
},
"meter_counter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "tariff_id"
}
]
},
"fields": [
{
"attribute": "external_id",
"jsonataExpression": "$string(meter_id) & '-' & $string(tariff_id) & '-' & $string(reading_id)"
},
{
"attribute": "timestamp",
"field": "read_at"
},
{
"attribute": "source",
"constant": "ERP"
},
{
"attribute": "value",
"field": "reading_value"
}
]
}
]
}
}
}
}
Input Event:
{
"readings": [
{
"meter_id": "M-001",
"tariff_id": "T1",
"reading_id": 1,
"read_at": "2025-01-15T10:00:00Z",
"reading_value": 5000.5
},
{
"meter_id": "M-001",
"tariff_id": "T2",
"reading_id": 2,
"read_at": "2025-01-15T10:00:00Z",
"reading_value": 7345.1
}
]
}
Output:
{
"meter_readings_updates": [
{
"meter": {
"$entity_unique_ids": {
"external_id": "M-001"
}
},
"meter_counter": {
"$entity_unique_ids": {
"tariff_id": "T1"
}
},
"attributes": {
"external_id": "M-001-T1-1",
"timestamp": "2025-01-15T10:00:00Z",
"source": "ERP",
"value": 5000.5
}
},
{
"meter": {
"$entity_unique_ids": {
"external_id": "M-001"
}
},
"meter_counter": {
"$entity_unique_ids": {
"tariff_id": "T2"
}
},
"attributes": {
"external_id": "M-001-T2-2",
"timestamp": "2025-01-15T10:00:00Z",
"source": "ERP",
"value": 7345.1
}
}
]
}
Example 3: Combined Entity and Meter Readings​
A single event can map to both entities and meter readings.
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"ContractWithReadings": {
"entities": [
{
"entity_schema": "contract",
"unique_ids": ["contract_number"],
"fields": [
{
"attribute": "contract_number",
"field": "number"
},
{
"attribute": "display_name",
"field": "name"
}
]
}
],
"meter_readings": [
{
"jsonataExpression": "$.readings",
"meter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "meter_id"
}
]
},
"fields": [
{
"attribute": "external_id",
"field": "reading_id"
},
{
"attribute": "timestamp",
"field": "read_at"
},
{
"attribute": "source",
"constant": "ERP"
},
{
"attribute": "value",
"field": "value"
}
]
}
]
}
}
}
}
Input Event:
{
"number": "CTR-001",
"name": "Main Contract",
"readings": [
{
"meter_id": "M-001",
"reading_id": "R-001",
"read_at": "2025-01-15T10:00:00Z",
"value": 12345.6
}
]
}
Output:
{
"entity_updates": [
{
"entity_slug": "contract",
"unique_identifiers": {
"contract_number": "CTR-001"
},
"attributes": {
"contract_number": "CTR-001",
"display_name": "Main Contract"
}
}
],
"meter_readings_updates": [
{
"meter": {
"$entity_unique_ids": {
"external_id": "M-001"
}
},
"attributes": {
"external_id": "R-001",
"timestamp": "2025-01-15T10:00:00Z",
"source": "ERP",
"value": 12345.6
}
}
]
}
Example 4: Single Meter Reading Without JSONata Expression​
When the event payload represents a single meter reading (not an array), you can omit the jsonataExpression field. The entire payload will be used as the reading data.
Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"MeterReadingUpdated": {
"meter_readings": [
{
"meter": {
"unique_ids": [
{
"attribute": "external_id",
"field": "meter_id"
}
]
},
"fields": [
{
"attribute": "external_id",
"field": "reading_id"
},
{
"attribute": "timestamp",
"field": "timestamp"
},
{
"attribute": "source",
"constant": "ERP"
},
{
"attribute": "value",
"field": "value"
}
]
}
]
}
}
}
}
Input Event:
{
"meter_id": "M-123",
"reading_id": "R-456",
"timestamp": "2025-01-15T14:30:00Z",
"value": 5678.9
}
Output:
{
"meter_readings_updates": [
{
"meter": {
"$entity_unique_ids": {
"external_id": "M-123"
}
},
"attributes": {
"external_id": "R-456",
"timestamp": "2025-01-15T14:30:00Z",
"source": "ERP",
"value": 5678.9
}
}
]
}
Validation​
The system validates meter readings configurations at runtime:
- Meter Configuration: Each meter_readings item must include a
meterdefinition - Meter Unique IDs: The
meter.unique_idsarray must contain at least one unique identifier - Required Fields: All meter_readings must include field mappings for:
external_idtimestampsourcevalue
- Meter Counter Validation: If
meter_counteris specified, it must have at least one unique identifier in itsunique_idsarray
Validation Error Example:
Meter readings configuration for "MeterReadingsChanged" (item 0) is missing required field attributes: timestamp, source, value
The error message includes the item index to help identify which specific meter_readings configuration has the issue when multiple configurations are present.
Best Practices​
Use Descriptive External IDs: Ensure reading
external_idvalues are unique and traceable{
"attribute": "external_id",
"jsonataExpression": "$string(meter_id) & '-' & $string(timestamp) & '-' & $string(reading_type)"
}Standardize Timestamps: Always use ISO 8601 format for timestamps We use the full timestamp for deduplication purposes, so in the case of multiple readings per day use a full timestamp.
{
"attribute": "timestamp",
"jsonataExpression": "$fromMillis(unix_timestamp * 1000)"
}Specify Source Clearly: Use consistent source values across your integration
{
"attribute": "source",
"constant": "ERP"
}
4Validate Data Quality: Use JSONata expressions to ensure data quality
{
"attribute": "value",
"jsonataExpression": "$number(reading_value) >= 0 ? $number(reading_value) : 0"
}
Array Attribute Operations​
Regular array attributes (like _tags, custom array fields, etc.) support _set, _append, and _append_all operations. These work similarly to relation operations but for simple array values.
_set for Array Attributes​
Replaces the entire array with new values.
Configuration:
{
"attribute": "_tags",
"field": "tags" // Assuming this returns an array or uses operations
}
With explicit operation (in attributes object):
{
"attributes": {
"_tags": {
"_set": ["CUSTOMER", "VIP", "ACTIVE"]
}
}
}
Result:
- Any existing tags are completely replaced
- The entity will have exactly the tags specified
_append for Array Attributes​
Adds new unique values to the end of existing array values (with automatic deduplication).
Configuration (in attributes object):
{
"attributes": {
"_tags": {
"_append": ["NEW_TAG", "ANOTHER_TAG"]
}
}
}
Example Scenario:
Initial entity state:
{
"_tags": ["EXISTING_TAG", "CUSTOMER"]
}
After applying _append with ["CUSTOMER", "NEW_TAG"]:
{
"_tags": ["EXISTING_TAG", "CUSTOMER", "NEW_TAG"]
}
Note: "CUSTOMER" is not duplicated because it already exists.
If entity doesn't exist:
Result:
{
"_tags": ["NEW_TAG", "ANOTHER_TAG"]
}
Important Notes:
_appendpreserves existing values and adds only new ones to the end- If the entity doesn't exist,
_appendbehaves like_set - Automatic deduplication - duplicate values are NOT added
- Works with any array-type attribute, not just
_tags
_append_all for Array Attributes​
Adds all values to the end of existing array values (without deduplication).
Configuration (in attributes object):
{
"attributes": {
"_tags": {
"_append_all": ["NEW_TAG", "ANOTHER_TAG"]
}
}
}
Example Scenario:
Initial entity state:
{
"_tags": ["EXISTING_TAG", "CUSTOMER"]
}
After applying _append_all with ["CUSTOMER", "NEW_TAG"]:
{
"_tags": ["EXISTING_TAG", "CUSTOMER", "CUSTOMER", "NEW_TAG"]
}
Note: "CUSTOMER" IS duplicated because _append_all skips deduplication.
If entity doesn't exist:
Result:
{
"_tags": ["NEW_TAG", "ANOTHER_TAG"]
}
Important Notes:
_append_allpreserves existing values and adds ALL new values to the end- If the entity doesn't exist,
_append_allbehaves like_set - No deduplication - duplicate values ARE added
- Use this when you explicitly want to allow duplicates
Complete Examples​
Example 1: Customer Update Event​
Maps a customer change event to a contact entity with billing account relation.
Mapping Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"CustomerChanged": {
"entities": [
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"fields": [
{
"attribute": "customer_number",
"field": "customerId"
},
{
"attribute": "first_name",
"field": "$.name.first"
},
{
"attribute": "last_name",
"field": "$.name.last"
},
{
"attribute": "email",
"field": "email"
},
{
"attribute": "full_name",
"jsonataExpression": "name.first & ' ' & name.last"
},
{
"attribute": "source",
"constant": "ERP"
},
{
"attribute": "billing_account",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "billing_account",
"_tags": ["PRIMARY"],
"unique_ids": [
{
"attribute": "external_id",
"field": "billingAccountId"
}
]
}
]
}
}
]
}
]
}
}
}
}
Input Event:
{
"customerId": "CUST-12345",
"name": {
"first": "Anna",
"last": "Schmidt"
},
"email": "anna.schmidt@example.com",
"billingAccountId": "BA-98765"
}
Output Entity:
{
"entity_slug": "contact",
"unique_identifiers": {
"customer_number": "CUST-12345"
},
"attributes": {
"customer_number": "CUST-12345",
"first_name": "Anna",
"last_name": "Schmidt",
"email": "anna.schmidt@example.com",
"full_name": "Anna Schmidt",
"source": "ERP",
"billing_account": {
"$relation": [{
"entity_id": "019a0c06-7190-7509-91c4-ff5bbe3680d8",
"_schema": "billing_account",
"_tags": ["PRIMARY"]
}]
}
}
}
Example 2: Contract with Multiple Meters​
Creates one contract entity and multiple meter entities from a single event.
Mapping Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"ContractChanged": {
"entities": [
{
"entity_schema": "contract",
"unique_ids": ["contract_number"],
"fields": [
{
"attribute": "contract_number",
"field": "contractNumber"
},
{
"attribute": "start_date",
"field": "startDate"
},
{
"attribute": "status",
"jsonataExpression": "active = true ? 'ACTIVE' : 'INACTIVE'"
}
]
},
{
"entity_schema": "meter",
"unique_ids": ["meter_number"],
"jsonataExpression": "meters.{\n \"number\": meterNumber,\n \"type\": meterType = 'E' ? 'electricity' : meterType = 'G' ? 'gas' : 'other'\n}",
"fields": [
{
"attribute": "meter_number",
"field": "number"
},
{
"attribute": "meter_type",
"field": "type"
}
]
}
]
}
}
}
}
Input Event:
{
"contractNumber": "CTR-2024-001",
"startDate": "2024-01-01",
"active": true,
"meters": [
{ "meterNumber": "M-001", "meterType": "E" },
{ "meterNumber": "M-002", "meterType": "G" },
{ "meterNumber": "M-003", "meterType": "E" }
]
}
Output Entities:
[
{
"entity_slug": "contract",
"unique_identifiers": { "contract_number": "CTR-2024-001" },
"attributes": {
"contract_number": "CTR-2024-001",
"start_date": "2024-01-01",
"status": "ACTIVE"
}
},
{
"entity_slug": "meter",
"unique_identifiers": { "meter_number": "M-001" },
"attributes": {
"meter_number": "M-001",
"meter_type": "electricity"
}
},
{
"entity_slug": "meter",
"unique_identifiers": { "meter_number": "M-002" },
"attributes": {
"meter_number": "M-002",
"meter_type": "gas"
}
},
{
"entity_slug": "meter",
"unique_identifiers": { "meter_number": "M-003" },
"attributes": {
"meter_number": "M-003",
"meter_type": "electricity"
}
}
]
Example 3: Complex Contract with Relations​
A comprehensive example showing contract with customer, billing account, and dynamic contact relations.
Mapping Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"ContractCreated": {
"entities": [
{
"entity_schema": "contract",
"unique_ids": ["contract_number"],
"fields": [
{
"attribute": "contract_number",
"field": "number"
},
{
"attribute": "display_name",
"field": "displayName"
},
{
"attribute": "contract_type",
"constant": "ENERGY"
},
{
"attribute": "primary_customer",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "contact",
"_tags": ["PRIMARY"],
"unique_ids": [
{
"attribute": "customer_number",
"field": "customerId"
}
]
}
]
}
},
{
"attribute": "billing_account",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "billing_account",
"unique_ids": [
{
"attribute": "external_id",
"field": "billingAccountId"
},
{
"attribute": "account_type",
"constant": "BILLING"
}
]
}
]
}
},
{
"attribute": "additional_contacts",
"relations": {
"operation": "_set",
"jsonataExpression": "contacts.{\n \"entity_schema\": \"contact\",\n \"unique_ids\": [\n {\n \"attribute\": \"email\",\n \"constant\": email\n }\n ],\n \"_tags\": [contactType]\n}"
}
}
]
}
]
}
}
}
}
Input Event:
{
"number": "CTR-2024-042",
"displayName": "Energy Supply Contract",
"customerId": "CUST-5678",
"billingAccountId": "BA-1234",
"contacts": [
{
"email": "technical@example.com",
"contactType": "TECHNICAL"
},
{
"email": "billing@example.com",
"contactType": "BILLING"
}
]
}
Output Entity:
{
"entity_slug": "contract",
"unique_identifiers": {
"contract_number": "CTR-2024-042"
},
"attributes": {
"contract_number": "CTR-2024-042",
"display_name": "Energy Supply Contract",
"contract_type": "ENERGY",
"primary_customer": {
"$relation": [{
"entity_id": "019a0c06-1111-1111-1111-111111111111",
"_schema": "contact",
"_tags": ["PRIMARY"]
}]
},
"billing_account": {
"$relation": [{
"entity_id": "019a0c06-2222-2222-2222-222222222222",
"_schema": "billing_account"
}]
},
"additional_contacts": {
"$relation": [
{
"entity_id": "019a0c06-3333-3333-3333-333333333333",
"_schema": "contact",
"_tags": ["TECHNICAL"]
},
{
"entity_id": "019a0c06-4444-4444-4444-444444444444",
"_schema": "contact",
"_tags": ["BILLING"]
}
]
}
}
}
Example 4: Conditional Field Processing with enabled​
A comprehensive example demonstrating field-level conditional processing using both boolean and JSONata enabled expressions.
Mapping Configuration:
{
"version": "2.0",
"mapping": {
"events": {
"CustomerChanged": {
"entities": [
{
"entity_schema": "contact",
"unique_ids": ["customer_number"],
"fields": [
{
"attribute": "customer_number",
"field": "customerId"
},
{
"attribute": "first_name",
"field": "firstName"
},
{
"attribute": "last_name",
"field": "lastName"
},
{
"attribute": "email",
"field": "email",
"enabled": "$exists(email) and email != ''"
},
{
"attribute": "phone",
"field": "phone",
"enabled": "$exists(phone) and phone != ''"
},
{
"attribute": "mobile",
"field": "mobile",
"enabled": "$exists(mobile) and mobile != ''"
},
{
"attribute": "vip_status",
"constant": "VIP",
"enabled": "isVip = true"
},
{
"attribute": "customer_type",
"jsonataExpression": "customerType = 'B' ? 'BUSINESS' : 'PRIVATE'",
"enabled": "$exists(customerType)"
},
{
"attribute": "internal_notes",
"field": "internalNotes",
"enabled": false
},
{
"attribute": "marketing_consent",
"field": "marketingConsent",
"enabled": "$exists(marketingConsent)"
},
{
"attribute": "billing_account",
"enabled": "$exists(billingAccountId) and billingAccountId != ''",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "billing_account",
"_tags": ["PRIMARY"],
"unique_ids": [
{
"attribute": "external_id",
"field": "billingAccountId"
}
]
}
]
}
},
{
"attribute": "contract",
"enabled": "$exists(contractNumber)",
"relations": {
"operation": "_set",
"items": [
{
"entity_schema": "contract",
"unique_ids": [
{
"attribute": "contract_number",
"field": "contractNumber"
}
]
}
]
}
}
]
}
]
}
}
}
}
Input Event (with all optional data):
{
"customerId": "CUST-2024-001",
"firstName": "Maria",
"lastName": "Garcia",
"email": "maria.garcia@example.com",
"phone": "+49-123-456789",
"mobile": "",
"isVip": true,
"customerType": "B",
"internalNotes": "High value customer - handle with care",
"marketingConsent": true,
"billingAccountId": "BA-12345",
"contractNumber": "CTR-2024-999"
}
Output Entity (with all optional data):
{
"entity_slug": "contact",
"uniqueIdentifiers": {
"customer_number": "CUST-2024-001"
},
"attributes": {
"customer_number": "CUST-2024-001",
"first_name": "Maria",
"last_name": "Garcia",
"email": "maria.garcia@example.com",
"phone": "+49-123-456789",
"vip_status": "VIP",
"customer_type": "BUSINESS",
"marketing_consent": true,
"billing_account": {
"$relation": {
"_set": [
{
"$entity_unique_ids": {
"external_id": "BA-12345"
},
"_schema": "billing_account",
"_tags": ["PRIMARY"]
}
]
}
},
"contract": {
"$relation": {
"_set": [
{
"$entity_unique_ids": {
"contract_number": "CTR-2024-999"
},
"_schema": "contract"
}
]
}
}
}
}
Note: Fields excluded from output:
mobile: Empty string (enabled condition failed)internal_notes: Explicitly disabled withenabled: false
Input Event (minimal data - many fields disabled):
{
"customerId": "CUST-2024-002",
"firstName": "John",
"lastName": "Smith",
"email": "",
"phone": "+49-987-654321",
"isVip": false,
"billingAccountId": ""
}
Output Entity (minimal data):
{
"entity_slug": "contact",
"uniqueIdentifiers": {
"customer_number": "CUST-2024-002"
},
"attributes": {
"customer_number": "CUST-2024-002",
"first_name": "John",
"last_name": "Smith",
"phone": "+49-987-654321"
}
}
Note: Fields excluded from output:
email: Empty string (enabled condition failed)mobile: Field doesn't exist in input (enabled condition failed)vip_status: isVip is false (enabled condition failed)customer_type: customerType field doesn't exist (enabled condition failed)internal_notes: Explicitly disabled withenabled: falsemarketing_consent: Field doesn't exist in input (enabled condition failed)billing_account: billingAccountId is empty string (enabled condition failed)contract: contractNumber field doesn't exist (enabled condition failed)
This example demonstrates how the enabled property allows the same mapping configuration to handle various data completeness scenarios gracefully, including only the fields that have valid data.
Best Practices​
1. Use Unique Identifiers Wisely​
Always map unique_ids from stable identifiers in your ERP system:
{
"unique_ids": ["customer_number"],
"fields": [
{
"attribute": "customer_number",
"field": "erpCustomerId"
}
]
}
2. Leverage Entity-Level JSONata for Arrays​
When dealing with array data, use entity-level JSONata:
{
"jsonataExpression": "items[status='active']",
"fields": [...]
}
3. Use Constants for Metadata​
Add source information or fixed values:
{
"attribute": "_source",
"constant": "SAP_ERP"
},
{
"attribute": "_imported_at",
"jsonataExpression": "$now()"
}
4. Normalize Data Early​
Use JSONata to standardize variations:
{
"attribute": "status",
"jsonataExpression": "status in ['active', 'Active', 'ACTIVE'] ? 'ACTIVE' : 'INACTIVE'"
}