When to use this endpoint

Use ScheduleOfRates_import only through a validated spreadsheet-import workflow. It can update rates, create rates and price bands, translate stock/labour text, and resolve nominal/tax metadata.

Authentication and permissions

The request must authenticate with signed API-key fields or a logged-in CRM session. The handler calls the normal login guard but performs no additional page or role-permission check.

All reads and writes use the authenticated tenant. The CRM screens apply client-side Schedule of Rates permissions, but those controls are not repeated by this endpoint.

Parameters

ParameterTypeRequiredDescription
mapJSON arrayYesOne mapping object per input column. to can be id, name, code, description, cost/price, stock_used, labour_used, stock, labour, price_bands, nominal, tax_rate, tax_type, or customerCosts. Stock/labour mappings can contain translate.field as blank (raw) or human. Unknown destinations are ignored.
rowsJSON array of row arraysYesValues are matched to map by numeric position. A positive mapped ID selects update; zero/blank selects insert.

Example request

$result = FM_api('ScheduleOfRates_import', [
	'map' => json_encode([
		['from' => 'ID', 'to' => 'id'],
		['from' => 'Name', 'to' => 'name'],
		['from' => 'Price', 'to' => 'price'],
		['from' => 'Price Bands', 'to' => 'price_bands'],
	]),
	'rows' => json_encode([
		['', 'Annual service', '150', json_encode(['Standard' => 145])],
	]),
]);

Example response

{
  "ok": 1,
  "ids": [430001]
}

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 parameter: rows"}rows is absent.
{"error":"missing parameter: map"}map is absent.
{"error":"invalid parameter: rows"}Decoded rows is not an array.
{"error":"invalid parameter: map"}Decoded map is not an array.
{"error":"Incorrect raw format for stock column."}A raw stock value does not decode to a truthy JSON value; notably an empty [] is rejected.
{"error":"invalid price band name: empty|too long","row":N,"price_band":"..."}A nonnumeric price-band object key is blank or exceeds 64 bytes.
{"error":"failed to create price band","name":"..."}A missing named price band could not be inserted.

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

Behaviour and edge cases

  • price maps to the database cost. Direct cost/price values are floating-point converted.
  • A price_bands JSON object accepts numeric IDs or case-insensitive names as keys. Missing names are created. Values become floats. JSON lists and non-JSON text are stored unchanged; null writes SQL null.
  • Human stock text is split on comma-space into name x quantity; an unknown name becomes stock ID 0. Human labour text extracts hours from a trailing x N hours and cost from text before the first slash; no user ID is retained.
  • customerCosts is comma-separated customer name - rate text. En dashes are normalized, names are exact and unescaped in the legacy query, unknown customers are dropped, and names containing hyphens are parsed incorrectly.
  • Nominal/tax mappings compare nominal codes case-insensitively, match tax category by name or rate, and use the tenant account/category relationship to populate IDs. Imported raw display values remain in metadata even when no relationship resolves.
  • asset_types, stock_cost, and labour_cost offered by the UI mapping list are not handled by this endpoint and are silently ignored.
  • An unknown positive update ID can still be returned in ids even though no rate row changed. Inserts do not require a name.

Side effects

  • Every processed row advances the scheduleOfRates cache marker and fires SOR_edit, including newly inserted rows; imports do not fire SOR_new.
  • Missing named price bands are inserted with current Unix timestamps and advance the price_bands cache marker.

See it in Fieldmotion

CRM1

The Schedule of Rates Import action maps spreadsheet columns and calls this endpoint.

CRM2

CRM2 exposes the same importer, including ID, price, price-band, stock, labour, nominal, tax, and customer-rate destinations.

Related endpoints