---
title: "simulateMappingV2"
method: POST
path: "/v2/erp/updates/mapping_simulation"
tags: ["erp"]
---

# simulateMappingV2

`POST /v2/erp/updates/mapping_simulation`

Test v2.0 mapping configuration by transforming a payload using the provided mapping rules without persisting data.

This endpoint accepts the same configuration format that is stored in the integration use case resource,
making it easier to test configurations before saving them to a use case.

See documentation at /docs/MAPPING_V2.md for detailed v2.0 format specification.

## Request body

- MappingSimulationV2Request — Request for v2 mapping simulation. Uses the same configuration format stored in integration use case resources, making it easier to test configurations before saving them.
  - `event_configuration` InboundIntegrationEventConfiguration, required — Configuration for inbound use cases (ERP to epilot)
    - `entities` IntegrationEntity[] — Array of entity configurations for this event
      - `entity_schema` string, required — Target entity schema (e.g., 'contact', 'contract')
      - `unique_ids` string[], required — Array of attribute names that uniquely identify this entity. The _type hint for repeatable fields (e.g., email, phone) should be specified on the corresponding field definition in the fields array.
      - `jsonataExpression` string — Optional JSONata expression to pre-process the event data before field mapping
      - `enabled` union — Controls whether this entity mapping should be processed. Can be a boolean or a JSONata expression (string) that evaluates to a boolean.
        - boolean
        - string
      - `mode` 'upsert' | 'delete' | 'purge' | 'upsert-prune-scope-purge' | 'upsert-prune-scope-delete' — Operation mode for entity mapping: - 'upsert': Create or update the entity (default) - 'delete': Soft delete the entity (marks as deleted) - 'purge': Hard delete the entity (permanent removal) - 'upsert-prune-scope-purge': Upsert entities from array, then purge entities in scope that weren't upserted - 'upsert-prune-scope-delete': Upsert entities from array, then soft delete entities in scope that weren't upserted
      - `scope` PruneScopeConfig — Scope configuration for upsert-prune-scope modes. Defines how to find entities that should be pruned if not in the upsert payload. The scope is resolved against the original event payload (not individual array items).
        - `scope_mode` 'relations' | 'query', required — Scope mode for finding entities to prune: - 'relations': Find scope by looking at all entities related to a specific entity (both direct and reverse relations) - 'query': Find scope entities directly via query parameters
        - `schema` string — For 'relations' mode: The schema of the entity to find (e.g., 'billing_account'). Not used for 'query' mode.
        - `unique_ids` RelationUniqueIdField[] — For 'relations' mode: How to identify the scope entity from the payload. Not used for 'query' mode.
          - `attribute` string, required — Target attribute name in the related entity
          - `_type` 'email' | 'phone' — Type hint for repeatable fields that require special search handling. These fields are stored as arrays of objects (e.g., email: [{ email: "value" }]).
          - `field` string — Source field name from the event data
          - `jsonataExpression` string — JSONata expression to compute the value
          - `constant` unknown
        - `query` RelationUniqueIdField[] — For 'query' mode: Direct query parameters to find scope entities. Not used for 'relations' or 'reverse-relations' modes.
          - `attribute` string, required — Target attribute name in the related entity
          - `_type` 'email' | 'phone' — Type hint for repeatable fields that require special search handling. These fields are stored as arrays of objects (e.g., email: [{ email: "value" }]).
          - `field` string — Source field name from the event data
          - `jsonataExpression` string — JSONata expression to compute the value
          - `constant` unknown
      - `fields` IntegrationEntityField[], required — Field mapping definitions
        - `attribute` string, required — Target attribute name
        - `field` string — Source field name or JSONPath expression (if starts with $)
        - `jsonataExpression` string — JSONata expression for transformation
        - `constant` unknown
        - `_type` 'email' | 'phone' — Type hint for repeatable fields that require special search handling. These fields are stored as arrays of objects (e.g., email: [{ email: "value" }]).
        - `enabled` union — Controls whether this field mapping should be processed. Can be a boolean or a JSONata expression (string) that evaluates to a boolean. Defaults to true if omitted.
          - boolean
          - string
        - `relations` RelationConfig
          - `operation` '_set' | '_append' | '_append_all', required — Relation operation: - '_set': Replace all existing relations with the specified items - '_append': Add new unique items to existing relations (deduplicates by entity_id) - '_append_all': Add all items to existing relations (no deduplication, allows duplicates)
          - `items` RelationItemConfig[] — Array of relation item configurations
            - `entity_schema` string, required — Related entity schema
            - `_tags` string[] — Optional tags for this relation
            - `unique_ids` RelationUniqueIdField[], required — Unique identifier mappings for the related entity
              - …
          - `jsonataExpression` string — JSONata expression that returns relation items array (alternative to 'items')
        - `relation_refs` RelationRefsConfig — Configuration for relation references ($relation_ref). Relation references link to a specific item within a repeatable attribute on a related entity. Common use case: referencing a specific address within a contact's address list.
          - `operation` '_set' | '_append' | '_append_all', required — Relation reference operation: - '_set': Replace all existing relation_refs with the specified items - '_append': Add new unique items to existing relation_refs (deduplicates by entity_id + _id) - '_append_all': Add all items to existing relation_refs (no deduplication, allows duplicates)
          - `items` RelationRefItemConfig[] — Array of relation reference item configurations
            - `entity_schema` string, required — Schema of the related entity (e.g., "contact")
            - `unique_ids` RelationUniqueIdField[], required — Unique identifier mappings for the related entity
              - …
            - `path` string, required — Attribute path on the related entity (e.g., "address")
            - `value` RelationRefValueConfig, required — Configuration for the value to set on the related entity's attribute
              - …
          - `jsonataExpression` string — JSONata expression that returns relation_ref items array (alternative to 'items')
        - `file_proxy_url` union — Auto-constructs a file proxy download URL. orgId and integrationId are injected from context. Exactly one of use_case_id or use_case_slug must be provided. Using use_case_slug is recommended as it is portable across environments.
          - object
            - `use_case_slug` string, required — Recommended. Slug of the file_proxy use case. Maps to useCaseSlug query parameter. Portable across environments.
            - `params` FileProxyUrlParams — Custom query parameters. Keys become URL param names, values resolved from payload.
          - object
            - `use_case_id` string, required — Legacy. UUID of the file_proxy use case. Maps to useCaseId query parameter. Prefer use_case_slug for portable configuration.
            - `params` FileProxyUrlParams — Custom query parameters. Keys become URL param names, values resolved from payload.
        - `portal_ref` union — Resolves to a property of one of the calling organization's epilot portal configurations at runtime, replacing hard-coded environment-specific portal UUIDs in inbound mappings. Matched portals are sorted ascending by `(_created_at, portal_id)`; portals without `_created_at` sort first (treated as oldest). When `select: "single"` matches more than one portal, the resolver still returns the oldest match and emits a `PORTAL_REF_AMBIGUOUS` warning.
          - object
            - `filter` PortalRefFilter — Filter applied to the org's portal configurations before selection. All filters default to "match any" except `enabled` (default `true`) and `is_dummy` (default `false`). Set `enabled` or `is_dummy` to `null` to opt out of the default.
              - …
            - `select` 'single' | 'all' — `single` returns one literal value (the oldest matching portal); `all` returns an array of literal values (0, 1, or many).
            - `return` 'portal_id' | 'origin' | 'domain' | 'name' — Which portal field to emit.
          - object
            - `filter` PortalRefFilter — Filter applied to the org's portal configurations before selection. All filters default to "match any" except `enabled` (default `true`) and `is_dummy` (default `false`). Set `enabled` or `is_dummy` to `null` to opt out of the default.
              - …
            - `select` 'single' | 'all'
            - `return` 'jsonata', required — Evaluate the sibling `jsonataExpression` against the matched portal(s). With `select: "single"` the input is the matched PortalConfig object; with `select: "all"` it is the full filtered+sorted array.
            - `jsonataExpression` string, required — JSONata expression evaluated against the matched portal(s).
        - `env_var_ref` union — Resolves to an org-scoped environment variable from the epilot environments-api service at runtime, replacing hard-coded environment-specific values (URLs, prefixes, identifiers) in inbound mappings. Secrets (`SecretString` values) are never exposed; the runtime treats both "missing key" and "secret-typed key" as identical `undefined` outcomes (no info disclosure via error code). For secret-resolving contexts (e.g. authorization headers in managed-call or file-proxy step configurations), use the templated `{{ env.<key> }}` syntax instead — that mechanism does decrypt secrets.
          - object
            - `key` string, required — Environment variable key. Must match the environments-api key contract (lowercase, digits, `_`, `.`, `-`; max 128 chars; starts with a lowercase letter or digit). Supports dot-namespaced keys like `erp_api.base_url`.
            - `default` string — Literal string returned when the key is missing (or is a secret). When provided, the `ENV_VAR_REF_NOT_FOUND` warning is suppressed because the author signalled the absence is expected.
            - `return` 'value' — `value` returns the resolved env-var string as-is.
          - object
            - `key` string, required
            - `default` string
            - `return` 'jsonata', required — Evaluate the sibling `jsonataExpression` against the resolved env-var value (the input `$` is the string value).
            - `jsonataExpression` string, required — JSONata expression evaluated against the resolved env-var value.
    - `meter_readings` IntegrationMeterReading[] — Array of meter reading configurations for this event
      - `jsonataExpression` string — Optional JSONata expression to extract meter reading items from the event data. 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 (e.g., "$.readings").
      - `reading_matching` 'external_id' | 'strict-date' — Strategy for matching incoming readings against existing readings. - 'external_id': Match readings by external_id attribute (default behavior) - 'strict-date': Match by meter_id + counter_id + direction + date (German timezone). Useful when readings originate from ECP and are echoed back by the ERP with truncated timestamps.
      - `mode` 'upsert' | 'delete' | 'upsert-prune-scope' — Operation mode for meter reading mapping: - 'upsert': Create or update meter readings (default) - 'delete': Delete the meter reading - 'upsert-prune-scope': Upsert readings from array, then delete all other readings for the same meter+counter that weren't upserted
      - `scope` MeterReadingPruneScopeConfig — Scope configuration for meter reading upsert-prune-scope mode. The scope is all readings for the same meter + counter.
        - `source` string — Optional source filter. When set, only readings with this source are eligible for pruning (e.g., 'ERP' to only prune ERP-synced readings).
      - `meter` MeterUniqueIdsConfig, required
        - `unique_ids` RelationUniqueIdField[], required — Array of unique identifier field mappings
          - `attribute` string, required — Target attribute name in the related entity
          - `_type` 'email' | 'phone' — Type hint for repeatable fields that require special search handling. These fields are stored as arrays of objects (e.g., email: [{ email: "value" }]).
          - `field` string — Source field name from the event data
          - `jsonataExpression` string — JSONata expression to compute the value
          - `constant` unknown
      - `meter_counter` MeterUniqueIdsConfig
        - `unique_ids` RelationUniqueIdField[], required — Array of unique identifier field mappings
          - `attribute` string, required — Target attribute name in the related entity
          - `_type` 'email' | 'phone' — Type hint for repeatable fields that require special search handling. These fields are stored as arrays of objects (e.g., email: [{ email: "value" }]).
          - `field` string — Source field name from the event data
          - `jsonataExpression` string — JSONata expression to compute the value
          - `constant` unknown
      - `fields` IntegrationEntityField[], required — Field mapping definitions for meter reading attributes
        - `attribute` string, required — Target attribute name
        - `field` string — Source field name or JSONPath expression (if starts with $)
        - `jsonataExpression` string — JSONata expression for transformation
        - `constant` unknown
        - `_type` 'email' | 'phone' — Type hint for repeatable fields that require special search handling. These fields are stored as arrays of objects (e.g., email: [{ email: "value" }]).
        - `enabled` union — Controls whether this field mapping should be processed. Can be a boolean or a JSONata expression (string) that evaluates to a boolean. Defaults to true if omitted.
          - boolean
          - string
        - `relations` RelationConfig
          - `operation` '_set' | '_append' | '_append_all', required — Relation operation: - '_set': Replace all existing relations with the specified items - '_append': Add new unique items to existing relations (deduplicates by entity_id) - '_append_all': Add all items to existing relations (no deduplication, allows duplicates)
          - `items` RelationItemConfig[] — Array of relation item configurations
            - `entity_schema` string, required — Related entity schema
            - `_tags` string[] — Optional tags for this relation
            - `unique_ids` RelationUniqueIdField[], required — Unique identifier mappings for the related entity
              - …
          - `jsonataExpression` string — JSONata expression that returns relation items array (alternative to 'items')
        - `relation_refs` RelationRefsConfig — Configuration for relation references ($relation_ref). Relation references link to a specific item within a repeatable attribute on a related entity. Common use case: referencing a specific address within a contact's address list.
          - `operation` '_set' | '_append' | '_append_all', required — Relation reference operation: - '_set': Replace all existing relation_refs with the specified items - '_append': Add new unique items to existing relation_refs (deduplicates by entity_id + _id) - '_append_all': Add all items to existing relation_refs (no deduplication, allows duplicates)
          - `items` RelationRefItemConfig[] — Array of relation reference item configurations
            - `entity_schema` string, required — Schema of the related entity (e.g., "contact")
            - `unique_ids` RelationUniqueIdField[], required — Unique identifier mappings for the related entity
              - …
            - `path` string, required — Attribute path on the related entity (e.g., "address")
            - `value` RelationRefValueConfig, required — Configuration for the value to set on the related entity's attribute
              - …
          - `jsonataExpression` string — JSONata expression that returns relation_ref items array (alternative to 'items')
        - `file_proxy_url` union — Auto-constructs a file proxy download URL. orgId and integrationId are injected from context. Exactly one of use_case_id or use_case_slug must be provided. Using use_case_slug is recommended as it is portable across environments.
          - object
            - `use_case_slug` string, required — Recommended. Slug of the file_proxy use case. Maps to useCaseSlug query parameter. Portable across environments.
            - `params` FileProxyUrlParams — Custom query parameters. Keys become URL param names, values resolved from payload.
          - object
            - `use_case_id` string, required — Legacy. UUID of the file_proxy use case. Maps to useCaseId query parameter. Prefer use_case_slug for portable configuration.
            - `params` FileProxyUrlParams — Custom query parameters. Keys become URL param names, values resolved from payload.
        - `portal_ref` union — Resolves to a property of one of the calling organization's epilot portal configurations at runtime, replacing hard-coded environment-specific portal UUIDs in inbound mappings. Matched portals are sorted ascending by `(_created_at, portal_id)`; portals without `_created_at` sort first (treated as oldest). When `select: "single"` matches more than one portal, the resolver still returns the oldest match and emits a `PORTAL_REF_AMBIGUOUS` warning.
          - object
            - `filter` PortalRefFilter — Filter applied to the org's portal configurations before selection. All filters default to "match any" except `enabled` (default `true`) and `is_dummy` (default `false`). Set `enabled` or `is_dummy` to `null` to opt out of the default.
              - …
            - `select` 'single' | 'all' — `single` returns one literal value (the oldest matching portal); `all` returns an array of literal values (0, 1, or many).
            - `return` 'portal_id' | 'origin' | 'domain' | 'name' — Which portal field to emit.
          - object
            - `filter` PortalRefFilter — Filter applied to the org's portal configurations before selection. All filters default to "match any" except `enabled` (default `true`) and `is_dummy` (default `false`). Set `enabled` or `is_dummy` to `null` to opt out of the default.
              - …
            - `select` 'single' | 'all'
            - `return` 'jsonata', required — Evaluate the sibling `jsonataExpression` against the matched portal(s). With `select: "single"` the input is the matched PortalConfig object; with `select: "all"` it is the full filtered+sorted array.
            - `jsonataExpression` string, required — JSONata expression evaluated against the matched portal(s).
        - `env_var_ref` union — Resolves to an org-scoped environment variable from the epilot environments-api service at runtime, replacing hard-coded environment-specific values (URLs, prefixes, identifiers) in inbound mappings. Secrets (`SecretString` values) are never exposed; the runtime treats both "missing key" and "secret-typed key" as identical `undefined` outcomes (no info disclosure via error code). For secret-resolving contexts (e.g. authorization headers in managed-call or file-proxy step configurations), use the templated `{{ env.<key> }}` syntax instead — that mechanism does decrypt secrets.
          - object
            - `key` string, required — Environment variable key. Must match the environments-api key contract (lowercase, digits, `_`, `.`, `-`; max 128 chars; starts with a lowercase letter or digit). Supports dot-namespaced keys like `erp_api.base_url`.
            - `default` string — Literal string returned when the key is missing (or is a secret). When provided, the `ENV_VAR_REF_NOT_FOUND` warning is suppressed because the author signalled the absence is expected.
            - `return` 'value' — `value` returns the resolved env-var string as-is.
          - object
            - `key` string, required
            - `default` string
            - `return` 'jsonata', required — Evaluate the sibling `jsonataExpression` against the resolved env-var value (the input `$` is the string value).
            - `jsonataExpression` string, required — JSONata expression evaluated against the resolved env-var value.
  - `format` 'json' | 'xml', required — Format of the payload data
  - `payload` union, required — The event data payload - can be either a serialized string or a direct JSON object
    - string — The serialized event data payload (JSON, XML, etc.) as a string
    - object — Direct JSON object (will be automatically serialized)

