Schedule of Rates
Import Schedule of Rates data
/a/ScheduleOfRates_import
Import mapped Schedule of Rates rows, updating rows with IDs and inserting rows without IDs.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
map | JSON array | Yes | One 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. |
rows | JSON array of row arrays | Yes | Values 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
| Response | Condition |
|---|---|
{"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
pricemaps to the databasecost. Directcost/pricevalues are floating-point converted.- A
price_bandsJSON 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 SQLnull. - Human stock text is split on comma-space into
name x quantity; an unknown name becomes stock ID0. Human labour text extracts hours from a trailingx N hoursand cost from text before the first slash; no user ID is retained. customerCostsis comma-separatedcustomer name - ratetext. 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, andlabour_costoffered 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
idseven though no rate row changed. Inserts do not require a name.
Side effects
- Every processed row advances the
scheduleOfRatescache marker and firesSOR_edit, including newly inserted rows; imports do not fireSOR_new. - Missing named price bands are inserted with current Unix timestamps and advance the
price_bandscache 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
ScheduleOfRates_getExportDataproduces the export-side field format.ScheduleOfRate_createDataprovides a safer one-row mapped insert.