ACTION_ID: push_data_to_sheet NAME: Send data to a sheet CATEGORY: Floq Tools CREDITS: 0 Send data to a sheet. ⚠ READ FIRST — Push columns must key on "name" (the destination column) and they link at PATCH time — add the destination input BEFORE patching the push, then verify destination rows are not empty. 1. INPUTS choose_or_create_a_new_sheet (string, required) The destination sheet's UUID. Pass the workflow's own ID for the workflow's main sheet, or a child sheet's ID for a sub-sheet. Find IDs via List Workflows → Get Workflow Overview (`data.sheets[].sheet_id`). select_a_list (structured_array, optional) A reference to a structured_array output from an upstream action. Each item in the resolved list becomes one new row on the destination sheet. Omit to send a single row built from the current row's values. choose_columns_to_send_to (jsonArray, required) Column mapping: which value to write into each input column on the destination sheet. Each item is `{name, value}` — `name` matches an input column name on the destination sheet; `value` is what to send (a `{{ref}}` to an upstream variable, a literal, or — when `select_a_list` is set — a `structured_array_reference` like `{{..}}`). 2. OUTPUTS summary (string) — Summary. Placeholder: "Sent 5. Updated 4. Created 1.". created_rows (jsonArray) — Created Rows. updated_rows (jsonArray) — Updated Rows. parent (json) — Parent. 3. HOW TO CONFIGURE Single-row push (built from the current row's values): { "inputs": { "choose_or_create_a_new_sheet": "", "choose_columns_to_send_to": [ { "name": "linkedin_url", "value": "{{input.linkedin_url}}" }, { "name": "company_name", "value": "{{enrich_company_linkedin_profile_1.company_name}}" } ] } } Fan out a structured_array into one row per item: { "inputs": { "choose_or_create_a_new_sheet": "", "select_a_list": "{{get_employees_by_company_using_apollo_1.list_of_employees}}", "choose_columns_to_send_to": [ { "name": "first_name", "value": "{{get_employees_by_company_using_apollo_1.list_of_employees.first_name}}" }, { "name": "last_name", "value": "{{get_employees_by_company_using_apollo_1.list_of_employees.last_name}}" }, { "name": "linkedin_url", "value": "{{get_employees_by_company_using_apollo_1.list_of_employees.person_linkedin_url}}" } ] } } Field-by-field: - choose_or_create_a_new_sheet Destination sheet UUID. Pass the workflow's own ID for its main sheet. - select_a_list Optional. A reference to an upstream structured_array. Each item becomes one row on the destination sheet. - choose_columns_to_send_to Each `name` matches an input column on the destination sheet. The server resolves and links destination columns automatically — unmatched names come back as `unknown_field` warnings. 4. KEY NOTES - The destination sheet must already exist. Use Create Sheet (or use the parent workflow's main sheet) before configuring this action; this endpoint does not create sheets implicitly despite the field's display name. - `name` values in `choose_columns_to_send_to` must match input column names on the destination sheet — the server validates each one and surfaces mismatches as warnings on the Configure Action response. - COLUMN KEY MUST BE `name`. Each entry keys on `name` (the destination column): `{name, value}`. UI-created pushes sometimes read back as `{input_field, value}` — do NOT copy that shape. PATCHing with `input_field` returns 200 with NO warning but maps NOTHING: `created_rows` come back as `{undefined: value}` and the destination row inputs land empty `{}`. Always spot-check a destination row's inputs are populated after a run. Verified 2026-06-08. - LINKS AT PATCH TIME. A push column links its `name` to a destination input column at PATCH time. If you configure the push before that input column exists on the destination sheet, it links to `undefined` (silent — only an `unknown_field` warning) and the value never lands. Add the destination input column FIRST, then re-PATCH the push so it re-links. Verified 2026-06-08. - When `select_a_list` is set, every column reference under `value` should typically use the 3-segment `structured_array_reference` shape (`{{..}}`) so each row of the list contributes its own column values. Mixing list-scoped and row-scoped references is allowed; row-scoped values are repeated on every row the list expands into. - Without `select_a_list`, exactly one row is appended on the destination sheet, built from whatever `value`s resolve in the current row's context. - ⚠ Deleting a destination row and re-pushing the same upstream data does NOT auto-run the recreated row. push_data_to_sheet identifies destination rows by a stable key derived from the upstream row + list position, so a re-push lands on the same destination row_id and the destination sheet's `auto_run` does not re-trigger for it (it is treated as already-seen). The recreated row arrives in `row_status: pending` with empty cells. To execute it, call Run Rows on the destination sheet (POST .../sheets/{dest_sheet_id}/run) with the row_id explicitly. If you want a clean auto-run instead, change the upstream input (so the source row resolves to a different identity) rather than deleting and re-pushing. A plain re-push without deleting behaves the same way: the push reports `Updated: 1, Created: 0`, the destination row keeps its old `row_status: complete`, and its cells go STALE (the input column updates but downstream cells keep their previous outputs — auto_run does not re-fire). Verified 2026-06-08. - ⚠ A BULK RE-PUSH IS NOT A SAFE NO-OP — it updates matched rows AND CREATES rows for every list position that no longer matches. The key is upstream row + LIST POSITION, so if the upstream list's length or ordering has changed since the first push (a re-run finder returning more people, a re-derived structured array, a filter that used to gate items), the shifted positions have no counterpart and are appended as new rows. Measured live 2026-08-04: re-pushing 4 list pushes over 202 upstream rows updated the existing 1,457 destination rows in place AND appended 2,005 more. Re-pushing to correct an input column is legitimate (it is the only way to change a landed row's inputs — there is no row-update endpoint), but ALWAYS record the destination row count first and compare after, and re-run the destination chain yourself afterwards because the updated rows' cells are stale by the note above. Prefer targeting specific upstream `row_ids` over a whole-sheet re-push. - ⚠ `created_at` ON AN UPDATED ROW IS REWRITTEN to the time of the re-push, even though the row keeps its `row_id` and its cells. It therefore CANNOT be used to tell newly-appended rows from updated ones — after a re-push the whole destination sheet can share one timestamp. To identify genuinely new rows, look for rows whose cells have never run (every cell status null), not for recent timestamps. Verified 2026-08-04. 5. WHERE IT FITS IN A WORKFLOW Pattern: enrichment / scrape -> push_data_to_sheet -> downstream sheet workflow processes the new rows. Most common use case: an upstream action returns a `structured_array` (an employee finder, a Salesforce / HubSpot lookup, a parsed scrape) and you want to expand each item into its own row on another sheet for per-record enrichment or outreach. 6. WHEN TO USE Use push_data_to_sheet to expand a `structured_array` into rows on another Floqer sheet, or to copy the current row's values onto a sheet for downstream processing. 7. WHEN NOT TO USE Need to push to another Floq (sub-workflow), not a sheet -> action-detail/push_data_to_another_floqer_workflow.txt Last updated: 2026-06-08.