Portal Community

When to Use

Row must exist: sheet/update only updates matching rows. If no row matches the LookupFilters, the operation completes with updatedRows: 0 — it does not create a new row. If you need insert-or-update behavior, use sheet/appendOrUpdate instead.

Configuration

FieldRequiredDescription
CredentialIdRequiredInteger ID referencing a stored Google credential in the BizFirst Credentials Manager.
SpreadsheetIdRequiredThe Google Sheets spreadsheet ID from the URL.
SheetNameRequiredExact name of the target tab. Case-sensitive.
LookupFiltersRequiredList of SheetFilterInfo objects that identify the row(s) to update. Same structure as sheet/get filters: Column, Operator, Value. All rows that match the filters will be updated.
CombineFiltersOptionalEnum: And | Or. Default And. How multiple LookupFilters are combined.
DataModeOptionalEnum: AutoMap | DefineBelow | Nothing. Default AutoMap. Controls how input data is mapped to sheet columns for the write.
ColumnMappingsOptionalRequired when DataMode = DefineBelow. List of ColumnMapping objects: Column (sheet header) and Value (expression or literal). Only the columns listed here are written — all other columns are untouched.
CellFormatOptionalEnum: UserEntered | Raw. Default UserEntered.
HeaderRowOptionalInteger. Default 1. Row number containing column headers.
FirstDataRowOptionalInteger. Default 2. First row containing data.

Validation Errors

Error CodeCause
VAL_MISSING_SPREADSHEET_IDSpreadsheetId is empty or whitespace.
VAL_MISSING_SHEET_NAMESheetName is empty or whitespace.
VAL_MISSING_LOOKUP_FILTERSLookupFilters is null or empty. Without filters, the node cannot identify which rows to update.
VAL_MISSING_COLUMN_MAPPINGSDataMode = DefineBelow but ColumnMappings is null or empty.
SHEET_NOT_FOUNDThe specified SheetName does not exist in the spreadsheet.

Output Fields

FieldTypeDescription
updatedRangestringA1 notation of the cells that were written. When multiple rows are updated, this is the full bounding range (e.g. "Employees!A10:H12").
updatedRowsintegerNumber of rows that matched the filters and were updated. 0 if no match was found.
spreadsheetIdstringEchoed spreadsheet ID.
sheetNamestringEchoed sheet/tab name.
statusstring"success".
resourcestringAlways "sheet".
operationstringAlways "update".

Sample Configuration

{
  "resource": "sheet",
  "operation": "update",
  "CredentialId": 12,
  "SpreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
  "SheetName": "Invoices",
  "LookupFilters": [
    { "Column": "InvoiceNumber", "Operator": "Equals", "Value": "{{ $json.invoiceNumber }}" }
  ],
  "CombineFilters": "And",
  "DataMode": "DefineBelow",
  "ColumnMappings": [
    { "Column": "Status",          "Value": "Paid" },
    { "Column": "PaidDate",        "Value": "{{ $json.paymentDate }}" },
    { "Column": "PaymentMethod",   "Value": "{{ $json.method }}" },
    { "Column": "AmountReceived",  "Value": "{{ $json.amountReceived }}" },
    { "Column": "TransactionRef",  "Value": "{{ $json.transactionId }}" }
  ],
  "CellFormat": "UserEntered",
  "HeaderRow": 1,
  "FirstDataRow": 2
}

Sample Output

{
  "updatedRange": "Invoices!A34:M34",
  "updatedRows": 1,
  "spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
  "sheetName": "Invoices",
  "status": "success",
  "resource": "sheet",
  "operation": "update"
}

Expression Reference

Assuming this node is named markPaid in the workflow:

ExpressionReturnsDescription
{{ $output.markPaid.updatedRows }}integerNumber of rows updated. Check for 0 to detect no-match scenarios.
{{ $output.markPaid.updatedRange }}stringA1 range of cells written.
{{ $output.markPaid.status }}string"success" on the success port.
{{ $output.markPaid.updatedRows == 0 }}booleanTrue if no matching row was found — use in IF node to handle the no-match case.

Node Policies & GuardRails

Workflow Examples

Example 1 — Invoice Payment Webhook Handler

// Trigger: Webhook from payment gateway (POST /webhooks/payment-received)
// Node 1 — sheet/update (markInvoicePaid)
{
  "resource": "sheet", "operation": "update",
  "CredentialId": 12,
  "SpreadsheetId": "{{ $env.FINANCE_SHEET_ID }}",
  "SheetName": "Invoices",
  "LookupFilters": [
    { "Column": "InvoiceNumber", "Operator": "Equals", "Value": "{{ $json.invoiceRef }}" }
  ],
  "DataMode": "DefineBelow",
  "ColumnMappings": [
    { "Column": "Status",    "Value": "Paid" },
    { "Column": "PaidDate",  "Value": "{{ $json.paidAt }}" },
    { "Column": "PaidAmount","Value": "{{ $json.amount }}" }
  ]
}

// Node 2 — IF: updatedRows == 0
//   True: Slack alert to finance@acme.com "Unknown invoice payment received: {{ $json.invoiceRef }}"
//   False: Continue to confirmation email

Example 2 — Approval Workflow — Mark Campaign Approved

// Trigger: Approval node output (manager approved campaign budget request)
// Node 1 — sheet/update (approveCampaign)
{
  "resource": "sheet", "operation": "update",
  "CredentialId": 15,
  "SpreadsheetId": "{{ $env.MARKETING_SHEET_ID }}",
  "SheetName": "Campaign Requests",
  "LookupFilters": [
    { "Column": "RequestId", "Operator": "Equals", "Value": "{{ $json.requestId }}" }
  ],
  "DataMode": "DefineBelow",
  "ColumnMappings": [
    { "Column": "Status",     "Value": "Approved" },
    { "Column": "ApprovedBy", "Value": "{{ $json.approverName }}" },
    { "Column": "ApprovedAt", "Value": "{{ $now | date('YYYY-MM-DD HH:mm') }}" },
    { "Column": "BudgetFinal","Value": "{{ $json.approvedBudget }}" }
  ]
}

Example 3 — Bulk Status Reset at Month End

// Update all rows where Status = "Pending Review" to "Archived" at month end
// Uses CombineFilters: And with a date filter
{
  "resource": "sheet", "operation": "update",
  "CredentialId": 12,
  "SpreadsheetId": "{{ $env.OPS_SHEET_ID }}",
  "SheetName": "Tasks",
  "LookupFilters": [
    { "Column": "Status",  "Operator": "Equals",    "Value": "Pending Review" },
    { "Column": "DueDate", "Operator": "LessThan",  "Value": "{{ $now | date('YYYY-MM-DD') }}" }
  ],
  "CombineFilters": "And",
  "DataMode": "DefineBelow",
  "ColumnMappings": [
    { "Column": "Status",     "Value": "Archived" },
    { "Column": "ArchivedAt", "Value": "{{ $now | date('YYYY-MM-DD') }}" }
  ]
}