## Response `200`

Successfully simulated mapping

- MappingSimulationResponse
  - `entity_updates` EntityUpdate[], required
    - `entity_slug` string, required — The entity type slug
    - `unique_identifiers` object, required — Unique identifier mappings for this entity
    - `attributes` object, required — Mapped attribute values
  - `meter_readings_updates` MeterReadingUpdate[]
    - `meter` object, required
      - `$entity_unique_ids` object, required — Unique identifiers for the meter
    - `meter_counter` object
      - `$entity_unique_ids` object — Unique identifiers for the meter counter
    - `attributes` object, required — Meter reading attributes. Required: external_id, timestamp, source, value. `timestamp` must be ISO 8601 — either `YYYY-MM-DD` or `YYYY-MM-DDTHH:mm:ss` (with optional fractional seconds and optional `Z` / `±HH:mm` timezone offset); non-ISO formats (e.g. `DD.MM.YYYY` or epoch numbers) are rejected and must be converted upstream via a `jsonataExpression` (e.g. `$fromMillis(...)`). Date-only values are normalized to midnight UTC and offset-less date-times are anchored to UTC before being forwarded to the metering API. `source` must be one of: ECP, ERP, 360, journey-submission. `reason` (optional) must be one of: regular, irregular, last, first, meter_change, contract_change, meter_adjustment (or empty/null).
  - `warnings` MappingSimulationWarning[] — Validation warnings about the configuration (e.g., unique_ids referencing non-indexed fields)
    - `entity_schema` string, required — The entity schema slug where the issue was found
    - `field` string, required — The field name that caused the warning
    - `message` string, required — Description of the validation issue

## Other responses

- `400` — Bad request
- `401` — Unauthorized request
- `422` — Unprocessable entity - mapping configuration or payload validation failed
- `500` — Internal Server Error

---

[API](https://skmtc.net/epilot/apis/integration-toolkit-api.md) · [All operations](https://skmtc.net/epilot/apis/integration-toolkit-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/epilot/integration-toolkit-api/revisions/c24837d75096/schema)
