When to use this endpoint

Use after choosing a table form and mapping import columns to its zero-based field positions. It is the CSV-import workflow, not a table-form schema editor.

Use Job_tableRowAppend when rows are already in destination-column order; use Job_setTableCells for a small set of addressed cells.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. The handler performs no additional page or role-permission check.

Job and form IDs refer to the authenticated account. Cross-account writes occur only through the stored outsourcing relationship on the routes that explicitly mirror changes.

The dispatcher also applies account/user and IP restrictions. A CRM session carrying a CSRF token must supply it through X-FMCSRF or _csrf; missing/incorrect tokens can be rejected before this handler runs.

Parameters

ParameterTypeRequiredDescription
job_idInteger stringYesPositive physical job ID, not a mobile app ID.
table_idInteger stringYesPositive destination table-form ID; the handler does not check that this form exists or belongs to the job’s main form.
mapJSON array stringYesOne mapping per source column position, for example [{"from":"Description","to":"f0"}]. The source position is the mapping’s array index; from is not read. Entries without to are skipped; all f characters are removed from to before integer conversion.
rowsJSON array stringYesPositional source rows, for example [["Inspection","Passed"]]. Values are copied from each mapping’s source index, with earlier destination gaps filled with empty strings. No decoded-shape or size validation is performed.
replace_existingInteger stringNoDefaults to 0. Any nonzero integer clears the selected table before appending; other tables remain stored.

Example request

$result = FM_api('Job_addTableRow', [
	'job_id'=>'1042', 'table_id'=>'302',
	'map'=>json_encode([['from'=>'Description','to'=>'f0'], ['from'=>'Result','to'=>'f1']]),
	'rows'=>json_encode([['Inspection','Passed']]),
	'replace_existing'=>'0',
]);

Example response

{"ok":1}

Errors and unusual responses

ResponseCondition
{"error":"not logged in"}No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs.
{"error":"missing or invalid parameter: job_id"}Job ID is nonpositive.
{"error":"missing or invalid parameter: table_id"}Table ID is nonpositive.
{"error":"missing or invalid parameter: map"}map is absent.
{"error":"missing or invalid parameter: rows"}rows is absent.
{"error":"no such job exists"}No active job is read.
{"error":"Unable to save job"}The primary database save failed. Successful-save history and subsequent follow-ups are not run.
{"ok":1,"warning":"Job saved; follow-up incomplete. Inspect saved state before retrying.","warnings":["Job_updateCosts: Unable to save job"],"saved":1}The primary save succeeded, but a recalculation, asset rebuild, notification or outsourced mirror failed. warnings identifies the failed follow-up; any normal response fields remain present. A benign no-change result from a follow-up is not a failure. Read saved state before retrying.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • Normalizes missing or invalid stored table collections to an empty collection before adding rows. Unselected tables are preserved.
  • Default mode appends in request order and does not deduplicate. Replaying a successful import duplicates rows. Replace mode discards every existing row in the selected table.
  • Malformed mapping/row JSON can produce PHP warnings or runtime failures rather than a structured validation error. Supply valid arrays; an ok response does not establish that every source column was mapped.
  • Table answers are serialized with table IDs as top-level object keys. There are no paging, filtering, row-count or batch-size controls.

Side effects

  • Writes subform_values, last_edited and edited_uuid; invalidates the meetings cache. The primary write is checked before follow-ups.
  • Calls Job_updateCosts, which may enrich resource answers, update financial totals and invoke Job_updatePrices; follow-up failures are returned as saved-state warnings. This route adds no direct import history or asset-link rebuild and does not mirror outsourced answers.

See it in Fieldmotion

CRM1

Open a job’s Tables page and use Import. pageJobTables.js supplies the column map and batches rows; Append is the default and Replace Existing sends replace_existing only for the initial replacement batch. Filter Network for Job_addTableRow.

CRM2

Open the job Form and import a table in pageJobForm.js. The importer also exposes Append / Replace Existing and sends Job_addTableRow; inspect job_id, table_id, map, rows and the replacement flag.

Related endpoints