Schedule of Rates
Query the CRM1 Schedule of Rates table
/a/ScheduleOfRates_getDT
Return CRM1’s positional Schedule of Rates DataTables page with legacy filters and metadata columns.
When to use this endpoint
Use ScheduleOfRates_getDT only when reproducing CRM1’s Schedule of Rates table. CRM2 uses the named-field ScheduleOfRates_getDataTable contract.
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 |
|---|---|---|---|
draw | Integer string | Yes | DataTables counter copied to the response as an integer. |
start / length | Integer strings | Yes | SQL offset and page size. The endpoint does not reject zero or negative values before constructing SQL. |
order | Native DataTables value | Yes | Presence is required. order[0][column] maps 1=name, 2=code, 3=description, 4=cost; anything else sorts by code. Exact direction desc is descending; otherwise ascending. |
search[value] | String | No | Trimmed case-insensitive substring over name, code, and description, OR an exact integer-converted ID. |
fName / fCode / fDescription | String | No | Additional case-insensitive substring filters, AND-combined. |
fArchived | Integer string | No | Exact archive flag. Integer -1 means no archive filter. |
Example request
$page = FM_api('ScheduleOfRates_getDT', [
'draw' => 7,
'start' => 0,
'length' => 25,
'order' => [['column' => 1, 'dir' => 'asc']],
'fArchived' => 0,
'search' => ['value' => 'annual'],
]);
Example response
{
"draw": 7,
"recordsTotal": "24",
"recordsFiltered": "1",
"data": [[430001,"Annual service","AS-01","Annual preventative service",150,"{\"2\":145}","[[74,1]]","","[{\"user_id\":18,\"hours\":2,\"cost\":50}]","","[]","4000",20,"VAT",0,""]]
}
Each row has 16 fixed positions: id, name, code, description, cost, price_bands, stock_used, "", labour_used, "", asset_types, nominal, tax_rate, tax_type, archived, "". IDs/archive/cost are JSON numbers; most other database values remain strings.
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 or invalid parameter: draw"} | draw is absent. |
{"error":"missing or invalid parameter: length"} | length is absent. |
{"error":"missing or invalid parameter: order"} | order is absent. |
{"error":"missing or invalid parameter: start"} | start is absent. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
recordsTotalcounts every active and archived row;recordsFilteredapplies all search/filter clauses.- Nominal output prefers
meta.nominal_code, then legacymeta.nominal. Tax uses modernmeta.tax_rate/meta.tax_type. Malformed metadata can trigger warnings. - Empty placeholder columns are reserved for client-computed stock/labour totals and actions.
- There is no page-size maximum or deleted-row filter.
See it in Fieldmotion
CRM1
Open Stock → Schedule of Rates. Search, column filters, sorting, paging, and archive selection call this route.
CRM2
CRM2 does not call this route; it uses the mapped named-field table endpoint.
Related endpoints
ScheduleOfRates_getDataTableis CRM2’s named-field query.ScheduleOfRates_getExportDataserves CSV export.