@celigo/api-specs 0.2.196 → 0.2.197

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.yml CHANGED
@@ -2596,57 +2596,2862 @@ components:
2596
2596
  422 with its message. Any other `statusCode` is sent as returned.
2597
2597
  items:
2598
2598
  type: object
2599
+ properties:
2600
+ generate:
2601
+ type: string
2602
+ description: |
2603
+ **Purpose**
2604
+ Defines the target field name in the output object/record.
2605
+
2606
+ **Guidance**
2607
+ This is the PRIMARY FIELD that identifies the output property being created:
2608
+
2609
+ - For regular fields: Set to the exact property name (e.g., "firstName", "price", "isActive")
2610
+ - For object fields: Set to the object property name, then add child mappings in the 'mappings' array
2611
+ - For array fields: Set to the array property name, then configure 'buildArrayHelper'
2612
+ - One structural blank: the single top-level `objectarray` item of a `rows [ ]` mapping (the
2613
+ array output structure — see the array's description). A child-bearing wrapper and a source-only row that
2614
+ already exist in a saved document also stay unnamed when the tree is re-sent — filling in a
2615
+ name changes the output; it does not complete the row
2616
+
2617
+ IMPORTANT: Do NOT use dot notation (e.g., "customer.firstName") in this field. Instead, create proper
2618
+ hierarchical structure with nested mappings:
2619
+ ```json
2620
+ {
2621
+ "generate": "customer",
2622
+ "dataType": "object",
2623
+ "status": "Active",
2624
+ "mappings": [
2625
+ {"generate": "firstName", "dataType": "string", "extract": "$.name.first", "status": "Active"}
2626
+ ]
2627
+ }
2628
+ ```
2629
+
2630
+ When parsing existing mappings, an empty `generate` on a row inside an `arrayarray` row's
2631
+ `buildArrayHelper` entry is that row's inner array (`arrayarray` fails at run time; see
2632
+ `dataType`); other unnamed rows are the wrappers and source-only rows described above; an
2633
+ empty `generate` on the ONLY top-level item, with `dataType: objectarray`, is the `rows [ ]` JSON
2634
+ structure — array output, bound as `rows` in templates — and is intentional, not a missing name.
2635
+ examples:
2636
+ - name
2637
+ - address
2638
+ - items
2639
+ dataType:
2640
+ type: string
2641
+ description: |
2642
+ **Purpose**
2643
+ Explicitly declares the data type of the output field, controlling how data is processed and structured.
2644
+
2645
+ **Guidance**
2646
+ This is a REQUIRED field that fundamentally determines mapping behavior:
2647
+
2648
+ **Simple Types (direct value mapping)**
2649
+ - `string`: Text values, converts other types to string representation
2650
+ - `number`: Numeric values. Converts a numeric string (`"24"` → `24`,
2651
+ `"007"` → `7`) and leaves the field out for an empty string; a value
2652
+ holding letters or a thousands separator (`"1,250.00"`) fails the
2653
+ record with `non_parsable_string` (`<generate>: String contains alpha
2654
+ characters`)
2655
+ - `boolean`: True/false values, converts truthy/falsy values
2656
+
2657
+ Dates are represented as strings — use `string` for date fields and
2658
+ drive the parsing/formatting through the `extractDateFormat` /
2659
+ `generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`
2660
+ fields. There is no separate `date` enum value.
2661
+
2662
+ **Complex Types (require additional configuration)**
2663
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
2664
+ copies a whole object with `extract` (one or the other, not both)
2665
+
2666
+ **Array Types**
2667
+ - `stringarray`: Array of strings
2668
+ - `numberarray`: Array of numbers
2669
+ - `booleanarray`: Array of booleans
2670
+ - `objectarray`: Array of objects (most common array type)
2671
+
2672
+ `arrayarray` is not a type the mapper recognizes: a save accepts it, but every record
2673
+ then fails with `Destination datatype is a required field.` Build an array of arrays
2674
+ in a script hook instead.
2675
+
2676
+ Array dataTypes are populated two ways: construct or iterate through
2677
+ `buildArrayHelper` entries, or set a constant with `hardCodedValue`. The
2678
+ row's own `extract` is never read on an array type: a primitive-array row
2679
+ that has only an `extract` (JSONPath, Handlebars or a literal) yields
2680
+ nothing, with no error, and an `objectarray` row without `buildArrayHelper`
2681
+ or `hardCodedValue` is refused with 422 ("buildArrayHelper" or
2682
+ "hardCodedValue" must be present for object array datatype.). To copy a
2683
+ source array through unchanged, use one entry that iterates it
2684
+ (`buildArrayHelper: [{"extract": "$.items[*]"}]`).
2685
+
2686
+ IMPORTANT: The dataType controls which additional fields are relevant:
2687
+ - For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant
2688
+ - For object types: 'mappings' array becomes relevant
2689
+ - For array types: `buildArrayHelper` or `hardCodedValue` (see above)
2690
+
2691
+ When analyzing existing mappings or generating new ones, always check dataType first
2692
+ to understand what additional fields should be present.
2693
+ x-celigo-ai-guidance:
2694
+ - |-
2695
+ Missing `dataType` is rejected at save with validation error
2696
+ `[mandatory_destination_datatype] Destination datatype is a
2697
+ required field.`
2698
+ - |-
2699
+ Give each row the type the destination field expects; `"string"` is
2700
+ not a safe default. It accepts any source value, but sends a numeric
2701
+ source as text (`"24"`), which a destination that checks JSON types
2702
+ refuses. Map numeric destination fields as `number`, which fails a
2703
+ record (`non_parsable_string`) only when the value holds letters or a
2704
+ thousands separator.
2705
+ enum:
2706
+ - string
2707
+ - number
2708
+ - boolean
2709
+ - object
2710
+ - stringarray
2711
+ - numberarray
2712
+ - booleanarray
2713
+ - objectarray
2714
+ x-enumDescriptions:
2715
+ string: Text values; converts other types to their string representation.
2716
+ number: Numeric values; converts numeric strings, and fails the record (`non_parsable_string`) on letters or a thousands separator.
2717
+ boolean: True/false values; converts truthy/falsy values.
2718
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
2719
+ stringarray: Array of string values.
2720
+ numberarray: Array of numeric values.
2721
+ booleanarray: Array of boolean values.
2722
+ objectarray: Array of objects, the most common array type.
2723
+ examples:
2724
+ - string
2725
+ - number
2726
+ - object
2727
+ - objectarray
2728
+ extract:
2729
+ type: string
2730
+ description: |
2731
+ **Purpose**
2732
+ Defines how to retrieve data from the input record to populate the output field.
2733
+
2734
+ **Guidance**
2735
+ This field supports THREE DISTINCT PATTERNS that are easily distinguished:
2736
+
2737
+ **1. json Path Syntax**
2738
+ - MUST start with '$' — the record root. An object record is addressed as
2739
+ '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'
2740
+ - Used for precisely targeting data in structured JSON objects
2741
+ - Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',
2742
+ '$[*].Tax' (every row of a grouped record)
2743
+ - Wildcards like [*] extract multiple values/objects
2744
+ - A key that contains a dot needs bracket notation: `$['P.O. Number']` (or
2745
+ `$["P.O. Number"]`, `$.[P.O. Number]`). `$.P.O. Number` is read as a nested
2746
+ path: it maps nothing and the record still succeeds. Spaces, hyphens and `#`
2747
+ need no brackets (`$.Ship To Name`, `$.Tracking #`)
2748
+ - Filter expressions such as `$.items[?(@.active)]` fail the record with
2749
+ "Eval [?(expr)] prevented in JSONPath expression."
2750
+
2751
+ ```json
2752
+ "extract": "$.customer.addresses[*]" // Extracts all addresses
2753
+ ```
2754
+
2755
+ **2. Handlebars Template Syntax**
2756
+ - Contains '{{' and '}}' pattern
2757
+ - Evaluated by the AFE 2.0 handlebars template engine
2758
+ - Can include logic, formatting, and computation
2759
+ - Access input record fields with {{record.fieldName}} notation; a grouped
2760
+ (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}
2761
+ - Examples: "{{record.firstName}} {{record.lastName}}", "{{#if record.isActive}}Active{{else}}Inactive{{/if}}"
2762
+ - Valid on scalars and on `object` rows, where the rendered output must
2763
+ parse into an object. On an array row the template goes in a
2764
+ `buildArrayHelper` entry instead: on an `objectarray` row's own
2765
+ `extract` it is refused with 422 ("buildArrayHelper" or "hardCodedValue"
2766
+ must be present for object array datatype.), and on a primitive-array
2767
+ row's own `extract` it yields nothing (the field is left out) without an
2768
+ error
2769
+
2770
+ ```json
2771
+ "extract": "{{record.price}} {{record.currency}}" // Combines two fields
2772
+ ```
2773
+
2774
+ **3. Hard-Coded Value (literal string)**
2775
+ - Does NOT start with '$'
2776
+ - Does NOT contain handlebars '{{' syntax
2777
+ - System treats it as a literal string value
2778
+ - VERY COMMON for setting static/constant values
2779
+ - Examples: "Active", "USD", "Completed", "true"
2780
+
2781
+ ```json
2782
+ "extract": "primary" // Sets field value to the literal string "primary"
2783
+ "extract": "true" // Sets field value to the literal string "true"
2784
+ "extract": "N/A" // Sets field value to the literal string "N/A"
2785
+ ```
2786
+
2787
+ This third pattern is the simplest and most efficient way to set hard-coded values in your mappings.
2788
+ AI agents should use this pattern whenever a field needs a static value that doesn't come from
2789
+ the input record or require computation.
2790
+
2791
+ **Important implementation details**
2792
+
2793
+ - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
2794
+ - The system maintains this context even in deeply nested mappings
2795
+ - For object mappings without child mappings, extract should return a complete object
2796
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
2797
+ both: a row with both fails with 422 (`"extract" should not be present if
2798
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
2799
+ `extract` and `mappings` work together.
2800
+ - The root is the record as it arrives: an object record roots at `$.field`; a
2801
+ grouped record (an array of rows — grouped exports, file key columns, NetSuite
2802
+ grouped saved searches) roots at the array, so its rows are addressed as
2803
+ `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the
2804
+ record's shape resolves to nothing without an error.
2805
+
2806
+ For most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.
2807
+ For hard-coded values, simply use the literal string as the extract value.
2808
+ x-celigo-ai-guidance:
2809
+ - |-
2810
+ ## GROUPED (ARRAY) RECORDS
2811
+ Decide the JSONPath root from the record's shape before writing
2812
+ any extract. When the record is an array of rows, `$.field`,
2813
+ `$.properties.field` and `$.rows[*].field` all resolve to
2814
+ nothing — the processor still reports success and the request
2815
+ body ships as `{}`. Address rows as `$[0].field` (that row's
2816
+ value, typed) or `$[*].field` (every row: joined with commas
2817
+ into a `string` destination; rejected with
2818
+ `incompatible_destination_conversion` into a `number`
2819
+ destination). Column labels with spaces work as
2820
+ `$[*][Order Number]`, `$[*].[Order Number]`, or
2821
+ `$[*]['Order Number']`. For one destination element per row
2822
+ the two array kinds take different helper forms: a primitive
2823
+ array (`stringarray` / `numberarray`) uses `buildArrayHelper:
2824
+ [{"extract": "$[*].field"}]`; an `objectarray` uses
2825
+ `buildArrayHelper: [{"extract": "$[*]", "mappings": [...]}]`
2826
+ with the children addressing the row relatively (`$.field`,
2827
+ `{{rows.field}}`). An `extract` placed directly on the
2828
+ array-typed field yields nothing. Handlebars
2829
+ extracts bind the array record as `rows` (`{{rows.0.field}}`),
2830
+ an object record as `record`. The reverse holds too: `$[*]` on
2831
+ an object record iterates the object's values, not rows.
2832
+ - |-
2833
+ ## SIZE LIMIT
2834
+ The platform's import save validator caps this field at **1024
2835
+ characters**. Saves with a longer `extract` are rejected
2836
+ with `[size_limit_exceeded] The maximum size of the field:
2837
+ mappings.<index>.extract in the Import document should be
2838
+ 1024 characters`. This typically only matters for
2839
+ Handlebars templates that build complex strings inline -- if
2840
+ a template is approaching the cap, prefer one of:
2841
+
2842
+ - **Decompose into nested mappings** (set `dataType:
2843
+ "object"` and use child `mappings` -- each child gets
2844
+ its own 1024-char budget).
2845
+ - **Move the logic to a `preMap` hook** so the heavy
2846
+ transformation runs in script and the mapping just reads
2847
+ `record.<computed>`.
2848
+ - **Use a lookup** (`lookupName` + a small `lookups` entry)
2849
+ for value translation that would otherwise need a long
2850
+ `{{#if ...}}{{else if ...}}` chain.
2851
+ examples:
2852
+ - $.fullName
2853
+ - '{{record.fullName}}'
2854
+ - primary
2855
+ - $.lineItems[*].unitPrice
2856
+ extractDateFormat:
2857
+ type: string
2858
+ description: |
2859
+ Specifies the format pattern of the input date string to ensure proper parsing.
2860
+
2861
+ Used on string-typed mappings whose `extract` yields a date. Uses
2862
+ Moment.js-compatible formatting tokens to describe how the incoming date
2863
+ string is structured.
2864
+ examples:
2865
+ - YYYY-MM-DD
2866
+ - MM/DD/YYYY
2867
+ - DD-MMM-YYYY HH:mm:ss
2868
+ extractDateTimezone:
2869
+ type: string
2870
+ description: |
2871
+ Specifies the timezone of the input date string using Olson/IANA timezone identifiers.
2872
+
2873
+ Used on string-typed mappings whose `extract` yields a date; tells the system
2874
+ how to interpret timestamp values from the input system.
2875
+ examples:
2876
+ - UTC
2877
+ - America/New_York
2878
+ - Europe/London
2879
+ generateDateFormat:
2880
+ type: string
2881
+ description: |
2882
+ Specifies the output format pattern when generating a date string or converting
2883
+ from a Date type to String type.
2884
+
2885
+ Uses Moment.js-compatible formatting tokens to define the structure of the resulting
2886
+ date string.
2887
+ examples:
2888
+ - YYYY-MM-DD
2889
+ - MM/DD/YYYY
2890
+ - DD-MMM-YYYY HH:mm:ss
2891
+ generateDateTimezone:
2892
+ type: string
2893
+ description: |
2894
+ Specifies the timezone to apply when generating or converting timestamp values
2895
+ using Olson/IANA timezone identifiers.
2896
+
2897
+ Controls timezone conversion when producing date output.
2898
+ examples:
2899
+ - UTC
2900
+ - America/New_York
2901
+ - Europe/London
2902
+ default:
2903
+ type:
2904
+ - string
2905
+ - 'null'
2906
+ description: |
2907
+ Specifies a fallback value to use when extract returns empty/null or when conditional
2908
+ logic fails and no other mapping supplies a value.
2909
+
2910
+ Explicit JSON `null` is itself a valid fallback: the destination field is written as
2911
+ JSON null when the extract yields nothing (the Mapper UI's "Use null as default value"
2912
+ action). Omitting the key entirely means no fallback — the field is left out of the
2913
+ output when the extract is missing or an empty string (the UI's "Do nothing" action),
2914
+ while a null source is still written as null unless `conditional.when` is
2915
+ `extract_not_empty`. Failing the record instead is `conditional.when:
2916
+ fail_record_when_empty`, which excludes a default.
2917
+ x-celigo-ai-guidance:
2918
+ - |-
2919
+ `"default": null` and `"default": ""` are distinct saved values, not
2920
+ absent keys: null renders the destination field as JSON null and the
2921
+ empty string renders it as `""` when the extract yields nothing.
2922
+ Preserve them verbatim when editing or migrating a mapping — dropping
2923
+ the key changes runtime behavior from "use null/empty string as
2924
+ default value" to "do nothing" (a missing or `""` source is left out
2925
+ of the output, while a null source is written as null unless
2926
+ `conditional.when` is `extract_not_empty`).
2927
+ - |-
2928
+ The four "Action to take if source field has no value" choices map to:
2929
+ do nothing → no `default` key (add `conditional.when:
2930
+ extract_not_empty` to leave a null source out too; without it a null
2931
+ source is written as null); use null → `"default": null`; use empty string or
2932
+ a custom value → `"default": "<value>"`; cause the record to fail →
2933
+ `conditional.when: fail_record_when_empty` with no `default` key.
2934
+ examples:
2935
+ - N/A
2936
+ - '0'
2937
+ - 'false'
2938
+ lookupName:
2939
+ type: string
2940
+ description: |
2941
+ **Purpose**
2942
+ References a lookup table for transforming values during the mapping process.
2943
+
2944
+ **Usage**
2945
+
2946
+ The lookupName refers to a named lookup defined in the lookups array of the same resource.
2947
+ On an HTTP import that is `http.lookups`: a `lookups` array sent only at the top level
2948
+ is dropped on save. On an import, a name that matches no lookup fails every record
2949
+ with "Unable to find lookup in mapping configs - <name>", and a key the lookup
2950
+ doesn't hold follows the lookup's `allowFailures`: false fails the record; true, or
2951
+ the field left out, lets the record succeed with the lookup's `default`, or without
2952
+ the mapped field when there is none.
2953
+
2954
+ ```json
2955
+ {
2956
+ "generate": "countryName",
2957
+ "dataType": "string",
2958
+ "extract": "$.countryCode",
2959
+ "lookupName": "countryCodeToName"
2960
+ }
2961
+ ```
2962
+
2963
+ During processing, the system:
2964
+ 1. Extracts the value from the input record (e.g., "US")
2965
+ 2. Finds the lookup table with the specified name
2966
+ 3. Uses the extracted value as a key in the lookup
2967
+ 4. Returns the corresponding value (e.g., "United States")
2968
+
2969
+ **Benefits**
2970
+
2971
+ - **Standardization**: Ensures consistent value translation across mappings
2972
+ - **Centralization**: Define translations once and reference them in multiple places
2973
+ - **Maintainability**: Update all mappings by changing the lookup definition
2974
+ - **Readability**: Makes mappings more descriptive and self-documenting
2975
+
2976
+ The specific lookup capabilities depend on the context where mappings are used.
2977
+ examples:
2978
+ - countryCodeToName
2979
+ - statusMapping
2980
+ - departmentCodes
2981
+ hardCodedValue:
2982
+ type:
2983
+ - string
2984
+ - 'null'
2985
+ description: |
2986
+ Constant written to the destination instead of an extracted value. On a primitive
2987
+ array (`stringarray`, `numberarray`, `booleanarray`) the string is split on commas,
2988
+ verbatim and untrimmed, into elements of the array's type (`"A,B"` gives `["A", "B"]`).
2989
+ On an `object` it must be a JSON object string and on an `objectarray` a JSON array
2990
+ string (an object string becomes one element); the save parses it and refuses non-JSON
2991
+ or the wrong shape with 422, and an array row with a constant needs no `buildArrayHelper`.
2992
+ JSON `null` writes the destination field as null; it is what the mapper saves for its
2993
+ hard-coded "Use null as default value" choice.
2994
+ examples:
2995
+ - USD
2996
+ - A,B
2997
+ - '[{"code": "A"}, {"code": "B"}]'
2998
+ description:
2999
+ type: string
3000
+ description: |
3001
+ Optional free-text annotation that appears in the Mapper sidebar to provide context about
3002
+ the mapping's purpose for collaboration and documentation.
3003
+
3004
+ Has no functional impact on the mapping behavior.
3005
+ examples:
3006
+ - Maps customer name
3007
+ - Converts price to target currency
3008
+ - Formats date for target system
3009
+ sourceDataType:
3010
+ type: string
3011
+ description: |
3012
+ Declares the JSON type of the value produced by `extract`, before any
3013
+ conversion to `dataType`. Same enum as `dataType`. Set on leaf mappings
3014
+ only — parent mappings (with child `mappings` or `buildArrayHelper`)
3015
+ have no extracted value of their own; the children carry their own
3016
+ `sourceDataType`.
3017
+
3018
+ For date fields use `string` (JSON represents dates as strings); the
3019
+ parsing/formatting lives in `extractDateFormat` / `generateDateFormat` /
3020
+ `extractDateTimezone` / `generateDateTimezone`.
3021
+ enum:
3022
+ - string
3023
+ - number
3024
+ - boolean
3025
+ - object
3026
+ - stringarray
3027
+ - numberarray
3028
+ - booleanarray
3029
+ - objectarray
3030
+ - arrayarray
3031
+ x-enumDescriptions:
3032
+ string: Source value is a text string.
3033
+ number: Source value is numeric.
3034
+ boolean: Source value is true or false.
3035
+ object: Source value is a JSON object.
3036
+ stringarray: Source value is an array of strings.
3037
+ numberarray: Source value is an array of numbers.
3038
+ booleanarray: Source value is an array of booleans.
3039
+ objectarray: Source value is an array of objects.
3040
+ arrayarray: Source value is an array of arrays.
3041
+ examples:
3042
+ - string
3043
+ - number
3044
+ - boolean
3045
+ - object
3046
+ mappings:
3047
+ type: array
3048
+ description: |
3049
+ **Purpose**
3050
+ Enables recursive definition of nested object structures through child mapping objects.
3051
+
3052
+ **Guidance**
3053
+ This is the KEY FIELD that implements the recursive pattern at the core of this schema:
3054
+
3055
+ **When to Use**
3056
+ - REQUIRED when dataType = "object" (unless you are copying an entire object from the input record)
3057
+ - REQUIRED in buildArrayHelper.mappings when defining complex object array elements
3058
+ - NEVER used with simple types (string, number, boolean)
3059
+
3060
+ **Behavior**
3061
+ - Each mapping in this array becomes a property of the parent object
3062
+ - The full Mappings schema is repeated recursively at each level
3063
+ - Can be nested to any depth for complex hierarchical structures
3064
+
3065
+ **Context Handling**
3066
+ - Each level of nesting changes the mapping CONTEXT for 'generate'
3067
+ - The extraction CONTEXT always remains the original input record
3068
+ - This means child mappings can pull data from anywhere in the input record
3069
+
3070
+ **Common Patterns**
3071
+
3072
+ **Nested Objects**
3073
+ ```json
3074
+ {
3075
+ "generate": "customer",
3076
+ "dataType": "object",
3077
+ "mappings": [
3078
+ {
3079
+ "generate": "contact",
3080
+ "dataType": "object",
3081
+ "mappings": [
3082
+ {"generate": "email", "dataType": "string", "extract": "$.customerEmail"}
3083
+ ]
3084
+ }
3085
+ ]
3086
+ }
3087
+ ```
3088
+
3089
+ **Multiple Fields in Object**
3090
+ ```json
3091
+ {
3092
+ "generate": "address",
3093
+ "dataType": "object",
3094
+ "mappings": [
3095
+ {"generate": "street", "dataType": "string", "extract": "$.address.line1"},
3096
+ {"generate": "city", "dataType": "string", "extract": "$.address.city"},
3097
+ {"generate": "country", "dataType": "string", "extract": "$.address.country"}
3098
+ ]
3099
+ }
3100
+ ```
3101
+
3102
+ IMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = "object"
3103
+ or if you're inside buildArrayHelper.mappings for objectarray elements. These are the only
3104
+ valid contexts for the mappings array.
3105
+ items:
3106
+ $ref: '#/components/schemas/items'
3107
+ examples:
3108
+ - - generate: firstName
3109
+ extract: $.name.first
3110
+ dataType: string
3111
+ status: Active
3112
+ - generate: lastName
3113
+ extract: $.name.last
3114
+ dataType: string
3115
+ status: Active
3116
+ buildArrayHelper:
3117
+ type: array
3118
+ x-celigo-ai-guidance:
3119
+ - |-
3120
+ Entry-level `extract` accepts an iterating array path
3121
+ (`$.items[*]`), `"$"` (the record root), or omission — a
3122
+ constructed entry (child `mappings` with the extract omitted or
3123
+ `"$"`; the two spellings are equivalent) contributes exactly one
3124
+ element, and entries append in order. On a grouped (array)
3125
+ record the record itself is the array to iterate: `"$[*]"`
3126
+ yields one `objectarray` element per row (children address the
3127
+ row as `$.field`), and `"$[*].field"` yields one primitive-array
3128
+ value per row. Indexed or comma-joined
3129
+ entry extracts (`"$[0]"`, `"$[0],$[0]"`) are not valid: the
3130
+ processor renders the entire destination array as null with no
3131
+ validation error. To emit a fixed number of static elements, add
3132
+ that many sibling constructed entries — never index the extract.
3133
+ - |-
3134
+ An entry's `extract` can be a Handlebars template. On an
3135
+ `objectarray` it must render a JSON object (one element) or a JSON
3136
+ array (one element per item). On a primitive array each entry
3137
+ renders one element, so a serialized array becomes one string
3138
+ element. A bare literal entry extract is refused with 422 ("extract
3139
+ only supports json path or handlebars expression"); set a constant
3140
+ with the row's `hardCodedValue` instead.
3141
+ description: |
3142
+ **Purpose**
3143
+ Configures how to construct arrays in the output record, handling various array types and inputs.
3144
+
3145
+ **Guidance**
3146
+ This is the mechanism for building array data types:
3147
+
3148
+ **When to Use**
3149
+ - REQUIRED when dataType ends with "array" (stringarray, objectarray, etc.), unless the
3150
+ row sets `hardCodedValue`: an array row's own `extract` is never read (see `dataType`)
3151
+ - Each entry in this array contributes elements to the output array
3152
+ - Multiple entries allow combining data from different input arrays
3153
+
3154
+ **Array Type Handling**
3155
+
3156
+ **For Simple Arrays (stringarray, numberarray, booleanarray)**
3157
+ - Only the 'extract' field is used to pull values
3158
+ - JSON path with wildcards (e.g., $.items[*].name) returns multiple values;
3159
+ on a grouped (array) record the record itself is the array, so the
3160
+ path roots at it ($[*].name — one value per row)
3161
+ - Each result is converted to the appropriate primitive type
3162
+ ```json
3163
+ {
3164
+ "generate": "productNames",
3165
+ "dataType": "stringarray",
3166
+ "buildArrayHelper": [
3167
+ {"extract": "$.products[*].name"}
3168
+ ]
3169
+ }
3170
+ ```
3171
+
3172
+ **For Object Arrays (objectarray) - three patterns**
3173
+
3174
+ 1. Extract Only (existing objects):
3175
+ ```json
3176
+ {
3177
+ "generate": "contacts",
3178
+ "dataType": "objectarray",
3179
+ "buildArrayHelper": [
3180
+ {"extract": "$.account.primaryContacts[*]"}, // Pull primary contact objects
3181
+ {"extract": "$.account.secondaryContacts[*]"}, // Pull secondary contact objects
3182
+ {"extract": "$.vendor.contactPersons[*]"}, // Pull vendor contact objects
3183
+ {"extract": "$.subsidiaries[*].mainContact"} // Pull main contact from each subsidiary
3184
+ ]
3185
+ }
3186
+ ```
3187
+
3188
+ 2. Mappings Only (constructed object):
3189
+ ```json
3190
+ {
3191
+ "generate": "contactInfo",
3192
+ "dataType": "objectarray",
3193
+ "buildArrayHelper": [
3194
+ {
3195
+ "mappings": [ // Creates one object in the array
3196
+ {"generate": "type", "dataType": "string", "extract": "primary"},
3197
+ {"generate": "email", "dataType": "string", "extract": "$.primaryEmail"}
3198
+ ]
3199
+ },
3200
+ {
3201
+ "mappings": [ // Creates another object in the array
3202
+ {"generate": "type", "dataType": "string", "extract": "secondary"},
3203
+ {"generate": "email", "dataType": "string", "extract": "$.secondaryEmail"}
3204
+ ]
3205
+ }
3206
+ ]
3207
+ }
3208
+ ```
3209
+ Each constructed entry contributes exactly one element, in entry
3210
+ order; writing the entry with `"extract": "$"` is equivalent to
3211
+ omitting the extract (both anchor the element at the record root).
3212
+ A fixed number of static elements is built from that many sibling
3213
+ constructed entries.
3214
+
3215
+ 3. Extract AND Mappings (transform input arrays):
3216
+ ```json
3217
+ {
3218
+ "generate": "lineItems",
3219
+ "dataType": "objectarray",
3220
+ "buildArrayHelper": [
3221
+ {
3222
+ "extract": "$.order.items[*]", // For each item in the array
3223
+ "mappings": [ // Transform to this structure using the composite object
3224
+ {"generate": "sku", "dataType": "string", "extract": "$.order.items.productId"}, // Notice: items is singular
3225
+ {"generate": "quantity", "dataType": "number", "extract": "$.order.items.qty"}, // Notice: items is singular
3226
+ {"generate": "orderNumber", "dataType": "string", "extract": "$.order.id"}, // Access parent data
3227
+ {"generate": "customerName", "dataType": "string", "extract": "$.customerName"} // Access root data
3228
+ ]
3229
+ }
3230
+ ]
3231
+ }
3232
+ ```
3233
+
3234
+ **Arrays of Arrays**
3235
+ - The mapper has no working type for them: `arrayarray` saves, but every record
3236
+ fails with `Destination datatype is a required field.` Build an array of arrays
3237
+ in a script hook instead.
3238
+
3239
+ **Important details**
3240
+
3241
+ - When both extract and mappings are provided, the system creates special composite objects
3242
+ that maintain hierarchical context during processing
3243
+ - This enables accessing both the current array element AND its parent context
3244
+ - An ITERATING entry's extract MUST be a JSON path that iterates an array:
3245
+ '$.items[*]' when the array is a field of an object record, or '$[*]'
3246
+ (objectarray) / '$[*].field' (primitive arrays) when the record itself is a
3247
+ grouped array of rows. A CONSTRUCTED entry (child mappings building one
3248
+ element) instead omits extract or sets it to exactly "$" — never rewrite "$"
3249
+ into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the
3250
+ entire destination array as null without raising a validation error
3251
+ - Each array helper entry acts independently, potentially adding multiple elements
3252
+
3253
+ The buildArrayHelper is the most complex part of the mappings system - always analyze the
3254
+ dataType first to understand which pattern is appropriate.
3255
+ items:
3256
+ type: object
3257
+ properties:
3258
+ extract:
3259
+ type: string
3260
+ description: |
3261
+ JSON path expression that identifies the input array or values to extract.
3262
+
3263
+ For objectarray with mappings, this defines which input objects to iterate through.
3264
+ The JSON path must return either a single object or an array of objects.
3265
+
3266
+ For a CONSTRUCTED entry (child mappings building exactly one element from
3267
+ record-root fields and constants), omit this field or set it to exactly "$" —
3268
+ the two spellings are equivalent. Indexed or comma-joined forms ('$[0]',
3269
+ '$[0],$[0]') are not valid at the entry level: the processor renders the
3270
+ entire destination array as null without raising a validation error.
3271
+
3272
+ The system creates special composite objects during processing to maintain
3273
+ hierarchical relationships, allowing easy access to both the current array item
3274
+ and its parent contexts.
3275
+
3276
+ An iterating entry keeps the `[*]`: `$.line_items` without it yields one empty
3277
+ element per item, with no error. Child extracts drop the `[*]` but keep the
3278
+ array's path (`$.line_items.sku`); `$.line_items[*].sku` maps nothing, and an
3279
+ element-relative `$.sku` reads the record root instead of the element.
3280
+ examples:
3281
+ - $.items[*]
3282
+ - $.order.lineItems[*]
3283
+ - $.parents[*].children[*]
3284
+ - $
3285
+ name:
3286
+ type: string
3287
+ maxLength: 200
3288
+ description: |
3289
+ Display label for this source object in the mapper, so the sources of
3290
+ an object array can be told apart instead of all showing as `$`.
3291
+ Has no effect at runtime; stored only when non-empty.
3292
+ x-celigo-ai-guidance:
3293
+ - |-
3294
+ Carry an existing `name` through every edit — it is the user's label
3295
+ for the tab, and an entry sent without it loses the label. Duplicate
3296
+ names across entries are allowed. Set one only when the user names
3297
+ the source object; never invent labels.
3298
+ examples:
3299
+ - Billing address
3300
+ - Shipping address
3301
+ sourceDataType:
3302
+ type: string
3303
+ description: |
3304
+ Declares the JSON type of the input array being iterated, to ensure
3305
+ proper type handling during array construction. Same enum as `dataType`.
3306
+ enum:
3307
+ - string
3308
+ - number
3309
+ - boolean
3310
+ - object
3311
+ - stringarray
3312
+ - numberarray
3313
+ - booleanarray
3314
+ - objectarray
3315
+ - arrayarray
3316
+ x-enumDescriptions:
3317
+ string: Input array contains string elements.
3318
+ number: Input array contains numeric elements.
3319
+ boolean: Input array contains boolean elements.
3320
+ object: Input array contains object elements.
3321
+ stringarray: Input array contains arrays of strings.
3322
+ numberarray: Input array contains arrays of numbers.
3323
+ booleanarray: Input array contains arrays of booleans.
3324
+ objectarray: Input array contains arrays of objects.
3325
+ arrayarray: Input array contains arrays of arrays.
3326
+ examples:
3327
+ - string
3328
+ - number
3329
+ - boolean
3330
+ - object
3331
+ default:
3332
+ type:
3333
+ - string
3334
+ - 'null'
3335
+ description: |
3336
+ Specifies a fallback value when the extracted array element is empty or
3337
+ not found in the input data.
3338
+
3339
+ Explicit JSON `null` is itself a valid fallback (the element is written as
3340
+ JSON null); omitting the key means no fallback is applied.
3341
+ examples:
3342
+ - N/A
3343
+ - '0'
3344
+ - 'false'
3345
+ conditional:
3346
+ type: object
3347
+ description: |
3348
+ Defines conditional rules for including each array element in the result.
3349
+ x-celigo-ai-guidance:
3350
+ - |-
3351
+ Judged against this entry's own `extract` (the array source). The
3352
+ design scopes the UI's tab-level "Action to take if source field has
3353
+ no value" to copy-as-is tabs (no child `mappings`); the API accepts
3354
+ `fail_record_when_empty` on a mapped entry as well, and the mapper
3355
+ processor honors it there — the record fails when that array is
3356
+ missing or empty (`errors[]` entry `code: extract_empty`, `fatal:
3357
+ true`, message `<generate>: Source field has no value`; probed
3358
+ 2026-10-09). Say so when writing it on a mapped entry: the user may
3359
+ not find the setting in the mapper's tab. To fail on an empty field
3360
+ inside each element, set the action on that child mapping instead.
3361
+ properties:
3362
+ when:
3363
+ type: string
3364
+ description: |
3365
+ Condition judged on the entry's extract — skip the elements the
3366
+ extract does not return, or fail the whole record when the source
3367
+ array is missing or empty.
3368
+ enum:
3369
+ - extract_not_empty
3370
+ - fail_record_when_empty
3371
+ x-enumDescriptions:
3372
+ extract_not_empty: Include an array element only when the extract returns a non-empty value for it
3373
+ fail_record_when_empty: Fail the record when the entry's source array is missing or empty
3374
+ examples:
3375
+ - extract_not_empty
3376
+ mappings:
3377
+ type: array
3378
+ description: |
3379
+ Contains recursive mapping definitions for complex array element transformations.
3380
+
3381
+ **Composite object mechanism**
3382
+
3383
+ When both 'extract' and 'mappings' are used together, the system implements a sophisticated
3384
+ "composite object" approach that is crucial for AI agents to understand:
3385
+
3386
+ 1. The system starts with the complete input record
3387
+
3388
+ 2. For each array element matched by the extract path, it creates a modified version of
3389
+ the input record where:
3390
+ - Array paths in the extract JSON path are REPLACED with single objects
3391
+ - Each array ([]) in the path is converted to a single object ({})
3392
+ - This preserves the hierarchical relationship between nested arrays
3393
+
3394
+ **Example**
3395
+
3396
+ Given an input record:
3397
+ ```json
3398
+ {
3399
+ "customer": {
3400
+ "name": "John Doe",
3401
+ "orders": [
3402
+ {
3403
+ "id": "O-001",
3404
+ "items": [
3405
+ {"sku": "ABC", "qty": 2},
3406
+ {"sku": "XYZ", "qty": 1}
3407
+ ]
3408
+ },
3409
+ {
3410
+ "id": "O-002",
3411
+ "items": [
3412
+ {"sku": "DEF", "qty": 3}
3413
+ ]
3414
+ }
3415
+ ]
3416
+ }
3417
+ }
3418
+ ```
3419
+
3420
+ With extract path: `$.customer.orders[*].items[*]`
3421
+
3422
+ For each item, the system creates a composite object like:
3423
+ ```json
3424
+ {
3425
+ "customer": {
3426
+ "name": "John Doe",
3427
+ "orders": { // Note: Array replaced with single object
3428
+ "id": "O-001",
3429
+ "items": { // Note: Array replaced with single object
3430
+ "sku": "ABC",
3431
+ "qty": 2
3432
+ }
3433
+ }
3434
+ }
3435
+ }
3436
+ ```
3437
+
3438
+ Then in your mappings, you can access:
3439
+ - The current item: `$.customer.orders.items.sku`
3440
+ - The parent order: `$.customer.orders.id`
3441
+ - Top-level data: `$.customer.name`
3442
+
3443
+ This approach allows for precise mapping from deeply nested structures while maintaining
3444
+ access to all contextual parent data, without requiring complex array index management.
3445
+
3446
+ **Implementation guidance**
3447
+
3448
+ When implementing the composite object mechanism:
3449
+
3450
+ 1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)
3451
+ 2. For each array in the path, understand that it will be replaced with a single object
3452
+ 3. In the mappings, use paths that reference these arrays as if they were objects
3453
+ 4. Remember that every mapping still has access to the full input record context
3454
+ 5. This mechanism is especially powerful when mapping hierarchical data like:
3455
+ - Order → Line Items → Taxes/Discounts
3456
+ - Customer → Addresses → Address Lines
3457
+ - Invoice → Line Items → Serial Numbers
3458
+
3459
+ The extract path effectively tells the system "iterate through these arrays",
3460
+ while the composite object mechanism ensures you can still access both the
3461
+ current array item AND its parent context during mapping.
3462
+ items:
3463
+ $ref: '#/components/schemas/items'
3464
+ examples:
3465
+ - - generate: itemName
3466
+ extract: $.name
3467
+ dataType: string
3468
+ status: Active
3469
+ - generate: itemPrice
3470
+ extract: $.price
3471
+ dataType: number
3472
+ status: Active
3473
+ if:
3474
+ properties:
3475
+ conditional:
3476
+ properties:
3477
+ when:
3478
+ const: fail_record_when_empty
3479
+ required:
3480
+ - when
3481
+ required:
3482
+ - conditional
3483
+ then:
3484
+ not:
3485
+ required:
3486
+ - default
3487
+ status:
3488
+ type: string
3489
+ description: |
3490
+ **Purpose**
3491
+ Controls whether the mapping is applied. Send it on every mapping entry.
3492
+
3493
+ **Guidance**
3494
+ Only `Active` rows run. `Draft` and `Inactive` rows keep their
3495
+ configuration, are saved with minimal validation, and are skipped at
3496
+ runtime and in preview; a non-Active parent skips its whole subtree
3497
+ whatever its children say. Imports (on save and in the mapper processor)
3498
+ and API response mappings reject a row missing this field (validation
3499
+ error: "Mapping object must have status field present."); a Tool's
3500
+ output mapping saves and runs one, which is why `required` doesn't
3501
+ list it.
3502
+ x-celigo-ai-guidance:
3503
+ - |-
3504
+ Emit `"Active"` for mappings that should run; `"Draft"` is also
3505
+ accepted and saves the mapping while bypassing the Active-only
3506
+ field validations. The value is case-sensitive. The API rejects:
3507
+ - Missing field: `[status_field_absent] Mapping object must have status field present.`
3508
+ - Wrong case (e.g. `"active"`): `[invalid_status_enums] active is not a valid enum for status field.`
3509
+ - |-
3510
+ `"Inactive"` is the user's "Set inactive" on a row: use it only when
3511
+ asked to disable or park a row, never to mean incomplete (that is
3512
+ `"Draft"`). Setting a parent `Inactive` means no `Active` row may
3513
+ remain under it — the save rejects an `Active` row under an
3514
+ `Inactive` parent (`[inactive_parent_active_child]` on `mappings`,
3515
+ no message text) and never cascades or promotes on its own; `Draft`
3516
+ descendants are kept as they are, and a `Draft` parent does not gate
3517
+ its children. The UI's Set inactive on a parent marks the parent and
3518
+ every child `Inactive`. Re-enabling a child
3519
+ means re-enabling its ancestors in the same payload. Edits that keep
3520
+ existing rows must carry their stored status forward — rewriting a
3521
+ `Draft` or `Inactive` row to `Active` turns a row the user parked
3522
+ back on.
3523
+ enum:
3524
+ - Active
3525
+ - Draft
3526
+ - Inactive
3527
+ x-enumDescriptions:
3528
+ Active: The mapping is enabled and applied during processing
3529
+ Draft: In-progress mapping; saved without the Active-only field validations and skipped at runtime
3530
+ Inactive: Disabled by the user; configuration kept, skipped at runtime and in preview
3531
+ examples:
3532
+ - Active
3533
+ conditional:
3534
+ type: object
3535
+ description: |
3536
+ **Purpose**
3537
+ Defines conditional processing rules for the entire mapping.
3538
+
3539
+ **Guidance**
3540
+ These conditions determine whether the mapping is applied based on record
3541
+ state or field content:
3542
+
3543
+ **When to Use**
3544
+ - When a mapping should only be applied in specific circumstances
3545
+ - To implement conditional logic without using complex handlebars expressions
3546
+ - For creating mappings that only run during create or update operations
3547
+
3548
+ **Available Conditions**
3549
+
3550
+ - `record_created`: Apply only when creating a new record
3551
+ Useful for setting initial values that should not be overwritten during updates
3552
+
3553
+ - `record_updated`: Apply only when updating an existing record
3554
+ Useful for transformation logic that should only run during updates
3555
+
3556
+ - `extract_not_empty`: Apply only when the extract field returns a value
3557
+ Useful for conditional mapping based on input data availability
3558
+
3559
+ - `fail_record_when_empty`: Fail the record when the extract field returns
3560
+ no value (the UI's "Cause record to fail" action when the source field
3561
+ has no value)
3562
+
3563
+ **Example**
3564
+ ```json
3565
+ {
3566
+ "generate": "statusMessage",
3567
+ "dataType": "string",
3568
+ "status": "Active",
3569
+ "extract": "$.status.message",
3570
+ "conditional": {
3571
+ "when": "extract_not_empty" // Only map when status.message exists
3572
+ }
3573
+ }
3574
+ ```
3575
+ x-celigo-ai-guidance:
3576
+ - |-
3577
+ `when` holds one value, and two different settings share it: the
3578
+ composite-import operation gate (`record_created` / `record_updated`,
3579
+ the UI's "Only perform mapping when") and the empty-source action
3580
+ (`extract_not_empty` / `fail_record_when_empty`, the UI's "Action to
3581
+ take if source field has no value"). A row cannot carry both — writing
3582
+ one replaces the other and the save succeeds, so a composite import
3583
+ row that needs both has to choose. Never author `fail_record_when_empty`
3584
+ on a row that already carries `record_created` or `record_updated`.
3585
+ properties:
3586
+ when:
3587
+ type: string
3588
+ description: |
3589
+ Condition that gates this mapping — either an operation gate on a
3590
+ composite (create-or-update) import or the action to take when the
3591
+ extract returns no value. Empty means null, undefined or an empty
3592
+ string; `0`, `false` and whitespace are values.
3593
+ x-celigo-ai-guidance:
3594
+ - |-
3595
+ `fail_record_when_empty` is the fourth "Action to take if source field
3596
+ has no value" and is mutually exclusive with the other three: send it
3597
+ with no `default` key. A `default`, a `lookupName` or a `hardCodedValue`
3598
+ on the same row — or a `default` on a `buildArrayHelper` entry — is
3599
+ rejected at save with `[unsupported_mapping] "<key>" and conditional.when
3600
+ "fail_record_when_empty" cannot be present in mapping simultaneously.`
3601
+ (the lookup variant adds `Use lookup "allowFailures" instead.`);
3602
+ lookups fail through `allowFailures: false`, and a hard-coded row
3603
+ always has a value. At runtime an empty extract fails the record with
3604
+ an `errors[]` entry `{code: "extract_empty", fatal: true, source:
3605
+ "mapping", message: "<generate>: Source field has no value"}`
3606
+ ("Input field has no value" in a Transformation 2.0); `0` and `false`
3607
+ are values and map through.
3608
+ enum:
3609
+ - record_created
3610
+ - record_updated
3611
+ - extract_not_empty
3612
+ - fail_record_when_empty
3613
+ x-enumDescriptions:
3614
+ record_created: Apply this mapping only when creating a new record
3615
+ record_updated: Apply this mapping only when updating an existing record
3616
+ extract_not_empty: Apply this mapping only when the extract field returns a non-empty value
3617
+ fail_record_when_empty: Fail the record when the extract field returns no value
3618
+ examples:
3619
+ - record_created
3620
+ - record_updated
3621
+ - extract_not_empty
3622
+ - fail_record_when_empty
2599
3623
  required:
2600
3624
  - dataType
3625
+ if:
3626
+ properties:
3627
+ conditional:
3628
+ properties:
3629
+ when:
3630
+ const: fail_record_when_empty
3631
+ required:
3632
+ - when
3633
+ required:
3634
+ - conditional
3635
+ then:
3636
+ not:
3637
+ anyOf:
3638
+ - required:
3639
+ - default
3640
+ - required:
3641
+ - lookupName
3642
+ - required:
3643
+ - hardCodedValue
3644
+ Mappings:
3645
+ type: array
3646
+ description: |
3647
+ Array of field mapping configurations for transforming data from one format into another.
3648
+
3649
+ **Guidance**
3650
+
3651
+ This schema is designed around RECURSION as its core architectural principle. Understanding this recursive
3652
+ nature is essential for building effective mappings:
3653
+
3654
+ 1. The schema is self-referential by design - a mapping can contain nested mappings of the same structure
3655
+ 2. Complex data structures (nested objects and arrays of objects, to any depth) are ALL
3656
+ handled through this recursive pattern; an array of arrays is not (build one in a script hook)
3657
+ 3. Each mapping handles one level of the data structure; deeper levels are handled by nested mappings
3658
+
3659
+ When generating mappings programmatically:
3660
+ - For simple fields (string, number, boolean): Create single mapping objects
3661
+ - For objects: Create a parent mapping with nested 'mappings' array containing child field mappings
3662
+ - For arrays: Use 'buildArrayHelper' with extract paths defining array inputs and
3663
+ recursive 'mappings' to define object structures
3664
+
3665
+ The system will process these nested structures recursively during runtime, ensuring proper construction
3666
+ of complex hierarchical data while maintaining excellent performance.
3667
+
3668
+ On save, a leaf row with neither a source (`extract`, `hardCodedValue`, `lookupName`) nor a
3669
+ destination (`generate`) is dropped silently, at every nesting level, and so is an object or
3670
+ object-array row left with no source, no destination and no remaining child `mappings` or
3671
+ `buildArrayHelper` entries; a row with only one of the two, and a source-less, destination-less
3672
+ wrapper that still has children, are kept.
3673
+
3674
+ The shape of the array is the mapper's **JSON structure**. Named top-level items produce an object
3675
+ record (`record { }`). Exactly one top-level item with `dataType: objectarray` and no `generate` is
3676
+ the `rows [ ]` structure: the mapped record is an array — usually one element per element of the
3677
+ source array that root's `buildArrayHelper` iterates — Handlebars templates such as `http.body`
3678
+ bind it as `rows` instead of `record`, and the mapping editor shows that row's destination disabled.
3679
+ x-celigo-ai-guidance:
3680
+ - |-
3681
+ Rows that exist in the saved document — including `Draft` and `Inactive` rows and
3682
+ rows with only a source or only a destination — are the user's state: an edit that
3683
+ re-sends the tree must carry them through unchanged unless the user asked to change
3684
+ them. Only a row with neither source nor destination — and, for an object or
3685
+ object-array row, no remaining children — can be left out; the save would drop it
3686
+ anyway. A wrapper with children but no `generate` is kept by the save, so keep it.
3687
+ - |-
3688
+ A single unnamed top-level `objectarray` item is the `rows [ ]` JSON structure, not a
3689
+ missing destination: keep it unnamed when editing (naming it turns the output into an
3690
+ object, and a template that iterates `rows` then renders nothing), and author that
3691
+ shape only when the request body must be an array or a template iterates `rows`.
3692
+ The editor's save check accepts the unnamed root only in the `rows [ ]` structure;
3693
+ any other row with a source and no `generate` fails with "One or more destination
3694
+ field values not entered".
3695
+ items:
3696
+ type: object
3697
+ properties:
3698
+ generate:
3699
+ type: string
3700
+ description: |
3701
+ **Purpose**
3702
+ Defines the target field name in the output object/record.
3703
+
3704
+ **Guidance**
3705
+ This is the PRIMARY FIELD that identifies the output property being created:
3706
+
3707
+ - For regular fields: Set to the exact property name (e.g., "firstName", "price", "isActive")
3708
+ - For object fields: Set to the object property name, then add child mappings in the 'mappings' array
3709
+ - For array fields: Set to the array property name, then configure 'buildArrayHelper'
3710
+ - One structural blank: the single top-level `objectarray` item of a `rows [ ]` mapping (the
3711
+ array output structure — see the array's description). A child-bearing wrapper and a source-only row that
3712
+ already exist in a saved document also stay unnamed when the tree is re-sent — filling in a
3713
+ name changes the output; it does not complete the row
3714
+
3715
+ IMPORTANT: Do NOT use dot notation (e.g., "customer.firstName") in this field. Instead, create proper
3716
+ hierarchical structure with nested mappings:
3717
+ ```json
3718
+ {
3719
+ "generate": "customer",
3720
+ "dataType": "object",
3721
+ "status": "Active",
3722
+ "mappings": [
3723
+ {"generate": "firstName", "dataType": "string", "extract": "$.name.first", "status": "Active"}
3724
+ ]
3725
+ }
3726
+ ```
3727
+
3728
+ When parsing existing mappings, an empty `generate` on a row inside an `arrayarray` row's
3729
+ `buildArrayHelper` entry is that row's inner array (`arrayarray` fails at run time; see
3730
+ `dataType`); other unnamed rows are the wrappers and source-only rows described above; an
3731
+ empty `generate` on the ONLY top-level item, with `dataType: objectarray`, is the `rows [ ]` JSON
3732
+ structure — array output, bound as `rows` in templates — and is intentional, not a missing name.
3733
+ examples:
3734
+ - name
3735
+ - address
3736
+ - items
3737
+ dataType:
3738
+ type: string
3739
+ description: |
3740
+ **Purpose**
3741
+ Explicitly declares the data type of the output field, controlling how data is processed and structured.
3742
+
3743
+ **Guidance**
3744
+ This is a REQUIRED field that fundamentally determines mapping behavior:
3745
+
3746
+ **Simple Types (direct value mapping)**
3747
+ - `string`: Text values, converts other types to string representation
3748
+ - `number`: Numeric values. Converts a numeric string (`"24"` → `24`,
3749
+ `"007"` → `7`) and leaves the field out for an empty string; a value
3750
+ holding letters or a thousands separator (`"1,250.00"`) fails the
3751
+ record with `non_parsable_string` (`<generate>: String contains alpha
3752
+ characters`)
3753
+ - `boolean`: True/false values, converts truthy/falsy values
3754
+
3755
+ Dates are represented as strings — use `string` for date fields and
3756
+ drive the parsing/formatting through the `extractDateFormat` /
3757
+ `generateDateFormat` / `extractDateTimezone` / `generateDateTimezone`
3758
+ fields. There is no separate `date` enum value.
3759
+
3760
+ **Complex Types (require additional configuration)**
3761
+ - `object`: Creates a nested object from child mappings in the 'mappings' array, or
3762
+ copies a whole object with `extract` (one or the other, not both)
3763
+
3764
+ **Array Types**
3765
+ - `stringarray`: Array of strings
3766
+ - `numberarray`: Array of numbers
3767
+ - `booleanarray`: Array of booleans
3768
+ - `objectarray`: Array of objects (most common array type)
3769
+
3770
+ `arrayarray` is not a type the mapper recognizes: a save accepts it, but every record
3771
+ then fails with `Destination datatype is a required field.` Build an array of arrays
3772
+ in a script hook instead.
3773
+
3774
+ Array dataTypes are populated two ways: construct or iterate through
3775
+ `buildArrayHelper` entries, or set a constant with `hardCodedValue`. The
3776
+ row's own `extract` is never read on an array type: a primitive-array row
3777
+ that has only an `extract` (JSONPath, Handlebars or a literal) yields
3778
+ nothing, with no error, and an `objectarray` row without `buildArrayHelper`
3779
+ or `hardCodedValue` is refused with 422 ("buildArrayHelper" or
3780
+ "hardCodedValue" must be present for object array datatype.). To copy a
3781
+ source array through unchanged, use one entry that iterates it
3782
+ (`buildArrayHelper: [{"extract": "$.items[*]"}]`).
3783
+
3784
+ IMPORTANT: The dataType controls which additional fields are relevant:
3785
+ - For date-like string fields: extractDateFormat, generateDateFormat, etc. become relevant
3786
+ - For object types: 'mappings' array becomes relevant
3787
+ - For array types: `buildArrayHelper` or `hardCodedValue` (see above)
3788
+
3789
+ When analyzing existing mappings or generating new ones, always check dataType first
3790
+ to understand what additional fields should be present.
3791
+ x-celigo-ai-guidance:
3792
+ - |-
3793
+ Missing `dataType` is rejected at save with validation error
3794
+ `[mandatory_destination_datatype] Destination datatype is a
3795
+ required field.`
3796
+ - |-
3797
+ Give each row the type the destination field expects; `"string"` is
3798
+ not a safe default. It accepts any source value, but sends a numeric
3799
+ source as text (`"24"`), which a destination that checks JSON types
3800
+ refuses. Map numeric destination fields as `number`, which fails a
3801
+ record (`non_parsable_string`) only when the value holds letters or a
3802
+ thousands separator.
3803
+ enum:
3804
+ - string
3805
+ - number
3806
+ - boolean
3807
+ - object
3808
+ - stringarray
3809
+ - numberarray
3810
+ - booleanarray
3811
+ - objectarray
3812
+ x-enumDescriptions:
3813
+ string: Text values; converts other types to their string representation.
3814
+ number: Numeric values; converts numeric strings, and fails the record (`non_parsable_string`) on letters or a thousands separator.
3815
+ boolean: True/false values; converts truthy/falsy values.
3816
+ object: Nested object built from child `mappings`, or copied whole with `extract` (not both).
3817
+ stringarray: Array of string values.
3818
+ numberarray: Array of numeric values.
3819
+ booleanarray: Array of boolean values.
3820
+ objectarray: Array of objects, the most common array type.
3821
+ examples:
3822
+ - string
3823
+ - number
3824
+ - object
3825
+ - objectarray
3826
+ extract:
3827
+ type: string
3828
+ description: |
3829
+ **Purpose**
3830
+ Defines how to retrieve data from the input record to populate the output field.
3831
+
3832
+ **Guidance**
3833
+ This field supports THREE DISTINCT PATTERNS that are easily distinguished:
3834
+
3835
+ **1. json Path Syntax**
3836
+ - MUST start with '$' — the record root. An object record is addressed as
3837
+ '$.field'; a grouped (array) record as '$[0].field' / '$[*].field'
3838
+ - Used for precisely targeting data in structured JSON objects
3839
+ - Examples: '$.customer.firstName', '$.items[0].price', '$.addresses[*].street',
3840
+ '$[*].Tax' (every row of a grouped record)
3841
+ - Wildcards like [*] extract multiple values/objects
3842
+ - A key that contains a dot needs bracket notation: `$['P.O. Number']` (or
3843
+ `$["P.O. Number"]`, `$.[P.O. Number]`). `$.P.O. Number` is read as a nested
3844
+ path: it maps nothing and the record still succeeds. Spaces, hyphens and `#`
3845
+ need no brackets (`$.Ship To Name`, `$.Tracking #`)
3846
+ - Filter expressions such as `$.items[?(@.active)]` fail the record with
3847
+ "Eval [?(expr)] prevented in JSONPath expression."
3848
+
3849
+ ```json
3850
+ "extract": "$.customer.addresses[*]" // Extracts all addresses
3851
+ ```
3852
+
3853
+ **2. Handlebars Template Syntax**
3854
+ - Contains '{{' and '}}' pattern
3855
+ - Evaluated by the AFE 2.0 handlebars template engine
3856
+ - Can include logic, formatting, and computation
3857
+ - Access input record fields with {{record.fieldName}} notation; a grouped
3858
+ (array) record binds as `rows` instead — {{rows.0.fieldName}} / {{#each rows}}
3859
+ - Examples: "{{record.firstName}} {{record.lastName}}", "{{#if record.isActive}}Active{{else}}Inactive{{/if}}"
3860
+ - Valid on scalars and on `object` rows, where the rendered output must
3861
+ parse into an object. On an array row the template goes in a
3862
+ `buildArrayHelper` entry instead: on an `objectarray` row's own
3863
+ `extract` it is refused with 422 ("buildArrayHelper" or "hardCodedValue"
3864
+ must be present for object array datatype.), and on a primitive-array
3865
+ row's own `extract` it yields nothing (the field is left out) without an
3866
+ error
3867
+
3868
+ ```json
3869
+ "extract": "{{record.price}} {{record.currency}}" // Combines two fields
3870
+ ```
3871
+
3872
+ **3. Hard-Coded Value (literal string)**
3873
+ - Does NOT start with '$'
3874
+ - Does NOT contain handlebars '{{' syntax
3875
+ - System treats it as a literal string value
3876
+ - VERY COMMON for setting static/constant values
3877
+ - Examples: "Active", "USD", "Completed", "true"
3878
+
3879
+ ```json
3880
+ "extract": "primary" // Sets field value to the literal string "primary"
3881
+ "extract": "true" // Sets field value to the literal string "true"
3882
+ "extract": "N/A" // Sets field value to the literal string "N/A"
3883
+ ```
3884
+
3885
+ This third pattern is the simplest and most efficient way to set hard-coded values in your mappings.
3886
+ AI agents should use this pattern whenever a field needs a static value that doesn't come from
3887
+ the input record or require computation.
3888
+
3889
+ **Important implementation details**
3890
+
3891
+ - JSON path patterns ALWAYS execute from the TOP-LEVEL root of the input record
3892
+ - The system maintains this context even in deeply nested mappings
3893
+ - For object mappings without child mappings, extract should return a complete object
3894
+ - An `object` row takes `extract` (to copy a whole object) or child `mappings`, not
3895
+ both: a row with both fails with 422 (`"extract" should not be present if
3896
+ "mappings" field is present`). A `buildArrayHelper` entry is different: there
3897
+ `extract` and `mappings` work together.
3898
+ - The root is the record as it arrives: an object record roots at `$.field`; a
3899
+ grouped record (an array of rows — grouped exports, file key columns, NetSuite
3900
+ grouped saved searches) roots at the array, so its rows are addressed as
3901
+ `$[0].field` (one row) or `$[*].field` (every row). A root that contradicts the
3902
+ record's shape resolves to nothing without an error.
3903
+
3904
+ For most simple field-to-field mappings, prefer JSON path syntax for its clarity and performance.
3905
+ For hard-coded values, simply use the literal string as the extract value.
3906
+ x-celigo-ai-guidance:
3907
+ - |-
3908
+ ## GROUPED (ARRAY) RECORDS
3909
+ Decide the JSONPath root from the record's shape before writing
3910
+ any extract. When the record is an array of rows, `$.field`,
3911
+ `$.properties.field` and `$.rows[*].field` all resolve to
3912
+ nothing — the processor still reports success and the request
3913
+ body ships as `{}`. Address rows as `$[0].field` (that row's
3914
+ value, typed) or `$[*].field` (every row: joined with commas
3915
+ into a `string` destination; rejected with
3916
+ `incompatible_destination_conversion` into a `number`
3917
+ destination). Column labels with spaces work as
3918
+ `$[*][Order Number]`, `$[*].[Order Number]`, or
3919
+ `$[*]['Order Number']`. For one destination element per row
3920
+ the two array kinds take different helper forms: a primitive
3921
+ array (`stringarray` / `numberarray`) uses `buildArrayHelper:
3922
+ [{"extract": "$[*].field"}]`; an `objectarray` uses
3923
+ `buildArrayHelper: [{"extract": "$[*]", "mappings": [...]}]`
3924
+ with the children addressing the row relatively (`$.field`,
3925
+ `{{rows.field}}`). An `extract` placed directly on the
3926
+ array-typed field yields nothing. Handlebars
3927
+ extracts bind the array record as `rows` (`{{rows.0.field}}`),
3928
+ an object record as `record`. The reverse holds too: `$[*]` on
3929
+ an object record iterates the object's values, not rows.
3930
+ - |-
3931
+ ## SIZE LIMIT
3932
+ The platform's import save validator caps this field at **1024
3933
+ characters**. Saves with a longer `extract` are rejected
3934
+ with `[size_limit_exceeded] The maximum size of the field:
3935
+ mappings.<index>.extract in the Import document should be
3936
+ 1024 characters`. This typically only matters for
3937
+ Handlebars templates that build complex strings inline -- if
3938
+ a template is approaching the cap, prefer one of:
3939
+
3940
+ - **Decompose into nested mappings** (set `dataType:
3941
+ "object"` and use child `mappings` -- each child gets
3942
+ its own 1024-char budget).
3943
+ - **Move the logic to a `preMap` hook** so the heavy
3944
+ transformation runs in script and the mapping just reads
3945
+ `record.<computed>`.
3946
+ - **Use a lookup** (`lookupName` + a small `lookups` entry)
3947
+ for value translation that would otherwise need a long
3948
+ `{{#if ...}}{{else if ...}}` chain.
3949
+ examples:
3950
+ - $.fullName
3951
+ - '{{record.fullName}}'
3952
+ - primary
3953
+ - $.lineItems[*].unitPrice
3954
+ extractDateFormat:
3955
+ type: string
3956
+ description: |
3957
+ Specifies the format pattern of the input date string to ensure proper parsing.
3958
+
3959
+ Used on string-typed mappings whose `extract` yields a date. Uses
3960
+ Moment.js-compatible formatting tokens to describe how the incoming date
3961
+ string is structured.
3962
+ examples:
3963
+ - YYYY-MM-DD
3964
+ - MM/DD/YYYY
3965
+ - DD-MMM-YYYY HH:mm:ss
3966
+ extractDateTimezone:
3967
+ type: string
3968
+ description: |
3969
+ Specifies the timezone of the input date string using Olson/IANA timezone identifiers.
3970
+
3971
+ Used on string-typed mappings whose `extract` yields a date; tells the system
3972
+ how to interpret timestamp values from the input system.
3973
+ examples:
3974
+ - UTC
3975
+ - America/New_York
3976
+ - Europe/London
3977
+ generateDateFormat:
3978
+ type: string
3979
+ description: |
3980
+ Specifies the output format pattern when generating a date string or converting
3981
+ from a Date type to String type.
3982
+
3983
+ Uses Moment.js-compatible formatting tokens to define the structure of the resulting
3984
+ date string.
3985
+ examples:
3986
+ - YYYY-MM-DD
3987
+ - MM/DD/YYYY
3988
+ - DD-MMM-YYYY HH:mm:ss
3989
+ generateDateTimezone:
3990
+ type: string
3991
+ description: |
3992
+ Specifies the timezone to apply when generating or converting timestamp values
3993
+ using Olson/IANA timezone identifiers.
3994
+
3995
+ Controls timezone conversion when producing date output.
3996
+ examples:
3997
+ - UTC
3998
+ - America/New_York
3999
+ - Europe/London
4000
+ default:
4001
+ type:
4002
+ - string
4003
+ - 'null'
4004
+ description: |
4005
+ Specifies a fallback value to use when extract returns empty/null or when conditional
4006
+ logic fails and no other mapping supplies a value.
4007
+
4008
+ Explicit JSON `null` is itself a valid fallback: the destination field is written as
4009
+ JSON null when the extract yields nothing (the Mapper UI's "Use null as default value"
4010
+ action). Omitting the key entirely means no fallback — the field is left out of the
4011
+ output when the extract is missing or an empty string (the UI's "Do nothing" action),
4012
+ while a null source is still written as null unless `conditional.when` is
4013
+ `extract_not_empty`. Failing the record instead is `conditional.when:
4014
+ fail_record_when_empty`, which excludes a default.
4015
+ x-celigo-ai-guidance:
4016
+ - |-
4017
+ `"default": null` and `"default": ""` are distinct saved values, not
4018
+ absent keys: null renders the destination field as JSON null and the
4019
+ empty string renders it as `""` when the extract yields nothing.
4020
+ Preserve them verbatim when editing or migrating a mapping — dropping
4021
+ the key changes runtime behavior from "use null/empty string as
4022
+ default value" to "do nothing" (a missing or `""` source is left out
4023
+ of the output, while a null source is written as null unless
4024
+ `conditional.when` is `extract_not_empty`).
4025
+ - |-
4026
+ The four "Action to take if source field has no value" choices map to:
4027
+ do nothing → no `default` key (add `conditional.when:
4028
+ extract_not_empty` to leave a null source out too; without it a null
4029
+ source is written as null); use null → `"default": null`; use empty string or
4030
+ a custom value → `"default": "<value>"`; cause the record to fail →
4031
+ `conditional.when: fail_record_when_empty` with no `default` key.
4032
+ examples:
4033
+ - N/A
4034
+ - '0'
4035
+ - 'false'
4036
+ lookupName:
4037
+ type: string
4038
+ description: |
4039
+ **Purpose**
4040
+ References a lookup table for transforming values during the mapping process.
4041
+
4042
+ **Usage**
4043
+
4044
+ The lookupName refers to a named lookup defined in the lookups array of the same resource.
4045
+ On an HTTP import that is `http.lookups`: a `lookups` array sent only at the top level
4046
+ is dropped on save. On an import, a name that matches no lookup fails every record
4047
+ with "Unable to find lookup in mapping configs - <name>", and a key the lookup
4048
+ doesn't hold follows the lookup's `allowFailures`: false fails the record; true, or
4049
+ the field left out, lets the record succeed with the lookup's `default`, or without
4050
+ the mapped field when there is none.
4051
+
4052
+ ```json
4053
+ {
4054
+ "generate": "countryName",
4055
+ "dataType": "string",
4056
+ "extract": "$.countryCode",
4057
+ "lookupName": "countryCodeToName"
4058
+ }
4059
+ ```
4060
+
4061
+ During processing, the system:
4062
+ 1. Extracts the value from the input record (e.g., "US")
4063
+ 2. Finds the lookup table with the specified name
4064
+ 3. Uses the extracted value as a key in the lookup
4065
+ 4. Returns the corresponding value (e.g., "United States")
4066
+
4067
+ **Benefits**
4068
+
4069
+ - **Standardization**: Ensures consistent value translation across mappings
4070
+ - **Centralization**: Define translations once and reference them in multiple places
4071
+ - **Maintainability**: Update all mappings by changing the lookup definition
4072
+ - **Readability**: Makes mappings more descriptive and self-documenting
4073
+
4074
+ The specific lookup capabilities depend on the context where mappings are used.
4075
+ examples:
4076
+ - countryCodeToName
4077
+ - statusMapping
4078
+ - departmentCodes
4079
+ hardCodedValue:
4080
+ type:
4081
+ - string
4082
+ - 'null'
4083
+ description: |
4084
+ Constant written to the destination instead of an extracted value. On a primitive
4085
+ array (`stringarray`, `numberarray`, `booleanarray`) the string is split on commas,
4086
+ verbatim and untrimmed, into elements of the array's type (`"A,B"` gives `["A", "B"]`).
4087
+ On an `object` it must be a JSON object string and on an `objectarray` a JSON array
4088
+ string (an object string becomes one element); the save parses it and refuses non-JSON
4089
+ or the wrong shape with 422, and an array row with a constant needs no `buildArrayHelper`.
4090
+ JSON `null` writes the destination field as null; it is what the mapper saves for its
4091
+ hard-coded "Use null as default value" choice.
4092
+ examples:
4093
+ - USD
4094
+ - A,B
4095
+ - '[{"code": "A"}, {"code": "B"}]'
4096
+ description:
4097
+ type: string
4098
+ description: |
4099
+ Optional free-text annotation that appears in the Mapper sidebar to provide context about
4100
+ the mapping's purpose for collaboration and documentation.
4101
+
4102
+ Has no functional impact on the mapping behavior.
4103
+ examples:
4104
+ - Maps customer name
4105
+ - Converts price to target currency
4106
+ - Formats date for target system
4107
+ sourceDataType:
4108
+ type: string
4109
+ description: |
4110
+ Declares the JSON type of the value produced by `extract`, before any
4111
+ conversion to `dataType`. Same enum as `dataType`. Set on leaf mappings
4112
+ only — parent mappings (with child `mappings` or `buildArrayHelper`)
4113
+ have no extracted value of their own; the children carry their own
4114
+ `sourceDataType`.
4115
+
4116
+ For date fields use `string` (JSON represents dates as strings); the
4117
+ parsing/formatting lives in `extractDateFormat` / `generateDateFormat` /
4118
+ `extractDateTimezone` / `generateDateTimezone`.
4119
+ enum:
4120
+ - string
4121
+ - number
4122
+ - boolean
4123
+ - object
4124
+ - stringarray
4125
+ - numberarray
4126
+ - booleanarray
4127
+ - objectarray
4128
+ - arrayarray
4129
+ x-enumDescriptions:
4130
+ string: Source value is a text string.
4131
+ number: Source value is numeric.
4132
+ boolean: Source value is true or false.
4133
+ object: Source value is a JSON object.
4134
+ stringarray: Source value is an array of strings.
4135
+ numberarray: Source value is an array of numbers.
4136
+ booleanarray: Source value is an array of booleans.
4137
+ objectarray: Source value is an array of objects.
4138
+ arrayarray: Source value is an array of arrays.
4139
+ examples:
4140
+ - string
4141
+ - number
4142
+ - boolean
4143
+ - object
4144
+ mappings:
4145
+ type: array
4146
+ description: |
4147
+ **Purpose**
4148
+ Enables recursive definition of nested object structures through child mapping objects.
4149
+
4150
+ **Guidance**
4151
+ This is the KEY FIELD that implements the recursive pattern at the core of this schema:
4152
+
4153
+ **When to Use**
4154
+ - REQUIRED when dataType = "object" (unless you are copying an entire object from the input record)
4155
+ - REQUIRED in buildArrayHelper.mappings when defining complex object array elements
4156
+ - NEVER used with simple types (string, number, boolean)
4157
+
4158
+ **Behavior**
4159
+ - Each mapping in this array becomes a property of the parent object
4160
+ - The full Mappings schema is repeated recursively at each level
4161
+ - Can be nested to any depth for complex hierarchical structures
4162
+
4163
+ **Context Handling**
4164
+ - Each level of nesting changes the mapping CONTEXT for 'generate'
4165
+ - The extraction CONTEXT always remains the original input record
4166
+ - This means child mappings can pull data from anywhere in the input record
4167
+
4168
+ **Common Patterns**
4169
+
4170
+ **Nested Objects**
4171
+ ```json
4172
+ {
4173
+ "generate": "customer",
4174
+ "dataType": "object",
4175
+ "mappings": [
4176
+ {
4177
+ "generate": "contact",
4178
+ "dataType": "object",
4179
+ "mappings": [
4180
+ {"generate": "email", "dataType": "string", "extract": "$.customerEmail"}
4181
+ ]
4182
+ }
4183
+ ]
4184
+ }
4185
+ ```
4186
+
4187
+ **Multiple Fields in Object**
4188
+ ```json
4189
+ {
4190
+ "generate": "address",
4191
+ "dataType": "object",
4192
+ "mappings": [
4193
+ {"generate": "street", "dataType": "string", "extract": "$.address.line1"},
4194
+ {"generate": "city", "dataType": "string", "extract": "$.address.city"},
4195
+ {"generate": "country", "dataType": "string", "extract": "$.address.country"}
4196
+ ]
4197
+ }
4198
+ ```
4199
+
4200
+ IMPORTANT: When analyzing or generating mappings, ALWAYS check if parent.dataType = "object"
4201
+ or if you're inside buildArrayHelper.mappings for objectarray elements. These are the only
4202
+ valid contexts for the mappings array.
4203
+ items:
4204
+ $ref: '#/components/schemas/items'
4205
+ examples:
4206
+ - - generate: firstName
4207
+ extract: $.name.first
4208
+ dataType: string
4209
+ status: Active
4210
+ - generate: lastName
4211
+ extract: $.name.last
4212
+ dataType: string
4213
+ status: Active
4214
+ buildArrayHelper:
4215
+ type: array
4216
+ x-celigo-ai-guidance:
4217
+ - |-
4218
+ Entry-level `extract` accepts an iterating array path
4219
+ (`$.items[*]`), `"$"` (the record root), or omission — a
4220
+ constructed entry (child `mappings` with the extract omitted or
4221
+ `"$"`; the two spellings are equivalent) contributes exactly one
4222
+ element, and entries append in order. On a grouped (array)
4223
+ record the record itself is the array to iterate: `"$[*]"`
4224
+ yields one `objectarray` element per row (children address the
4225
+ row as `$.field`), and `"$[*].field"` yields one primitive-array
4226
+ value per row. Indexed or comma-joined
4227
+ entry extracts (`"$[0]"`, `"$[0],$[0]"`) are not valid: the
4228
+ processor renders the entire destination array as null with no
4229
+ validation error. To emit a fixed number of static elements, add
4230
+ that many sibling constructed entries — never index the extract.
4231
+ - |-
4232
+ An entry's `extract` can be a Handlebars template. On an
4233
+ `objectarray` it must render a JSON object (one element) or a JSON
4234
+ array (one element per item). On a primitive array each entry
4235
+ renders one element, so a serialized array becomes one string
4236
+ element. A bare literal entry extract is refused with 422 ("extract
4237
+ only supports json path or handlebars expression"); set a constant
4238
+ with the row's `hardCodedValue` instead.
4239
+ description: |
4240
+ **Purpose**
4241
+ Configures how to construct arrays in the output record, handling various array types and inputs.
4242
+
4243
+ **Guidance**
4244
+ This is the mechanism for building array data types:
4245
+
4246
+ **When to Use**
4247
+ - REQUIRED when dataType ends with "array" (stringarray, objectarray, etc.), unless the
4248
+ row sets `hardCodedValue`: an array row's own `extract` is never read (see `dataType`)
4249
+ - Each entry in this array contributes elements to the output array
4250
+ - Multiple entries allow combining data from different input arrays
4251
+
4252
+ **Array Type Handling**
4253
+
4254
+ **For Simple Arrays (stringarray, numberarray, booleanarray)**
4255
+ - Only the 'extract' field is used to pull values
4256
+ - JSON path with wildcards (e.g., $.items[*].name) returns multiple values;
4257
+ on a grouped (array) record the record itself is the array, so the
4258
+ path roots at it ($[*].name — one value per row)
4259
+ - Each result is converted to the appropriate primitive type
4260
+ ```json
4261
+ {
4262
+ "generate": "productNames",
4263
+ "dataType": "stringarray",
4264
+ "buildArrayHelper": [
4265
+ {"extract": "$.products[*].name"}
4266
+ ]
4267
+ }
4268
+ ```
4269
+
4270
+ **For Object Arrays (objectarray) - three patterns**
4271
+
4272
+ 1. Extract Only (existing objects):
4273
+ ```json
4274
+ {
4275
+ "generate": "contacts",
4276
+ "dataType": "objectarray",
4277
+ "buildArrayHelper": [
4278
+ {"extract": "$.account.primaryContacts[*]"}, // Pull primary contact objects
4279
+ {"extract": "$.account.secondaryContacts[*]"}, // Pull secondary contact objects
4280
+ {"extract": "$.vendor.contactPersons[*]"}, // Pull vendor contact objects
4281
+ {"extract": "$.subsidiaries[*].mainContact"} // Pull main contact from each subsidiary
4282
+ ]
4283
+ }
4284
+ ```
4285
+
4286
+ 2. Mappings Only (constructed object):
4287
+ ```json
4288
+ {
4289
+ "generate": "contactInfo",
4290
+ "dataType": "objectarray",
4291
+ "buildArrayHelper": [
4292
+ {
4293
+ "mappings": [ // Creates one object in the array
4294
+ {"generate": "type", "dataType": "string", "extract": "primary"},
4295
+ {"generate": "email", "dataType": "string", "extract": "$.primaryEmail"}
4296
+ ]
4297
+ },
4298
+ {
4299
+ "mappings": [ // Creates another object in the array
4300
+ {"generate": "type", "dataType": "string", "extract": "secondary"},
4301
+ {"generate": "email", "dataType": "string", "extract": "$.secondaryEmail"}
4302
+ ]
4303
+ }
4304
+ ]
4305
+ }
4306
+ ```
4307
+ Each constructed entry contributes exactly one element, in entry
4308
+ order; writing the entry with `"extract": "$"` is equivalent to
4309
+ omitting the extract (both anchor the element at the record root).
4310
+ A fixed number of static elements is built from that many sibling
4311
+ constructed entries.
4312
+
4313
+ 3. Extract AND Mappings (transform input arrays):
4314
+ ```json
4315
+ {
4316
+ "generate": "lineItems",
4317
+ "dataType": "objectarray",
4318
+ "buildArrayHelper": [
4319
+ {
4320
+ "extract": "$.order.items[*]", // For each item in the array
4321
+ "mappings": [ // Transform to this structure using the composite object
4322
+ {"generate": "sku", "dataType": "string", "extract": "$.order.items.productId"}, // Notice: items is singular
4323
+ {"generate": "quantity", "dataType": "number", "extract": "$.order.items.qty"}, // Notice: items is singular
4324
+ {"generate": "orderNumber", "dataType": "string", "extract": "$.order.id"}, // Access parent data
4325
+ {"generate": "customerName", "dataType": "string", "extract": "$.customerName"} // Access root data
4326
+ ]
4327
+ }
4328
+ ]
4329
+ }
4330
+ ```
4331
+
4332
+ **Arrays of Arrays**
4333
+ - The mapper has no working type for them: `arrayarray` saves, but every record
4334
+ fails with `Destination datatype is a required field.` Build an array of arrays
4335
+ in a script hook instead.
4336
+
4337
+ **Important details**
4338
+
4339
+ - When both extract and mappings are provided, the system creates special composite objects
4340
+ that maintain hierarchical context during processing
4341
+ - This enables accessing both the current array element AND its parent context
4342
+ - An ITERATING entry's extract MUST be a JSON path that iterates an array:
4343
+ '$.items[*]' when the array is a field of an object record, or '$[*]'
4344
+ (objectarray) / '$[*].field' (primitive arrays) when the record itself is a
4345
+ grouped array of rows. A CONSTRUCTED entry (child mappings building one
4346
+ element) instead omits extract or sets it to exactly "$" — never rewrite "$"
4347
+ into an indexed or comma-joined form ('$[0]', '$[0],$[0]'): those render the
4348
+ entire destination array as null without raising a validation error
4349
+ - Each array helper entry acts independently, potentially adding multiple elements
4350
+
4351
+ The buildArrayHelper is the most complex part of the mappings system - always analyze the
4352
+ dataType first to understand which pattern is appropriate.
4353
+ items:
4354
+ type: object
4355
+ properties:
4356
+ extract:
4357
+ type: string
4358
+ description: |
4359
+ JSON path expression that identifies the input array or values to extract.
4360
+
4361
+ For objectarray with mappings, this defines which input objects to iterate through.
4362
+ The JSON path must return either a single object or an array of objects.
4363
+
4364
+ For a CONSTRUCTED entry (child mappings building exactly one element from
4365
+ record-root fields and constants), omit this field or set it to exactly "$" —
4366
+ the two spellings are equivalent. Indexed or comma-joined forms ('$[0]',
4367
+ '$[0],$[0]') are not valid at the entry level: the processor renders the
4368
+ entire destination array as null without raising a validation error.
4369
+
4370
+ The system creates special composite objects during processing to maintain
4371
+ hierarchical relationships, allowing easy access to both the current array item
4372
+ and its parent contexts.
4373
+
4374
+ An iterating entry keeps the `[*]`: `$.line_items` without it yields one empty
4375
+ element per item, with no error. Child extracts drop the `[*]` but keep the
4376
+ array's path (`$.line_items.sku`); `$.line_items[*].sku` maps nothing, and an
4377
+ element-relative `$.sku` reads the record root instead of the element.
4378
+ examples:
4379
+ - $.items[*]
4380
+ - $.order.lineItems[*]
4381
+ - $.parents[*].children[*]
4382
+ - $
4383
+ name:
4384
+ type: string
4385
+ maxLength: 200
4386
+ description: |
4387
+ Display label for this source object in the mapper, so the sources of
4388
+ an object array can be told apart instead of all showing as `$`.
4389
+ Has no effect at runtime; stored only when non-empty.
4390
+ x-celigo-ai-guidance:
4391
+ - |-
4392
+ Carry an existing `name` through every edit — it is the user's label
4393
+ for the tab, and an entry sent without it loses the label. Duplicate
4394
+ names across entries are allowed. Set one only when the user names
4395
+ the source object; never invent labels.
4396
+ examples:
4397
+ - Billing address
4398
+ - Shipping address
4399
+ sourceDataType:
4400
+ type: string
4401
+ description: |
4402
+ Declares the JSON type of the input array being iterated, to ensure
4403
+ proper type handling during array construction. Same enum as `dataType`.
4404
+ enum:
4405
+ - string
4406
+ - number
4407
+ - boolean
4408
+ - object
4409
+ - stringarray
4410
+ - numberarray
4411
+ - booleanarray
4412
+ - objectarray
4413
+ - arrayarray
4414
+ x-enumDescriptions:
4415
+ string: Input array contains string elements.
4416
+ number: Input array contains numeric elements.
4417
+ boolean: Input array contains boolean elements.
4418
+ object: Input array contains object elements.
4419
+ stringarray: Input array contains arrays of strings.
4420
+ numberarray: Input array contains arrays of numbers.
4421
+ booleanarray: Input array contains arrays of booleans.
4422
+ objectarray: Input array contains arrays of objects.
4423
+ arrayarray: Input array contains arrays of arrays.
4424
+ examples:
4425
+ - string
4426
+ - number
4427
+ - boolean
4428
+ - object
4429
+ default:
4430
+ type:
4431
+ - string
4432
+ - 'null'
4433
+ description: |
4434
+ Specifies a fallback value when the extracted array element is empty or
4435
+ not found in the input data.
4436
+
4437
+ Explicit JSON `null` is itself a valid fallback (the element is written as
4438
+ JSON null); omitting the key means no fallback is applied.
4439
+ examples:
4440
+ - N/A
4441
+ - '0'
4442
+ - 'false'
4443
+ conditional:
4444
+ type: object
4445
+ description: |
4446
+ Defines conditional rules for including each array element in the result.
4447
+ x-celigo-ai-guidance:
4448
+ - |-
4449
+ Judged against this entry's own `extract` (the array source). The
4450
+ design scopes the UI's tab-level "Action to take if source field has
4451
+ no value" to copy-as-is tabs (no child `mappings`); the API accepts
4452
+ `fail_record_when_empty` on a mapped entry as well, and the mapper
4453
+ processor honors it there — the record fails when that array is
4454
+ missing or empty (`errors[]` entry `code: extract_empty`, `fatal:
4455
+ true`, message `<generate>: Source field has no value`; probed
4456
+ 2026-10-09). Say so when writing it on a mapped entry: the user may
4457
+ not find the setting in the mapper's tab. To fail on an empty field
4458
+ inside each element, set the action on that child mapping instead.
4459
+ properties:
4460
+ when:
4461
+ type: string
4462
+ description: |
4463
+ Condition judged on the entry's extract — skip the elements the
4464
+ extract does not return, or fail the whole record when the source
4465
+ array is missing or empty.
4466
+ enum:
4467
+ - extract_not_empty
4468
+ - fail_record_when_empty
4469
+ x-enumDescriptions:
4470
+ extract_not_empty: Include an array element only when the extract returns a non-empty value for it
4471
+ fail_record_when_empty: Fail the record when the entry's source array is missing or empty
4472
+ examples:
4473
+ - extract_not_empty
4474
+ mappings:
4475
+ type: array
4476
+ description: |
4477
+ Contains recursive mapping definitions for complex array element transformations.
4478
+
4479
+ **Composite object mechanism**
4480
+
4481
+ When both 'extract' and 'mappings' are used together, the system implements a sophisticated
4482
+ "composite object" approach that is crucial for AI agents to understand:
4483
+
4484
+ 1. The system starts with the complete input record
4485
+
4486
+ 2. For each array element matched by the extract path, it creates a modified version of
4487
+ the input record where:
4488
+ - Array paths in the extract JSON path are REPLACED with single objects
4489
+ - Each array ([]) in the path is converted to a single object ({})
4490
+ - This preserves the hierarchical relationship between nested arrays
4491
+
4492
+ **Example**
4493
+
4494
+ Given an input record:
4495
+ ```json
4496
+ {
4497
+ "customer": {
4498
+ "name": "John Doe",
4499
+ "orders": [
4500
+ {
4501
+ "id": "O-001",
4502
+ "items": [
4503
+ {"sku": "ABC", "qty": 2},
4504
+ {"sku": "XYZ", "qty": 1}
4505
+ ]
4506
+ },
4507
+ {
4508
+ "id": "O-002",
4509
+ "items": [
4510
+ {"sku": "DEF", "qty": 3}
4511
+ ]
4512
+ }
4513
+ ]
4514
+ }
4515
+ }
4516
+ ```
4517
+
4518
+ With extract path: `$.customer.orders[*].items[*]`
4519
+
4520
+ For each item, the system creates a composite object like:
4521
+ ```json
4522
+ {
4523
+ "customer": {
4524
+ "name": "John Doe",
4525
+ "orders": { // Note: Array replaced with single object
4526
+ "id": "O-001",
4527
+ "items": { // Note: Array replaced with single object
4528
+ "sku": "ABC",
4529
+ "qty": 2
4530
+ }
4531
+ }
4532
+ }
4533
+ }
4534
+ ```
4535
+
4536
+ Then in your mappings, you can access:
4537
+ - The current item: `$.customer.orders.items.sku`
4538
+ - The parent order: `$.customer.orders.id`
4539
+ - Top-level data: `$.customer.name`
4540
+
4541
+ This approach allows for precise mapping from deeply nested structures while maintaining
4542
+ access to all contextual parent data, without requiring complex array index management.
4543
+
4544
+ **Implementation guidance**
4545
+
4546
+ When implementing the composite object mechanism:
4547
+
4548
+ 1. Analyze the extract path to identify all array patterns (`[*]` or `[number]`)
4549
+ 2. For each array in the path, understand that it will be replaced with a single object
4550
+ 3. In the mappings, use paths that reference these arrays as if they were objects
4551
+ 4. Remember that every mapping still has access to the full input record context
4552
+ 5. This mechanism is especially powerful when mapping hierarchical data like:
4553
+ - Order → Line Items → Taxes/Discounts
4554
+ - Customer → Addresses → Address Lines
4555
+ - Invoice → Line Items → Serial Numbers
4556
+
4557
+ The extract path effectively tells the system "iterate through these arrays",
4558
+ while the composite object mechanism ensures you can still access both the
4559
+ current array item AND its parent context during mapping.
4560
+ items:
4561
+ $ref: '#/components/schemas/items'
4562
+ examples:
4563
+ - - generate: itemName
4564
+ extract: $.name
4565
+ dataType: string
4566
+ status: Active
4567
+ - generate: itemPrice
4568
+ extract: $.price
4569
+ dataType: number
4570
+ status: Active
4571
+ if:
4572
+ properties:
4573
+ conditional:
4574
+ properties:
4575
+ when:
4576
+ const: fail_record_when_empty
4577
+ required:
4578
+ - when
4579
+ required:
4580
+ - conditional
4581
+ then:
4582
+ not:
4583
+ required:
4584
+ - default
4585
+ status:
4586
+ type: string
4587
+ description: |
4588
+ **Purpose**
4589
+ Controls whether the mapping is applied. Send it on every mapping entry.
4590
+
4591
+ **Guidance**
4592
+ Only `Active` rows run. `Draft` and `Inactive` rows keep their
4593
+ configuration, are saved with minimal validation, and are skipped at
4594
+ runtime and in preview; a non-Active parent skips its whole subtree
4595
+ whatever its children say. Imports (on save and in the mapper processor)
4596
+ and API response mappings reject a row missing this field (validation
4597
+ error: "Mapping object must have status field present."); a Tool's
4598
+ output mapping saves and runs one, which is why `required` doesn't
4599
+ list it.
4600
+ x-celigo-ai-guidance:
4601
+ - |-
4602
+ Emit `"Active"` for mappings that should run; `"Draft"` is also
4603
+ accepted and saves the mapping while bypassing the Active-only
4604
+ field validations. The value is case-sensitive. The API rejects:
4605
+ - Missing field: `[status_field_absent] Mapping object must have status field present.`
4606
+ - Wrong case (e.g. `"active"`): `[invalid_status_enums] active is not a valid enum for status field.`
4607
+ - |-
4608
+ `"Inactive"` is the user's "Set inactive" on a row: use it only when
4609
+ asked to disable or park a row, never to mean incomplete (that is
4610
+ `"Draft"`). Setting a parent `Inactive` means no `Active` row may
4611
+ remain under it — the save rejects an `Active` row under an
4612
+ `Inactive` parent (`[inactive_parent_active_child]` on `mappings`,
4613
+ no message text) and never cascades or promotes on its own; `Draft`
4614
+ descendants are kept as they are, and a `Draft` parent does not gate
4615
+ its children. The UI's Set inactive on a parent marks the parent and
4616
+ every child `Inactive`. Re-enabling a child
4617
+ means re-enabling its ancestors in the same payload. Edits that keep
4618
+ existing rows must carry their stored status forward — rewriting a
4619
+ `Draft` or `Inactive` row to `Active` turns a row the user parked
4620
+ back on.
4621
+ enum:
4622
+ - Active
4623
+ - Draft
4624
+ - Inactive
4625
+ x-enumDescriptions:
4626
+ Active: The mapping is enabled and applied during processing
4627
+ Draft: In-progress mapping; saved without the Active-only field validations and skipped at runtime
4628
+ Inactive: Disabled by the user; configuration kept, skipped at runtime and in preview
4629
+ examples:
4630
+ - Active
4631
+ conditional:
4632
+ type: object
4633
+ description: |
4634
+ **Purpose**
4635
+ Defines conditional processing rules for the entire mapping.
4636
+
4637
+ **Guidance**
4638
+ These conditions determine whether the mapping is applied based on record
4639
+ state or field content:
4640
+
4641
+ **When to Use**
4642
+ - When a mapping should only be applied in specific circumstances
4643
+ - To implement conditional logic without using complex handlebars expressions
4644
+ - For creating mappings that only run during create or update operations
4645
+
4646
+ **Available Conditions**
4647
+
4648
+ - `record_created`: Apply only when creating a new record
4649
+ Useful for setting initial values that should not be overwritten during updates
4650
+
4651
+ - `record_updated`: Apply only when updating an existing record
4652
+ Useful for transformation logic that should only run during updates
4653
+
4654
+ - `extract_not_empty`: Apply only when the extract field returns a value
4655
+ Useful for conditional mapping based on input data availability
4656
+
4657
+ - `fail_record_when_empty`: Fail the record when the extract field returns
4658
+ no value (the UI's "Cause record to fail" action when the source field
4659
+ has no value)
4660
+
4661
+ **Example**
4662
+ ```json
4663
+ {
4664
+ "generate": "statusMessage",
4665
+ "dataType": "string",
4666
+ "status": "Active",
4667
+ "extract": "$.status.message",
4668
+ "conditional": {
4669
+ "when": "extract_not_empty" // Only map when status.message exists
4670
+ }
4671
+ }
4672
+ ```
4673
+ x-celigo-ai-guidance:
4674
+ - |-
4675
+ `when` holds one value, and two different settings share it: the
4676
+ composite-import operation gate (`record_created` / `record_updated`,
4677
+ the UI's "Only perform mapping when") and the empty-source action
4678
+ (`extract_not_empty` / `fail_record_when_empty`, the UI's "Action to
4679
+ take if source field has no value"). A row cannot carry both — writing
4680
+ one replaces the other and the save succeeds, so a composite import
4681
+ row that needs both has to choose. Never author `fail_record_when_empty`
4682
+ on a row that already carries `record_created` or `record_updated`.
4683
+ properties:
4684
+ when:
4685
+ type: string
4686
+ description: |
4687
+ Condition that gates this mapping — either an operation gate on a
4688
+ composite (create-or-update) import or the action to take when the
4689
+ extract returns no value. Empty means null, undefined or an empty
4690
+ string; `0`, `false` and whitespace are values.
4691
+ x-celigo-ai-guidance:
4692
+ - |-
4693
+ `fail_record_when_empty` is the fourth "Action to take if source field
4694
+ has no value" and is mutually exclusive with the other three: send it
4695
+ with no `default` key. A `default`, a `lookupName` or a `hardCodedValue`
4696
+ on the same row — or a `default` on a `buildArrayHelper` entry — is
4697
+ rejected at save with `[unsupported_mapping] "<key>" and conditional.when
4698
+ "fail_record_when_empty" cannot be present in mapping simultaneously.`
4699
+ (the lookup variant adds `Use lookup "allowFailures" instead.`);
4700
+ lookups fail through `allowFailures: false`, and a hard-coded row
4701
+ always has a value. At runtime an empty extract fails the record with
4702
+ an `errors[]` entry `{code: "extract_empty", fatal: true, source:
4703
+ "mapping", message: "<generate>: Source field has no value"}`
4704
+ ("Input field has no value" in a Transformation 2.0); `0` and `false`
4705
+ are values and map through.
4706
+ enum:
4707
+ - record_created
4708
+ - record_updated
4709
+ - extract_not_empty
4710
+ - fail_record_when_empty
4711
+ x-enumDescriptions:
4712
+ record_created: Apply this mapping only when creating a new record
4713
+ record_updated: Apply this mapping only when updating an existing record
4714
+ extract_not_empty: Apply this mapping only when the extract field returns a non-empty value
4715
+ fail_record_when_empty: Fail the record when the extract field returns no value
4716
+ examples:
4717
+ - record_created
4718
+ - record_updated
4719
+ - extract_not_empty
4720
+ - fail_record_when_empty
4721
+ required:
4722
+ - dataType
4723
+ if:
4724
+ properties:
4725
+ conditional:
4726
+ properties:
4727
+ when:
4728
+ const: fail_record_when_empty
4729
+ required:
4730
+ - when
4731
+ required:
4732
+ - conditional
4733
+ then:
4734
+ not:
4735
+ anyOf:
4736
+ - required:
4737
+ - default
4738
+ - required:
4739
+ - lookupName
4740
+ - required:
4741
+ - hardCodedValue
4742
+ Lookups:
4743
+ type: array
4744
+ description: |
4745
+ Configuration for value-to-value transformations using lookup tables.
4746
+
4747
+ **Purpose**
4748
+
4749
+ Lookups provide a way to translate values from one system to another. They transform
4750
+ input values into output values using either static mapping tables or
4751
+ dynamic lookup caches.
4752
+
4753
+ **Lookup mechanisms**
4754
+
4755
+ There are two distinct lookup mechanisms available:
4756
+
4757
+ 1. **Static Lookups**: Define a simple key-value map object and store it as part of your resource
4758
+ - Best for: Small, fixed sets of values that rarely change
4759
+ - Implementation: Configure the `map` object with input-to-output value mappings
4760
+ - Example: Country codes, status values, simple translations
4761
+
4762
+ 2. **Dynamic Lookups**: Reference an existing 'Lookup Cache' resource in your Celigo account
4763
+ - Best for: Large datasets, frequently changing values, or complex reference data
4764
+ - Implementation: Configure `_lookupCacheId` to reference cached data maintained independently
4765
+ - Example: Product catalogs, customer databases, pricing information
4766
+
4767
+ **Property usage**
4768
+
4769
+ There are two mutually exclusive ways to configure lookups, depending on which mechanism you choose:
4770
+
4771
+ 1. **For Static Mappings**: Configure the `map` property with a direct key-value object
4772
+ ```json
4773
+ "map": {"US": "United States", "CA": "Canada"}
4774
+ ```
4775
+
4776
+ 2. **For Dynamic Lookups**: Configure the following properties:
4777
+ - `_lookupCacheId`: Reference to the lookup cache resource
4778
+ - `extract`: JSON path to extract specific value from the returned lookup object
4779
+
4780
+ **When to use**
4781
+
4782
+ Lookups are ideal for:
4783
+
4784
+ 1. **Value Translation**: Mapping codes or IDs to human-readable values
4785
+
4786
+ 2. **Data Enrichment**: Adding related information to records during processing
4787
+
4788
+ 3. **Normalization**: Ensuring consistent formatting of values across systems
4789
+
4790
+ **Implementation details**
4791
+
4792
+ Lookups can be referenced in:
4793
+
4794
+ 1. **Field Mappings**: Direct use in field transformation configurations
4795
+
4796
+ 2. **Handlebars Templates**: Use within templates with the syntax:
4797
+ ```
4798
+ {{lookup 'lookupName' record.fieldName}}
4799
+ ```
4800
+
4801
+ **Example usage**
4802
+
4803
+ ```json
4804
+ "lookups": [
4805
+ {
4806
+ "name": "countryCodeToName",
4807
+ "map": {
4808
+ "US": "United States",
4809
+ "CA": "Canada",
4810
+ "UK": "United Kingdom"
4811
+ },
4812
+ "default": "Unknown Country",
4813
+ "allowFailures": true
4814
+ },
4815
+ {
4816
+ "name": "productDetails",
4817
+ "_lookupCacheId": "60a2c4e6f321d800129a1a3c",
4818
+ "extract": "$.details.price",
4819
+ "allowFailures": false
4820
+ }
4821
+ ]
4822
+ ```
4823
+ items:
4824
+ type: object
4825
+ properties:
4826
+ name:
4827
+ type: string
4828
+ description: |
4829
+ Unique identifier for the lookup table within this configuration.
4830
+
4831
+ This name must be unique within the scope where the lookup is defined and is used to reference
4832
+ the lookup in handlebars templates with the syntax {{lookup 'name' value}}.
4833
+
4834
+ Choose descriptive names that indicate the transformation purpose, such as:
4835
+ - "countryCodeToName" for country code to full name conversion
4836
+ - "statusMapping" for status code translations
4837
+ - "departmentCodes" for department code to name mapping
4838
+ examples:
4839
+ - countryCodeToName
4840
+ - statusMapping
4841
+ - departmentCodes
4842
+ map:
4843
+ type:
4844
+ - object
4845
+ - 'null'
4846
+ description: |
4847
+ The lookup mapping table as key-value pairs. The platform stores `null`
4848
+ here on dynamic lookups, which resolve values at runtime instead of
4849
+ from a static table.
4850
+
4851
+ This object contains the input values as keys and their corresponding
4852
+ output values. When a input value matches a key in this object,
4853
+ it will be replaced with the corresponding value.
4854
+
4855
+ The map should be kept to a reasonable size (typically under 100 entries)
4856
+ for optimal performance. For larger mapping requirements, consider using
4857
+ dynamic lookups instead.
4858
+
4859
+ Maps can include:
4860
+ - Simple code to name conversions: {"US": "United States"}
4861
+ - Status transformations: {"A": "Active", "I": "Inactive"}
4862
+ - ID to name mappings: {"100": "Marketing", "200": "Sales"}
4863
+
4864
+ Values can be strings, numbers, or booleans, but all are stored as strings
4865
+ in the configuration.
4866
+ examples:
4867
+ - US: United States
4868
+ UK: United Kingdom
4869
+ CA: Canada
4870
+ - A: Active
4871
+ I: Inactive
4872
+ P: Pending
4873
+ - 'true': 'Yes'
4874
+ 'false': 'No'
4875
+ _lookupCacheId:
4876
+ type: string
4877
+ description: |
4878
+ Reference to a LookupCache resource that contains the reference data for the lookup.
4879
+
4880
+ **Purpose**
4881
+
4882
+ This field connects the lookup to an external data source that has been cached in the system.
4883
+ Unlike static lookups that use the `map` property, dynamic lookups can reference large datasets
4884
+ or frequently changing information without requiring constant updates to the integration.
4885
+
4886
+ **Implementation details**
4887
+
4888
+ The LookupCache resource referenced by this ID contains:
4889
+ - The data records to be used as a reference source
4890
+ - Configuration for how the data should be indexed and accessed
4891
+ - Caching parameters to balance performance with data freshness
4892
+
4893
+ **Usage patterns**
4894
+
4895
+ Commonly used to reference:
4896
+ - Product catalogs or SKU databases
4897
+ - Customer or account information
4898
+ - Pricing tables or discount rules
4899
+ - Complex business logic lookup tables
4900
+
4901
+ Format: 24-character hexadecimal string (MongoDB ObjectId)
4902
+ format: objectid
4903
+ x-celigo-refModel: lookupcaches
4904
+ examples:
4905
+ - 60a2c4e6f321d800129a1a3c
4906
+ - 5f8d43a1b9e5a80011a35f2c
4907
+ extract:
4908
+ type: string
4909
+ description: |
4910
+ JSON path expression that extracts a specific value from the cached lookup object.
4911
+
4912
+ **Purpose**
4913
+
4914
+ When using dynamic lookups with a LookupCache, this JSON path identifies which field to extract
4915
+ from the cached object after it has been retrieved using the lookup key.
4916
+
4917
+ **Implementation details**
4918
+
4919
+ - Must use JSON path syntax (similar to mapping extract fields)
4920
+ - Operates on the cached object returned by the lookup operation
4921
+ - Examples:
4922
+ - "$.name" - Extract the name field from the top level
4923
+ - "$.details.price" - Extract a nested price field
4924
+ - "$.attributes[0].value" - Extract a value from the first element of an array
4925
+
4926
+ **Usage scenario**
4927
+
4928
+ When a lookup cache contains complex objects:
4929
+ ```json
4930
+ // Cache entry for key "PROD-123":
4931
+ {
4932
+ "id": "PROD-123",
4933
+ "name": "Premium Widget",
4934
+ "details": {
4935
+ "price": 99.99,
4936
+ "currency": "USD",
4937
+ "inStock": true
4938
+ }
4939
+ }
4940
+ ```
4941
+
4942
+ Setting extract to "$.details.price" would return 99.99 as the lookup result.
4943
+
4944
+ If no extract is provided, the entire cached object is returned as the lookup result.
4945
+ examples:
4946
+ - $.name
4947
+ - $.details.price
4948
+ - $.attributes.color
4949
+ - $.category.name
4950
+ default:
4951
+ type:
4952
+ - string
4953
+ - 'null'
4954
+ description: |
4955
+ Default value to use when the source value is not found in the lookup map.
4956
+ The platform stores `null` here when no default is configured.
4957
+
4958
+ This value is used as a fallback when:
4959
+ 1. The source value doesn't match any key in the map
4960
+ 2. allowFailures is true or omitted
4961
+
4962
+ Setting an appropriate default helps prevent flow failures due to unexpected
4963
+ values and provides predictable behavior for edge cases.
4964
+
4965
+ Common default patterns include:
4966
+ - Descriptive unknowns: "Unknown Country", "Unspecified Status"
4967
+ - Original value indicators: "{Original Value}", "No mapping found"
4968
+ - Neutral values: "Other", "N/A", "Miscellaneous"
4969
+
4970
+ A save refuses a default together with an explicit `allowFailures: false`
4971
+ (422 `Lookups with default set can not have allowFailures explicitly set to
4972
+ false.`): a lookup either fails a miss (`allowFailures: false`, no default) or
4973
+ falls back to its default.
4974
+ examples:
4975
+ - Unknown
4976
+ - Other
4977
+ - N/A
4978
+ - Unmapped Value
4979
+ - '{Original Value}'
4980
+ x-celigo-ai-guidance:
4981
+ - 'Omit this field entirely when no fallback value is intended: a miss the lookup lets through then leaves the mapped field out, and `allowFailures: false` (which a save refuses alongside a default) fails it. An empty string is a value, not "no default" — the save accepts `default: ""`, and an allowed miss writes `""`.'
4982
+ - A default sends every unmapped value with no error, so add the missing key to the map when the destination needs the real value; keys match the extracted value exactly (case, spacing and suffixes count), and a save replaces the whole map.
4983
+ allowFailures:
4984
+ type:
4985
+ - boolean
4986
+ - 'null'
4987
+ description: |
4988
+ When true, missing lookup values will use the default value rather than causing an error.
4989
+
4990
+ **Behavior control**
4991
+
4992
+ This field determines how the system handles source values that don't exist in the map:
4993
+
4994
+ - true: Use the default value for missing mappings and continue processing
4995
+ - false: Treat missing mappings as errors, failing the record (`lookup_error` for a
4996
+ static map, `lookupcache_evaluation_failed` for a lookup cache)
4997
+ - omitted or null: the record doesn't fail either. On an import a static lookup writes
4998
+ its default if it has one, and a static or cache lookup without one leaves the
4999
+ mapped field out of the output, with no error
5000
+
5001
+ **Recommendation**
5002
+
5003
+ Set this to true when:
5004
+ - New source values might appear over time
5005
+ - Data quality issues could introduce unexpected values
5006
+ - Processing should continue even with imperfect mapping
5007
+
5008
+ Set this to false when:
5009
+ - Complete data accuracy is critical
5010
+ - All possible source values are known and controlled
5011
+ - Missing mappings indicate serious data problems that should be addressed
5012
+
5013
+ A default raises no error: records that miss go out with the default value and
5014
+ nothing reports them. Use true only when that fallback is acceptable at the
5015
+ destination, and set false explicitly when a missing value must stop the record.
5016
+ examples:
5017
+ - true
5018
+ - false
5019
+ x-celigo-ai-guidance:
5020
+ - 'Never leave this field out to mean "fail on a miss": on an import, an omitted or null value lets a missing key through without an error (with the default, or without the mapped field when there is none). Only an explicit false fails the record.'
5021
+ Transform:
5022
+ type: object
5023
+ description: |
5024
+ Configuration for transforming data during processing operations. This object enables
5025
+ reshaping of records.
5026
+
5027
+ **Transformation capabilities**
5028
+
5029
+ Celigo's transformation engine offers powerful features for data manipulation:
5030
+ - Precise field mapping with JSONPath expressions
5031
+ - Support for any level of nested arrays
5032
+ - Formula-based field value generation
5033
+ - Dynamic references to flow and integration settings
5034
+
5035
+ **Implementation approaches**
5036
+
5037
+ There are two distinct transformation mechanisms available:
5038
+
5039
+ **Rule-Based Transformation (`type: "expression"`)**
5040
+ - **Best For**: Most transformation scenarios from simple to complex
5041
+ - **Capabilities**: Field mapping, formula calculations, lookups, nested data handling
5042
+ - **Advantages**: Visual configuration, no coding required, intuitive interface
5043
+ - **Configuration**: Define rules in the `expression` object
5044
+ - **Use When**: You have clear mapping requirements or need to reshape data structure
5045
+
5046
+ **Script-Based Transformation (`type: "script"`)**
5047
+ - **Best For**: Extremely complex logic or proprietary algorithms
5048
+ - **Capabilities**: Full programmatic control, custom processing, complex business rules
5049
+ - **Advantages**: Maximum flexibility, can implement any transformation logic
5050
+ - **Configuration**: Reference a script in the `script` object
5051
+ - **Use When**: Visual transformation tools aren't sufficient for your use case
2601
5052
  properties:
2602
- generate:
2603
- type: string
2604
- description: Record field the row writes.
2605
- examples:
2606
- - customerId
2607
- extract:
2608
- type: string
2609
- description: JSONPath into the request body that the value is read from.
2610
- examples:
2611
- - $.id
2612
- dataType:
5053
+ type:
2613
5054
  type: string
5055
+ description: |
5056
+ Determines which transformation mechanism to use. This choice affects which properties
5057
+ must be configured and how transformation logic is implemented.
5058
+
5059
+ **Available types**
5060
+
5061
+ **Rule-Based Transformation (`"expression"`)**
5062
+ - **Required Config**: The `expression` object with mapping definitions
5063
+ - **Behavior**: Applies declarative rules to reshape data
5064
+ - **Best For**: Most transformation scenarios from simple to complex
5065
+ - **Advantages**: Visual configuration, no coding required
5066
+
5067
+ **Script-Based Transformation (`"script"`)**
5068
+ - **Required Config**: The `script` object with _scriptId and function
5069
+ - **Behavior**: Executes custom JavaScript to transform data
5070
+ - **Best For**: Extremely complex logic or proprietary algorithms
5071
+ - **Advantages**: Maximum flexibility, can implement any logic
5072
+
5073
+ **Implementation guidance**
5074
+
5075
+ 1. For standard data transformations, use `"expression"`
5076
+ 2. For complex logic or specialized processing, use `"script"`
5077
+ 3. When selecting a type, you must configure the corresponding object:
5078
+ - `type: "expression"` requires the `expression` object
5079
+ - `type: "script"` requires the `script` object
2614
5080
  enum:
2615
- - string
2616
- - number
2617
- - boolean
2618
- - object
2619
- - stringarray
2620
- - numberarray
2621
- - booleanarray
2622
- - objectarray
5081
+ - expression
5082
+ - script
2623
5083
  x-enumDescriptions:
2624
- string: Single string value
2625
- number: Single numeric value
2626
- boolean: Single boolean value
2627
- object: Nested object value
2628
- stringarray: Array of strings
2629
- numberarray: Array of numbers
2630
- booleanarray: Array of booleans
2631
- objectarray: Array of objects
2632
- description: Data type the row writes.
2633
- examples:
2634
- - string
2635
- sourceDataType:
2636
- type: string
2637
- description: Data type of the extracted value.
2638
- examples:
2639
- - string
2640
- status:
2641
- type: string
2642
- description: Row status; `Active` rows run.
5084
+ expression: Rule-based transformation using declarative mapping definitions.
5085
+ script: Script-based transformation using custom JavaScript logic.
2643
5086
  examples:
2644
- - Active
2645
- mappings:
2646
- type: array
2647
- description: Child rows of an `object` row, with the same shape as this row.
2648
- items:
2649
- $ref: '#/components/schemas/items'
5087
+ - expression
5088
+ - script
5089
+ expression:
5090
+ type: object
5091
+ description: |
5092
+ Configuration for declarative rule-based transformations. This object enables reshaping data
5093
+ without requiring custom code.
5094
+
5095
+ **Usage context**
5096
+
5097
+ This object is REQUIRED when `transform.type` is set to "expression" and should not be
5098
+ configured otherwise. It provides a standardized way to define transformation rules that
5099
+ can map, modify, and generate data elements.
5100
+
5101
+ **Implementation guidance**
5102
+
5103
+ The expression system uses a rule-based approach where:
5104
+ - Field mappings define how input data is transformed to target fields
5105
+ - Formulas can be used to calculate or generate new values
5106
+ - Lookups can enrich data by fetching related information
5107
+ - Mode determines how records are processed (create new or modify existing)
5108
+ properties:
5109
+ version:
5110
+ type: string
5111
+ description: |
5112
+ Version of the expression format. Determines which rules
5113
+ property contains the transformation logic.
5114
+ enum:
5115
+ - '1'
5116
+ - '2'
5117
+ x-enumDescriptions:
5118
+ '1': Legacy format. Rules are in the `rules` array (array of arrays of extract/generate objects).
5119
+ '2': Current format. Rules are in the `rulesTwoDotZero` object with mode, mappings, and lookups.
5120
+ examples:
5121
+ - '1'
5122
+ - '2'
5123
+ rules:
5124
+ type: array
5125
+ description: |
5126
+ Transformation rules for version 1 expressions. An array of
5127
+ rule groups; each group is an array of field-mapping objects.
5128
+ Most transforms have a single group. Present when `version`
5129
+ is `"1"`. The output record contains ONLY the generated
5130
+ fields — every unmapped field is dropped (v1 has no
5131
+ equivalent of Transform 2.0's `modify` mode), and the
5132
+ record's trace key does not survive the rebuild.
5133
+ x-celigo-ai-guidance:
5134
+ - |-
5135
+ v1 rules REPLACE the record: a one-field rule group drops
5136
+ every other field, silently breaking downstream filters,
5137
+ router branch rules, and templates that referenced the
5138
+ dropped fields. Either map every field downstream logic
5139
+ needs forward, or author Transform 2.0 with
5140
+ ``mode: "modify"`` instead.
5141
+ - |-
5142
+ An import's ``responseTransform`` is the exception: it accepts
5143
+ version ``"1"`` only (``"2"`` is refused with 422, verified live
5144
+ 2026-10-21), so there, map every response field that response
5145
+ mapping needs.
5146
+ items:
5147
+ type: array
5148
+ items:
5149
+ type: object
5150
+ properties:
5151
+ extract:
5152
+ type: string
5153
+ description: |
5154
+ Source field path to read from. Supports multiple
5155
+ syntaxes: bare field names (`id`), dot notation
5156
+ (`fulfillment.shipment_id`), slash-prefixed paths
5157
+ for XML (`/FeedProcessingStatus`), wildcards (`*.id`,
5158
+ `*.[Internal ID]`), and array indexing (`SDF[0]`).
5159
+ generate:
5160
+ type: string
5161
+ description: |
5162
+ Target field name to write to. Typically a bare name
5163
+ (`id`) or dot path (`SDF.Filter.ID`).
5164
+ key:
5165
+ type: string
5166
+ description: |
5167
+ Auto-generated identifier for this rule, used by the
5168
+ UI to track individual rules for editing and reordering.
5169
+ required:
5170
+ - extract
5171
+ - generate
5172
+ rulesTwoDotZero:
5173
+ type: object
5174
+ description: |
5175
+ Configuration for version 2 transformation rules. This object contains the core logic
5176
+ for how data is mapped, enriched, and transformed.
5177
+
5178
+ **Capabilities**
5179
+
5180
+ Transformation 2.0 provides:
5181
+ - Precise field mapping with JSONPath expressions
5182
+ - Support for deeply nested data structures
5183
+ - Formula-based field generation
5184
+ - Dynamic lookups for data enrichment
5185
+ - Multiple operating modes to fit different scenarios
5186
+ properties:
5187
+ mode:
5188
+ type: string
5189
+ description: |
5190
+ Transformation mode that determines how records are handled during processing.
5191
+
5192
+ **Available modes**
5193
+
5194
+ **Create Mode (`"create"`)**
5195
+ - **Behavior**: Builds entirely new output records from inputs
5196
+ - **Use When**: Output structure differs significantly from input
5197
+ - **Advantage**: Clean slate approach, no field inheritance
5198
+
5199
+ **Modify Mode (`"modify"`)**
5200
+ - **Behavior**: Makes targeted edits to existing records
5201
+ - **Use When**: Output structure should remain similar to input
5202
+ - **Advantage**: Preserves unmapped fields from the original record
5203
+ enum:
5204
+ - create
5205
+ - modify
5206
+ x-enumDescriptions:
5207
+ create: Builds entirely new output records from inputs, ignoring unmapped fields.
5208
+ modify: Makes targeted edits to existing records, preserving unmapped fields.
5209
+ x-celigo-ai-guidance:
5210
+ - |-
5211
+ On a grouped record (the export groups rows, so the record is an
5212
+ array) only `create` can author output — build it from the rows with
5213
+ `$[0].field`, `$[*].field`, or a `buildArrayHelper` over `$[*]`.
5214
+ `modify` has no object to overlay onto an array: the record passes
5215
+ through untouched and the processor reports success. Either mode
5216
+ reshapes the inside of one record; neither changes how many records
5217
+ the page carries (that is the export's `preSavePage` hook) or whether
5218
+ the export groups at all (that is its grouping setting).
5219
+ examples:
5220
+ - create
5221
+ - modify
5222
+ mappings:
5223
+ $ref: '#/components/schemas/Mappings'
5224
+ lookups:
5225
+ allOf:
5226
+ - description: |
5227
+ Shared lookup tables used across all mappings defined in the transformation rules.
5228
+
5229
+ **Purpose**
5230
+
5231
+ Lookups provide centralized value translation that can be referenced from any mapping
5232
+ in your transformation configuration. They enable consistent translation of codes, IDs,
5233
+ and values between systems without duplicating translation logic.
5234
+
5235
+ **Usage in transformations**
5236
+
5237
+ Lookups are particularly valuable in transformations for:
5238
+
5239
+ - **Data Normalization**: Standardizing values from diverse source systems
5240
+ - **Code Translation**: Converting between different coding systems (e.g., status codes)
5241
+ - **Field Enrichment**: Adding descriptive values based on ID or code lookups
5242
+ - **Cross-Reference Resolution**: Mapping identifiers between integrated systems
5243
+
5244
+ **Implementation**
5245
+
5246
+ Lookups are defined once in this array and referenced by name in mappings:
5247
+
5248
+ ```json
5249
+ "lookups": [
5250
+ {
5251
+ "name": "statusMapping",
5252
+ "map": {
5253
+ "A": "Active",
5254
+ "I": "Inactive",
5255
+ "P": "Pending"
5256
+ },
5257
+ "default": "Unknown Status"
5258
+ }
5259
+ ]
5260
+ ```
5261
+
5262
+ Then referenced in mappings using the lookupName property:
5263
+
5264
+ ```json
5265
+ {
5266
+ "generate": "status",
5267
+ "dataType": "string",
5268
+ "extract": "$.statusCode",
5269
+ "lookupName": "statusMapping"
5270
+ }
5271
+ ```
5272
+
5273
+ The system automatically applies the lookup during transformation processing.
5274
+
5275
+ For complete details on lookup properties and behavior, see the Lookups schema.
5276
+ - $ref: '#/components/schemas/Lookups'
5277
+ inputContext:
5278
+ type: string
5279
+ enum:
5280
+ - record
5281
+ - envelope
5282
+ x-enumDescriptions:
5283
+ record: The transform processor evaluates `mappings[].extract` JSONPath against the flat record itself (`$.field`, no `record.` segment) — the default when absent.
5284
+ envelope: The transform processor evaluates JSONPath against the wrapped runtime envelope `{record, job, testMode, settings, headers, queryParams}` (file-provider steps also carry `fileMeta`) — record fields need the `record.` segment (`$.record.field`), while `headers` and `queryParams` sit beside `record` (`$.headers['X-Id']`, `$.queryParams.src`).
5285
+ description: |
5286
+ Controls the JSON shape the transformTwoDotZero processor
5287
+ evaluates `mappings[].extract` JSONPath values against at
5288
+ flow runtime. Applies only to Transform 2.0 (v2,
5289
+ `rulesTwoDotZero`); v1 transforms (the `rules` array on
5290
+ `transform.expression.rules`) and script-mode transforms
5291
+ ignore this field.
5292
+ x-celigo-ai-guidance:
5293
+ - |-
5294
+ ## Extract anchoring by mode
5295
+
5296
+ - `record` (default — absent / empty / undefined): the
5297
+ processor sees the FLAT record as its evaluation root.
5298
+ `mappings[].extract` JSONPath MUST anchor directly at
5299
+ `$` with NO `record.` segment — e.g. `"$.orderId"`,
5300
+ `"$.customer.email"`; PLACEHOLDER extracts use
5301
+ `"$.PLACEHOLDER_<field>"`.
5302
+ This is the dominant Celigo idiom and the right choice for new transforms.
5303
+ - `envelope`: the processor sees a wrapped object
5304
+ `{record: {...}, job, testMode, settings, headers,
5305
+ queryParams}` (plus `fileMeta` on file-provider steps).
5306
+ `mappings[].extract` JSONPath MUST include the
5307
+ `record.` segment for record fields — e.g.
5308
+ `"$.record.orderId"` — and reads `headers` and
5309
+ `queryParams` beside it (`$.headers['X-Id']`);
5310
+ PLACEHOLDER extracts use `"$.record.PLACEHOLDER_<field>"`.
5311
+ Pick this only when the transform was authored against
5312
+ the envelope shape on purpose.
5313
+ - |-
5314
+ Handlebars expressions inside `extract`
5315
+ (`{{record.field}}`, `{{dateFormat ... record.field}}`)
5316
+ ALWAYS reference the `record` root regardless of
5317
+ `inputContext` — only JSONPath anchoring flips.
5318
+ - |-
5319
+ In `envelope` mode the output is still a bare record: a
5320
+ `modify` transform returns the record with its mapped
5321
+ fields merged in (no `record` wrapper, no `job` or
5322
+ `settings` keys), and a `create` transform returns only
5323
+ the mapped fields.
5324
+ - |-
5325
+ Emit `inputContext` explicitly on new v2 transforms:
5326
+ unset is read as `record`, but stating it makes the
5327
+ extract-anchoring contract self-documenting and immune
5328
+ to a platform default change.
5329
+ - |-
5330
+ ## Allowed values
5331
+
5332
+ - ``record`` (default — emitted when the field is absent
5333
+ / empty / undefined): the transform processor sees
5334
+ the FLAT record itself as its evaluation root.
5335
+ ``mappings[].extract`` JSONPath values MUST anchor
5336
+ directly at ``$`` with NO ``record.`` segment — for
5337
+ example ``"$.orderId"`` or
5338
+ ``"$.customer.email"``. PLACEHOLDER extracts use
5339
+ ``"$.PLACEHOLDER_<field>"``. This is the dominant
5340
+ Celigo idiom and the right choice for new transforms.
5341
+
5342
+ - ``envelope``: the transform processor sees a wrapped
5343
+ object of the shape
5344
+ ``{record: {...}, job, testMode, settings, headers,
5345
+ queryParams}`` (plus ``fileMeta`` on file-provider
5346
+ steps; ``headers`` and ``queryParams`` sit beside
5347
+ ``record``) — the
5348
+ same runtime-context envelope Handlebars / SQL /
5349
+ GraphQL templates render against. ``mappings[].extract``
5350
+ JSONPath values for record fields MUST include the
5351
+ ``record.`` segment — for example ``"$.record.orderId"``
5352
+ or ``"$.record.customer.email"`` — while ``headers`` and
5353
+ ``queryParams`` are read beside it
5354
+ (``"$.headers['X-Id']"``). PLACEHOLDER extracts
5355
+ use ``"$.record.PLACEHOLDER_<field>"``. Pick this
5356
+ mode only when the export was authored against the
5357
+ envelope shape on purpose (typically because an
5358
+ upstream step intentionally feeds the wrapped
5359
+ runtime context through to the transform).
5360
+
5361
+ ## Handlebars expressions are NOT affected
5362
+
5363
+ Handlebars expressions inside ``extract``
5364
+ (``{{record.field}}``,
5365
+ ``{{dateFormat ... record.field}}``, etc.) ALWAYS
5366
+ reference the runtime context's ``record`` root
5367
+ regardless of ``inputContext`` — the Handlebars runtime
5368
+ always sees the wrapped envelope. Only JSONPath
5369
+ behavior flips with this field.
5370
+
5371
+ ## Agent guidance
5372
+
5373
+ Set this field explicitly on every new v2 transform
5374
+ the agent authors. Leaving it unset is interpreted as
5375
+ ``record`` by the platform, but emitting
5376
+ ``inputContext: record`` makes the contract
5377
+ self-documenting and prevents the transform from
5378
+ drifting into envelope mode if an upstream change ever
5379
+ changes the platform default. Read this value before
5380
+ writing ``mappings[].extract`` so the JSONPath form
5381
+ matches the runtime root.
5382
+ - |-
5383
+ ## fileMeta on file-provider steps
5384
+
5385
+ File-provider exports and lookups populate a
5386
+ ``fileMeta`` envelope key describing each record's
5387
+ source file: ``fileName``, ``fileSize``, and
5388
+ ``lastModifiedTime`` (epoch milliseconds). Reach it
5389
+ as ``$.fileMeta.<field>`` in envelope mode, or as
5390
+ ``{{fileMeta.<field>}}`` from a Handlebars extract in
5391
+ either mode. The keys are exactly these three —
5392
+ lowercase variants such as ``filesize`` or
5393
+ ``filename`` resolve empty. The standalone transform
5394
+ processor substitutes sample fileMeta values when the
5395
+ posted data lacks them, so a resolving editor render
5396
+ is not proof the step provides fileMeta — only
5397
+ file-provider steps populate it at flow runtime.
5398
+ examples:
5399
+ - record
5400
+ - envelope
5401
+ script:
5402
+ type: object
5403
+ description: |
5404
+ Configuration for programmable script-based transformations. This object enables complex, custom
5405
+ transformation logic beyond what expression-based transformations can provide.
5406
+
5407
+ **Usage context**
5408
+
5409
+ This object is REQUIRED when `transform.type` is set to "script" and should not be configured
5410
+ otherwise. It provides a way to execute custom JavaScript code to transform data according to
5411
+ specialized business rules or complex algorithms.
5412
+
5413
+ **Implementation approach**
5414
+
5415
+ Script-based transformation works by:
5416
+ 1. Executing the specified function from the referenced script
5417
+ 2. Passing input data to the function
5418
+ 3. Using the function's return value as the transformed output
5419
+
5420
+ **Common use cases**
5421
+
5422
+ Script transformation is ideal for:
5423
+ - Complex business logic that can't be expressed through mappings
5424
+ - Algorithmic transformations requiring computation
5425
+ - Dynamic transformations based on external factors
5426
+ - Legacy system data format compatibility
5427
+ - Multi-stage processing with intermediate steps
5428
+
5429
+ Only use script-based transformation when expression-based transformation is insufficient.
5430
+ Script transformation requires maintaining custom code, which adds complexity to the integration.
5431
+ properties:
5432
+ _scriptId:
5433
+ type: string
5434
+ description: |
5435
+ Reference to a predefined script resource containing the transformation logic.
5436
+
5437
+ The referenced script should contain the function specified in the
5438
+ 'function' property. It must be a script in this account: any other id fails the save
5439
+ with 422 ("Only a script owned by the user or a script shared by the Integration App can
5440
+ be used at transform.script._scriptId.").
5441
+ format: objectid
5442
+ x-celigo-refModel: scripts
5443
+ examples:
5444
+ - 60a2c4e6f321d800129a1a3c
5445
+ - 5f8d43a1b9e5a80011a35f2c
5446
+ function:
5447
+ type: string
5448
+ description: |
5449
+ Name of the function within the script to execute for transformation. This function
5450
+ must exist in the script referenced by _scriptId.
5451
+ examples:
5452
+ - transformData
5453
+ - convertRecord
5454
+ - applyMapping
2650
5455
  ApiRequest:
2651
5456
  type: object
2652
5457
  description: Request configuration for a builder-mode API endpoint.
@@ -2843,114 +5648,35 @@ components:
2843
5648
  its mockResponse or a placeholder). Can include body, headers, pathParams, and
2844
5649
  queryParams; only the body reaches the record the steps see.
2845
5650
  transform:
2846
- type: object
2847
5651
  description: |-
2848
- Optional transformation applied to the incoming request before processing. The
2849
- expression form (`type: "expression"` with Transformation 2.0 rules in `expression`)
2850
- saves and runs. In a test run its rules see only the request body, not `pathParams`,
2851
- `queryParams` or headers.
2852
- properties:
2853
- type:
2854
- type: string
2855
- description: Selects the transform form; `expression` runs the rules in `expression`.
2856
- examples:
2857
- - expression
2858
- expression:
2859
- type: object
2860
- description: Transformation 2.0 rules applied to the request body.
2861
- properties:
2862
- version:
2863
- type: string
2864
- description: Rule format; `"2"` selects the rules in `rulesTwoDotZero`.
2865
- examples:
2866
- - '2'
2867
- rulesTwoDotZero:
2868
- type: object
2869
- description: The rules applied to the request body.
2870
- properties:
2871
- mode:
2872
- type: string
2873
- enum:
2874
- - create
2875
- - modify
2876
- x-enumDescriptions:
2877
- create: Builds a new record from the mappings, dropping unmapped fields.
2878
- modify: Edits the incoming record, keeping unmapped fields.
2879
- description: How the mappings apply to the record; `modify` keeps the body's own fields beside the mapped ones.
2880
- examples:
2881
- - modify
2882
- mappings:
2883
- type: array
2884
- description: Mapper 2.0 rows that write fields onto the record.
2885
- items:
2886
- type: object
2887
- required:
2888
- - dataType
2889
- properties:
2890
- generate:
2891
- type: string
2892
- description: Record field the row writes.
2893
- examples:
2894
- - customerId
2895
- extract:
2896
- type: string
2897
- description: JSONPath into the request body that the value is read from.
2898
- examples:
2899
- - $.id
2900
- dataType:
2901
- type: string
2902
- enum:
2903
- - string
2904
- - number
2905
- - boolean
2906
- - object
2907
- - stringarray
2908
- - numberarray
2909
- - booleanarray
2910
- - objectarray
2911
- x-enumDescriptions:
2912
- string: Single string value
2913
- number: Single numeric value
2914
- boolean: Single boolean value
2915
- object: Nested object value
2916
- stringarray: Array of strings
2917
- numberarray: Array of numbers
2918
- booleanarray: Array of booleans
2919
- objectarray: Array of objects
2920
- description: Data type the row writes.
2921
- examples:
2922
- - string
2923
- sourceDataType:
2924
- type: string
2925
- description: Data type of the extracted value.
2926
- examples:
2927
- - string
2928
- status:
2929
- type: string
2930
- description: Row status; `Active` rows run.
2931
- examples:
2932
- - Active
2933
- mappings:
2934
- type: array
2935
- description: Child rows of an `object` row, with the same shape as this row.
2936
- items:
2937
- $ref: '#/components/schemas/items'
2938
- _scriptId:
2939
- type: string
2940
- format: objectId
2941
- x-celigo-refModel: scripts
2942
- description: Reference to a script for custom transformation logic.
2943
- examples:
2944
- - 689212a2c42d988978e27a11
2945
- function:
2946
- type: string
2947
- description: Function name in the script to execute.
2948
- examples:
2949
- - transformRequest
5652
+ Optional transformation applied to the incoming request before processing. It takes the
5653
+ same forms as an export's `transform`: Transformation 2.0 rules, legacy version 1 `rules`,
5654
+ or a `script`. In a test run the body is the only part of the request the rules see (under
5655
+ `record` when `inputContext` is `envelope`); `pathParams`, `queryParams` and headers are
5656
+ not passed to them.
5657
+ allOf:
5658
+ - $ref: '#/components/schemas/Transform'
2950
5659
  x-celigo-ai-guidance:
2951
5660
  - |-
2952
5661
  Transforms the request data before it is processed by routers or responses.
2953
5662
  Useful for normalizing data or extracting specific fields.
5663
+ - |-
5664
+ Put a script's id and function under `script` (`script._scriptId`, `script.function`).
5665
+ Sent at the top level of `transform` they are dropped without an error, and the API is
5666
+ saved with no transform at all.
5667
+ - |-
5668
+ In an API test run, an `envelope` input context holds only `job`, `lookupCacheOptions`,
5669
+ `record` (the request body), `settings` and `testMode`: no `pathParams`, and none of the
5670
+ `headers`, `queryParams` or `fileMeta` keys listed on `inputContext`. There
5671
+ `$.record.<field>` and `{{record.<field>}}` resolve while `$.pathParams`, `$.queryParams`
5672
+ and `$.headers` resolve to nothing even when the run's `mockRequest` carries them, so a
5673
+ test run cannot show whether rules that read request params or headers work; a real
5674
+ call's envelope was not probed.
5675
+ - |-
5676
+ On an API request transform, a `script._scriptId` that names no script fails the save
5677
+ with 422 `invalid_ref` and the message
5678
+ "<id> is not a valid builder.request.transform.script._scriptId", not the message
5679
+ quoted on `script._scriptId`. A script from another account was not probed on this path.
2954
5680
  required:
2955
5681
  - relativeURI
2956
5682
  - method
@@ -3460,10 +6186,14 @@ components:
3460
6186
  items:
3461
6187
  $ref: '#/components/schemas/items-2'
3462
6188
  hardCodedValue:
3463
- type: string
6189
+ type:
6190
+ - string
6191
+ - 'null'
3464
6192
  description: |-
3465
6193
  Static value written to the target field instead of extracting
3466
- from input data.
6194
+ from input data. JSON `null` writes the destination field as null;
6195
+ it is what the mapper saves for its hard-coded
6196
+ "Use null as default value" choice.
3467
6197
  x-celigo-ai-guidance:
3468
6198
  - |-
3469
6199
  The field name is exactly `hardCodedValue` (capital C). The
@@ -3775,10 +6505,14 @@ components:
3775
6505
  items:
3776
6506
  $ref: '#/components/schemas/items-2'
3777
6507
  hardCodedValue:
3778
- type: string
6508
+ type:
6509
+ - string
6510
+ - 'null'
3779
6511
  description: |-
3780
6512
  Static value written to the target field instead of extracting
3781
- from input data.
6513
+ from input data. JSON `null` writes the destination field as null;
6514
+ it is what the mapper saves for its hard-coded
6515
+ "Use null as default value" choice.
3782
6516
  x-celigo-ai-guidance:
3783
6517
  - |-
3784
6518
  The field name is exactly `hardCodedValue` (capital C). The