Data API
The Data API provides methods to create, read, update, and delete records on Facilio modules. All actions respect the current user's permissions.
Error handling
Async methods may reject with an error, or return an error object in the response (e.g., { code, error, ... }). Handle both: use try/catch for rejections and check response.error for in-response errors.
Module key in responses
The record (or count) is returned under a key that matches the module link name you pass. Examples: createRecord('workorder', ...) → response.workorder; fetchRecord('vendors', ...) → response.vendors. For dynamic access, use response[moduleName].
| Method | Description |
|---|---|
| createRecord | Create a new record |
| updateRecord | Update an existing record by ID |
| fetchRecord | Fetch a single record by ID |
| fetchAll | Fetch a list of records with filters and pagination |
| deleteRecord | Delete a record by ID |
| uploadFile | Upload a file and get a file ID for use in File/Signature fields |
Review Field types for value formats and Filters for query syntax before using these methods.
Field types and value formats#
Use the correct format for each field type when creating or updating records.
| Field Type | Format | Example |
|---|---|---|
| String | Plain string | "Chiller maintenance" |
| Number | Number | 234 |
| Decimal | Decimal number | 23423.34 |
| Currency | Number + currencyCode + exchangeRate | "currency_workorder": 23423, "currencyCode": "AED", "exchangeRate": 2 |
| Boolean | true or false | false |
| Date / DateTime | Milliseconds since epoch | new Date('2025-03-15').getTime() or Date.now() |
| Lookup | Object with id | { id: 54 } |
| Multi-select Lookup | Array of { id } objects | [{ id: 10700 }, { id: 10701 }] |
| Picklist | Object with id | { id: 955 } |
| Enum | String value | "urgent" |
| URL | Object with href | { href: "https://facilio.com" } |
| File / Signature | File ID with Id suffix on field name | "signature_1Id": 55744684 |
caution
Date and DateTime fields must always be milliseconds since epoch. Use Date.now() for current time or new Date('2025-03-15').getTime() to convert a date string.
Custom fields#
Custom fields use the naming pattern {fieldLinkName}_{moduleLinkName}.
To find the exact link name of a field, go to Setup > Customization > Modules > [Your Module] > Fields in Facilio.
Reading record objects#
When records are returned from fetchRecord or fetchAll, field values may be objects. Use these rules when reading:
| Field Type | How to read the display value |
|---|---|
| Picklist | Check displayName first, then fall back to name. Example: record.priority?.displayName ?? record.priority?.name |
| Lookup | Use name for the display label. Example: record.vendor?.name |
| Multi-select Lookup | Each item has name; iterate as needed |
| siteId | Special number field — not a lookup. Call fetchRecord('site', { id: record.siteId }) to get the site name. |
const { workorder } = await window.facilioApp.api.fetchRecord('workorder', { id: 729857 });// Picklist: prefer displayName, then nameconst priorityLabel = workorder.priority?.displayName ?? workorder.priority?.name;// Lookup: name is fineconst vendorName = workorder.vendor?.name;// siteId is a number, not a lookup — fetch site to get nameconst { site } = await window.facilioApp.api.fetchRecord('site', { id: workorder.siteId });const siteName = site?.name;createRecord#
Creates a new record on a module.
app.api.createRecord(moduleName, options)| Param | Type | Description |
|---|---|---|
moduleName | string | Module link name (e.g., 'workorder', 'asset') |
options.data | object | Field values. See Field types |
Returns — On success: { code: 0, error: null, [moduleName]: createdRecord }. The created record is under the module key (e.g., workorder for workorder module). On error: error object in the response or thrown in the catch block.
Example
const response = await window.facilioApp.api.createRecord('workorder', { data: { subject: 'Chiller maintenance', description: 'Quarterly inspection', siteId: 1559257, client: { id: 54 }, assignedTo: { id: 1440055 }, priority: { id: 955 }, dueDate: new Date('2025-04-01').getTime(), highRisk: false }});// Success: { code: 0, error: null, workorder: { id, subject, ... } }const createdRecord = response.workorder;Example with custom fields
await window.facilioApp.api.createRecord('workorder', { data: { subject: 'Custom field example', siteId: 1559257, single_line_test: 'custom string value', non_currency_workorder: 234, default_decimal_workorder_1: 23423.34, currency_workorder: 23423, currencyCode: 'AED', exchangeRate: 2, field_schedule_date_workorder_1: new Date('2025-06-25').getTime(), boolean_25: false, lookup_space_workorder: { id: 1559359 }, people_lookup_workorder: [{ id: 10700 }], url_field_workorder: { href: 'https://facilio.com' }, signature_1Id: 55744684 }});updateRecord#
Updates an existing record by its ID. Only pass the fields you want to change.
app.api.updateRecord(moduleName, options)| Param | Type | Description |
|---|---|---|
moduleName | string | Module link name |
options.id | number | Record ID to update |
options.data | object | Fields to update |
Returns — On success: { code: 0, error: null, [moduleName]: updatedRecord }. The updated record is under the module key (e.g., workorder for workorder module). On error: error object in the response or thrown in the catch block.
Example
const response = await window.facilioApp.api.updateRecord('workorder', { id: 729857, data: { subject: 'Updated subject', priority: { id: 955 }, dueDate: new Date('2025-05-01').getTime() }});// Success: { code: 0, error: null, workorder: { id, subject, ... } }const updatedRecord = response.workorder;fetchRecord#
Fetches a single record by its ID.
app.api.fetchRecord(moduleName, options)| Param | Type | Description |
|---|---|---|
moduleName | string | Module link name |
options.id | number | Record ID |
Returns — An object with code, error, and the record under the module key:
| Field | Type | Description |
|---|---|---|
code | number | 0 on success |
error | null | object | Error details if any |
{moduleName} | object | The record (e.g., workorder for workorder module, vendors for vendors) |
Example
const response = await window.facilioApp.api.fetchRecord('workorder', { id: 729857 });const workorder = response.workorder; // Record is under the module keyconsole.log(workorder.subject, workorder.id);fetchAll#
Fetches a list of records with optional filtering, pagination, and sorting.
app.api.fetchAll(moduleName, options)| Param | Type | Description |
|---|---|---|
moduleName | string | Module link name |
options.viewName | string | View name (e.g., 'all', 'active') |
options.filters | string | JSON-stringified filter object. See Filters |
options.page | number | Page number (1-based) |
options.perPage | number | Records per page |
options.orderBy | string | Field link name to sort by |
options.orderType | string | 'asc' or 'desc' |
options.includeParentFilter | boolean | Include parent module filters |
options.withCount | boolean | Include total count in response |
Returns — { list, code, meta, error }:
| Field | Type | Description |
|---|---|---|
list | array | Records. Always an array — empty when no results or on error. |
code | number | 0 on success |
error | null | object | Error details if any. When set, list is still present as empty array. |
meta | object | Present when withCount: true. Contains { supplements: {...}, pagination: { totalCount: number } } |
Example
const { list, error, meta } = await window.facilioApp.api.fetchAll('workorder', { viewName: 'all', page: 1, perPage: 50, orderBy: 'createdTime', orderType: 'desc', withCount: true, filters: JSON.stringify({ subject: { operator: 'contains', value: ['maintenance'] }, priority: { operator: 'is', value: ['955'] } })});// list is always array; meta.pagination.totalCount when withCount: trueconst totalCount = meta?.pagination?.totalCount;deleteRecord#
Deletes a record by its ID.
app.api.deleteRecord(moduleName, options)| Param | Type | Description |
|---|---|---|
moduleName | string | Module link name |
options.id | number | Record ID to delete |
Returns — On success: { code: 0, error: null, [moduleName]: 1 }. The module key contains the count of deleted records (1). On error: error object in the response or thrown in the catch block.
Example
const response = await window.facilioApp.api.deleteRecord('workorder', { id: 729857 });// Success: { code: 0, error: null, workorder: 1 }uploadFile#
Uploads a file and returns a JSON object with fileId. Use the returned fileId for File or Signature fields (e.g., signature_1Id, or any file field with the Id suffix).
app.api.uploadFile(file)| Param | Type | Description |
|---|---|---|
file | File | A File object from an <input type="file"> or DataTransfer |
Returns — A Promise that resolves with { fileId } — use fileId in record create/update for File or Signature fields.
File size limit
Maximum file size is 10 MB. The method throws an error if the file exceeds this limit.
Example
// From file inputconst fileInput = document.querySelector('input[type="file"]');const file = fileInput.files[0];if (file) { const { fileId } = await window.facilioApp.api.uploadFile(file); await window.facilioApp.api.createRecord('workorder', { data: { subject: 'Work order with attachment', siteId: 1559257, attachmentId: fileId // or the appropriate field with Id suffix } });}Example — File input change handler
async handleFileSelect(event) { const file = event.target.files[0]; if (!file) return; try { const { fileId } = await window.facilioApp.api.uploadFile(file); this.uploadedFileId = fileId; } catch (error) { if (error.message.includes('10 MB')) { window.facilioApp.interface.notify({ title: 'File too large', message: 'Maximum file size is 10 MB', type: 'error' }); } else { throw error; } }}Filters#
Pass a JSON-stringified filter object to the filters option in fetchAll.
Structure#
filters: JSON.stringify({ fieldLinkName: { operator: 'operator string', value: ['value1', 'value2'] }})valueis always an array, even for single values- For operators that need no value (e.g.,
"Today","is empty"), pass[] - Multiple fields in the same object = AND logic
note
Operator strings are case-sensitive. Use them exactly as shown (e.g., "Today" not "today", "Current Month" not "current_month").
String operators#
| Operator | Description |
|---|---|
"is" | Exact match |
"isn't" | Not equal |
"contains" | Contains substring |
"doesn't contain" | Does not contain |
"starts with" | Starts with |
"ends with" | Ends with |
Number / Currency operators#
| Operator | Description |
|---|---|
"=" | Equals |
"!=" | Not equals |
"<" | Less than |
"<=" | Less than or equal |
">" | Greater than |
">=" | Greater than or equal |
"between" | Between two values |
"not between" | Not between two values |
Date / DateTime operators#
| Operator | Value needed |
|---|---|
"is" | Date in milliseconds |
"isn't" | Date in milliseconds |
"is before" | Date in milliseconds |
"is after" | Date in milliseconds |
"between" | Two dates in milliseconds |
"not between" | Two dates in milliseconds |
"Today" | [] |
"today upto now" | [] |
"Tomorrow" | [] |
"Starting Tomorrow" | [] |
"Yesterday" | [] |
"Till Yesterday" | [] |
"Till Now" | [] |
"Upcoming" | [] |
"Current Week" | [] |
"Current Week upto now" | [] |
"Last Week" | [] |
"Next Week" | [] |
"Next N Weeks" | ['N'] |
"Current Month" | [] |
"Current Month upto now" | [] |
"Last Month" | [] |
"Next Month" | [] |
"Next N Months" | ['N'] |
"Last Months" | ['N'] |
"Current Year" | [] |
"Current Year upto now" | [] |
"Last Year" | [] |
"Age in Days" | ['N'] |
"Due in Days" | ['N'] |
"Next N Days" | ['N'] |
"Within N Hours" | ['N'] |
Boolean operators#
| Operator | Value |
|---|---|
"is" | ['true'] or ['false'] |
Lookup / Picklist operators#
| Operator | Value |
|---|---|
"is" | ['recordId'] |
"isn't" | ['recordId'] |
Enum operators#
| Operator | Value |
|---|---|
"is" | ['enumValue'] |
"isn't" | ['enumValue'] |
"value is" | ['enumValue'] |
"value isn't" | ['enumValue'] |
Common operators (all field types)#
| Operator | Value |
|---|---|
"is empty" | [] |
"is not empty" | [] |
Filter examples#
| Use case | Filter |
|---|---|
| String contains | { subject: { operator: 'contains', value: ['chiller'] } } |
| String exact match | { name: { operator: 'is', value: ['Building A'] } } |
| Number greater than | { area: { operator: '>', value: ['500'] } } |
| Number between | { area: { operator: 'between', value: ['100', '500'] } } |
| Date today | { dueDate: { operator: 'Today', value: [] } } |
| Date before | { createdTime: { operator: 'is before', value: [String(new Date('2025-03-01').getTime())] } } |
| Date current month | { dueDate: { operator: 'Current Month', value: [] } } |
| Date next 7 days | { dueDate: { operator: 'Next N Days', value: ['7'] } } |
| Boolean true | { highRisk: { operator: 'is', value: ['true'] } } |
| Lookup by ID | { siteId: { operator: 'is', value: ['1559257'] } } |
| Picklist by ID | { priority: { operator: 'is', value: ['955'] } } |
| Enum by value | { sourceType: { operator: 'value is', value: ['email'] } } |
| Field not empty | { description: { operator: 'is not empty', value: [] } } |
| Custom field | { non_currency_workorder: { operator: '>', value: ['1000'] } } |
Combining filters#
Multiple fields in the same object are combined with AND logic.
const { list } = await window.facilioApp.api.fetchAll('workorder', { viewName: 'all', filters: JSON.stringify({ subject: { operator: 'contains', value: ['maintenance'] }, priority: { operator: 'is', value: ['955'] }, dueDate: { operator: 'Current Month', value: [] } })});