ACTION_ID: merge_columns NAME: Merge Columns CATEGORY: Data Operations CREDITS: 0 Combine values from several upstream actions into one column, as an ordered list of formula slots. Each slot holds its own expression; they are evaluated in waterfall order so the first slot that produces a value wins. The standard way to coalesce the same field coming off two or three different providers into a single clean column. 1. INPUTS merge_columns (formula_waterfall, required) Merge Columns. Merge data from multiple actions into one. A structured object rather than a plain string — see §3 for the exact shape. 2. OUTPUTS merged_data (string) — Formatted data. The value from the first slot that resolved. Empty when every slot came back empty. 3. HOW TO CONFIGURE `merge_columns` takes the multi-formula waterfall object. Adding the action seeds two empty slots (`id` 1 and 2); add more by appending entries with the next `id`. Configure Action body (PATCH /api/v1/workflows/{workflow_id}/sheets/{sheet_id}/actions/{action_instance_id}): { "inputs": { "merge_columns": { "type": "multi_formula", "formula_type": "waterfall", "data_type": "string", "formula_waterfall": [ { "id": 1, "prompt": { "value": "" }, "formula": { "value": "{{person_enrich_using_apollo_01ab.work_email}}" } }, { "id": 2, "prompt": { "value": "" }, "formula": { "value": "{{person_enrich_using_people_data_labs_01cd.work_email}}" } } ] } } } Field-by-field: - type / formula_type / data_type Fixed envelope: `multi_formula`, `waterfall`, `string`. Send them as shown. - formula_waterfall The ordered slots. `id` sets the order, `formula.value` holds the expression for that slot. - prompt.value Leave as `""` for a plain coalesce. Each `formula.value` takes the same expression syntax as the `formula` action — a bare `{{ref}}` template or a JS expression. 4. KEY NOTES - ORDER IS PRIORITY. Slots run in `id` order and the first non-empty result wins, so put your most trusted source in slot 1. Reordering the array changes which provider's value lands in the column. - Costs nothing and runs locally — same evaluator family as `formula`, no provider call. Merging is always cheaper than re-enriching. - Output is always a `string`, whatever the slots return. Numeric operators on `run_if` and `filter` derive their type from the declared output type, so a numeric threshold against `merged_data` silently fails to fire. Return a string sentinel (`"yes"` / `"no"`) and gate with `is` — the same trap documented in action-detail/formula.txt §4. - Sending the field as a plain string does not work. It is the structured object above; a bare expression comes back as an `unknown_field` warning on Configure Action and the action runs unconfigured. - Every slot empty gives an empty `merged_data`, not an error. Gate downstream on it being non-empty rather than reading cell status. - For one value from one source, `formula` is the simpler action. Reach for merge_columns only when there are genuinely several candidate sources to fall through. 5. WHERE IT FITS IN A WORKFLOW Pattern: two or three enrichment actions writing the same logical field -> merge_columns (best source first) -> the consumer reads one clean column instead of branching on which provider hit. Useful straight after a fan-out where coverage differs per provider — one returns a title, another a phone, and the downstream step only wants whichever exists. 6. WHEN TO USE Use merge_columns when the same field arrives from multiple upstream actions with partial coverage and you want a single column carrying the best available value. 7. WHEN NOT TO USE One source, or real transformation logic -> action-detail/formula.txt You want the provider fallback done inside one action, with billing per attempt -> action-detail/person_work_email_waterfall.txt (and the other waterfall actions — they fall through providers natively rather than merging separate columns) You want to combine ROWS rather than columns -> action-detail/merge_employee_finder_structured_array.txt Last updated: 2026-08-13.