When to use this endpoint

Use ScheduleOfRate_createData for CRM2’s shared Schedule of Rates create form. It accepts the newer camel-case field map, including nested nominal, tax-type, and customer-price metadata.

Use ScheduleOfRates_add only for the older CRM1 payload and its account-code resolution rules.

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
name / code / descriptionStringNoStored verbatim; the helper does not trim, require, or deduplicate these fields.
costNumberNoBase customer price after floating-point conversion; defaults to the schema value when omitted.
stockUsedString or native arrayNoStored in stock_used. A native array is JSON-encoded; a string is stored without validating its JSON. CRM2 uses [[stockId, quantity], ...].
labourUsedString or native arrayNoStored in labour_used. CRM2 uses objects such as {"user_id":18,"hours":2,"cost":50}; legacy readers also accept two-item arrays.
assetTypesString or native arrayNoStored in asset_types; CRM callers use a JSON array of asset-type IDs.
priceBandsJSON string or native objectNoStored in the JSON column price_bands, normally as an object keyed by price-band ID. Blank becomes SQL null.
archivedInteger stringNoInteger-converted archive flag; the schema defaults to 0.
metaString or native objectNoComplete raw metadata value. Do not combine a replacement with nested metadata keys unless that interaction has been tested.
metaNominal / metaNominalID / metaNominalCode / metaTaxTypeID / metaCustomerCostsScalar or native valueNoValues written into meta.nominal, meta.nominal_id, meta.nominal_code, meta.tax_type_id, and meta.customerCosts. Account, tax, and customer IDs are not validated here.
taxTypeNative objectNoComposite CRM2 picker value. id maps to metaTaxTypeID and nominalID maps to metaNominalID. Supplying the explicit metadata keys is clearer for integrations.
lastEditedDatetime stringNoExplicit replacement. If omitted, current server time is stored automatically. Blank writes SQL null.

Example request

$created = FM_api('ScheduleOfRate_createData', [
	'name' => 'Annual service',
	'code' => 'AS-01',
	'cost' => 150,
	'stockUsed' => [[74, 1]],
	'labourUsed' => [[
		'user_id' => 18,
		'hours' => 2,
		'cost' => 50,
	]],
]);

Example response

{
  "ok": 1,
  "id": 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 or invalid parameters."}No writable mapped field was supplied.
Database errorA supplied JSON-column value is not valid for the tenant database.

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

Behaviour and edge cases

  • Unknown keys and id are ignored. At least one other mapped key must be accepted.
  • Native arrays/objects supplied to text fields are JSON-encoded by the shared helper; already-encoded strings are stored as received.
  • These endpoints store the base price in cost; they do not calculate a customer’s final price. Job/quote consumers can apply meta.customerCosts, the tenant setting sor-child-gets-parent-price, and the customer’s price band later.
  • There is no filtering or pagination because exactly one insert is attempted.

Side effects

  • Inserts a tenant schedule_of_rates row, advances the schedule_of_rates cache marker, and writes generic field-level history for accepted values.
  • Fires the tenant-configurable SOR_new event with the new rate ID. Any configured listeners run synchronously and can add integration-specific side effects.

See it in Fieldmotion

CRM1

CRM1 creates rates through ScheduleOfRates_add, not this mapped route.

CRM2

Open Stock → Schedule of Rates and create a rate. The shared display widget calls this route through its singular ScheduleOfRate API prefix.

Related endpoints