When to use this endpoint

Use Run Once after testing the source and selecting its map. It runs synchronously, including for Disabled sources; it is not a dry run.

Authentication and permissions

Use signed API-key authentication or a logged-in CRM session. API keys act as their owner; session requests use dispatcher CSRF protection when configured.

Requires a valid tenant account and View on pageImportsCustomersFtp plus Edit. Source IDs and counts are restricted to the authenticated account owner; client-supplied ownership cannot expand access.

The source owner must be active. Manual runs require Customer Add/Edit for each row and TeamAccess for edited customers/parents; scoped creates use the actor’s first department and reject missing department membership.

Parameters

ParameterTypeRequiredDescription
idPositive integer or decimal integer stringYesUse the source or tenant row ID returned by its list/table. Fractions, negative numbers, arrays and out-of-range integers are rejected. This is not the import run token.

Example request

$result = FM_api('ImportCustomersFtp_runOnce', ['id'=>'18']);

Example response

[
  "customers.csv",
  "Imported 1 new and 0 edited customers"
]

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": "permission denied"}The user lacks the required Imports page action.
{"error": "missing or invalid parameter: id"}A required row ID is missing or invalid.
{"error": "no such entry"}The requested owned source or tenant row does not exist.

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

Behaviour and edge cases

  • Manual runs also work for a Disabled source, and stamp last_import as an attempt marker even if processing fails. Cron selects enabled sources for active accounts; one failing source does not stop other scheduled sources. Runs/configuration changes are serialized by an account/source lock.
  • Lists sorted visible regular files and processes at most 100 files with a soft 40-second per-source budget; cron uses at most 100 sources with a soft 45-second loop budget. An in-progress transfer/parser is not interrupted at that budget.
  • Requires an existing customers map of heading → destination strings, including pipe-joined headings, literal: values and custom[Name]. The first worksheet contains a header row; blank rows are skipped. Missing/duplicate headings, invalid destinations or row values fail the file. Preview returns every sheet but import uses only the first.
  • Supported ordinary destinations: id, account_number, name, notes, email, industry, street_address1, street_address2, town, county, postcode, country, landline, mobile, contact_name, account_manager, type, latitude, longitude and parent. Customer name is required. Blank ordinary fields leave saved values unchanged; reference "0" means no supplied type/parent/account manager, while ordinary zero coordinates/account data are retained. Custom values replace the mapped custom-value object.
  • Type and parent resolve an unambiguous existing name; parents must be active and cannot create a parent cycle. Parent writes use the canonical parent_id. Account manager must be an active user; email, coordinate ranges and bounded text lengths are checked. Invalid rows roll back the entire current file, including customer and audit writes; the file remains remote.
  • Intentional historical duplicate-name rule: if any customer already has the mapped name, create a new customer even when the row supplies an existing ID. Otherwise a positive supplied ID edits an active customer; blank/0 ID creates. This rule has been confirmed and is preserved.
  • When both contractProgrammes and contractProgrammeImport account features are enabled, an existing customer marked contract_programme_source cannot be edited by this worker.
  • Each file commits its customers, audit and pending-cleanup signature together. Remote removal rechecks content/mtime/size against the imported signature. Failed cleanup retains the checkpoint; retrying the identical file performs cleanup without repeating customer writes. Changed files are retained if they change during reading/cleanup. Re-uploading a file after successful cleanup is a new import.
  • A bare message array reports each filename and counts, including cleanup-pending or follow-up warnings. A later-file error returns error, file and messages for earlier work. Connection/map failures return error objects. Global configuration and tenant data do not share one distributed transaction.

Side effects

  • Updates last_import even on a failed attempt; writes customer data, address-history snapshots, tenant audit and per-source cleanup checkpoints; invalidates customer caches and refreshes dependent Job parent caches after a parent move.
  • A real customer type transition on an update can queue its customer-target email triggers after commit, using the actual previous/current email. Failed mail/cache follow-ups return a saved warning; repeating writes is unsafe. New-customer type assignment does not send this transition mail.
  • Downloads bounded remote spreadsheets to private temporary files and removes those copies in all paths. Removes a remote file only after committed import and matching signature. No automatic archive or import-log rollback is provided.

See it in Fieldmotion

CRM1

In CRM1, open Settings > Imports > Customers FTP. Click Run Once and inspect ImportCustomersFtp_runOnce; the returned strings form the Log dialog.

CRM2

In CRM2, open Imports > Customers FTP. Click Run Once in the source row; the same synchronous message list is displayed.

Related endpoints