Quotes: queries, documents and delivery
Export quote header fields
/a/Quotes_getExportData
Select quote IDs, then fetch positional header/form values for a CSV export.
When to use this endpoint
Use for quote-level exports. fields controls response columns, while the first phase chooses IDs using its own filter vocabulary.
Authentication and permissions
Authenticate with signed API-key fields or a CRM session. Requires Quotes View (pageQuotes_view); non-admin users blocked by legacy crm_access bit 32 are denied. Client administrators inherit page permissions.
Quote visibility follows the account’s department/account-manager customer filters for non-admin users, including signed keys. Export routes additionally require pageMain_exportTableData. Linked Jobs require Jobs View and their TeamAccess scope; invoice enrichment requires Invoices View and the legacy invoice access check.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
_ids | String: 1 or JSON-encoded ID array | Yes | Literal 1 starts selection and returns integer IDs. Otherwise submit a nonempty encoded ID array to fetch rows; entries integer-convert. An empty list fails. No server checkpoint is stored. |
fields | JSON-encoded ordered array of field names | Fetch phase | Requested positions become f0, f1, etc. Unknown names fail. Native fields arrays are not JSON-decoded by these exporters. |
from / to | Date strings | No; selection only | Independent inclusive cdate bounds; to appends 23:59:59. No calendar validation. |
quote_id / quote_num | String patterns | No; selection only | Contains-style ID/reference LIKE matches, not exact quote_id equality. Wildcards retain SQL LIKE meaning. |
form_id / contract_id / user_id | Integer-compatible IDs | No; selection only | Truthy exact filters after conversion. |
customer / notes / search | String patterns | No; selection only | Customer/name, quote notes, and global ID/reference/customer search respectively; individual exporter differences are described below. |
status | Integer-compatible value or 999 | No; selection only | Omitted/blank or 999 means all statuses. Otherwise filters by integer status; no enum allowlist. |
marketingSource / metaEmailSent | Native integer lists | No; selection only | Nonempty arrays add integer IN filters; malformed entries return an invalid-list error naming the field. A one-choice 0 email filter is exact zero and does not include missing metadata like the mapped table does. |
metaTags | String pattern | No; selection only | Case-folded contains on meta.tags; interpolation is not safely bound in this legacy branch. |
referenceDateField / dateFromFilter / dateToFilter / isDateUnix | Date alias, relative day offsets and flag | No; selection only | Allowed cdate/last_edited/won_date and inclusive relative day bounds. Quote date columns are not Unix timestamps; nonzero isDateUnix is rejected. |
Example request
$selection = json_decode(FM_api('Quotes_getExportData', ['_ids'=>'1','status'=>'999']), true);
$rows = FM_api('Quotes_getExportData', [
'_ids'=>json_encode($selection['ids']),
'fields'=>json_encode(['id','quote_num','total_gross']),
]);
Example response
[{"quote_id":"1042","f0":"1042","f1":"QT-1042","f2":"120.00"}]
Selection example: {"ids":[1042,1088]}. Check selection errors and skip fetch when ids is empty; an encoded empty list is an error. The Getting Started FM_api helper returns raw JSON text, so decode the selection before reading its ids.
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: _ids"} | _ids omitted/null. |
{"error":"_ids should be a JSON array of numbers"} | Fetch selector is empty, invalid JSON or not an array. |
{"error":"fields should be an array of requested field names"} | Missing/empty/invalid encoded fields. |
{"error":"invalid referenceDateField: \"example\""} | Relative-date filter uses an unsupported field name. |
{"error":"permission denied"} | Required Quotes/Export permission is absent or legacy access restrictions apply. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Requires Quotes View and the Export permission; both selection and fetch enforce active quote/customer visibility. _ids and fields must be encoded nonempty lists in fetch mode; malformed structures fail before SQL.
- Selection _ids=1 returns integer IDs using numeric-coerced quote reference ordering. Fetch still uses f0/f1/etc positions and quote_id, ignores selection filters and does not preserve caller ordering. Callers chunk requests; there is no server snapshot.
- Date bounds and supported relative-date aliases are validated. Quote date fields reject isDateUnix rather than applying Unix conversion to stored date columns. Tags filters are safely escaped, actual tag newlines flatten to commas, and sale-chance date is unquoted before date formatting.
- profit_margin uses profit divided by adjusted net (total_gross minus total_tax), consistent with discounts and markup; a zero denominator yields null. profit_pc remains profit/cost*100.
- quote_costs remains encoded JSON with current Stock/SoR names. rows_names and rows_codes are supported derived aliases. Form answer selections keep FORM_ID:FIELD_KEY position mapping and omit absent answers.
- The legacy appointment_id export field still selects the newest active linked Job. invoice_id is reached through that Job; these are not all-links exports. No write, recalculation or email.
- No direct caller for this endpoint was found in the mobile app or its m-service intermediary.
Side effects
- Reads active permitted records without quote cost, history, email or derived Job-cache writes.
See it in Fieldmotion
CRM1
Quotes → Export uses Quotes_getExportData through widgetExport; inspect the initial ID request followed by encoded _ids/fields batches.
CRM2
Quotes → Export first asks Quotes_getDataTable for filtered IDs, then widgetExportCRM2 sends explicit ID batches to Quotes_getExportData. Its initial selection phase can therefore differ from the table filters.
Related endpoints
Quotes_getDataTablecan supply CRM2’s matching ID set.Quotes_getLineItemsExportDataexpands one row per cost item.