Skip to main content

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].

MethodDescription
createRecordCreate a new record
updateRecordUpdate an existing record by ID
fetchRecordFetch a single record by ID
fetchAllFetch a list of records with filters and pagination
deleteRecordDelete a record by ID
uploadFileUpload 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 TypeFormatExample
StringPlain string"Chiller maintenance"
NumberNumber234
DecimalDecimal number23423.34
CurrencyNumber + currencyCode + exchangeRate"currency_workorder": 23423, "currencyCode": "AED", "exchangeRate": 2
Booleantrue or falsefalse
Date / DateTimeMilliseconds since epochnew Date('2025-03-15').getTime() or Date.now()
LookupObject with id{ id: 54 }
Multi-select LookupArray of { id } objects[{ id: 10700 }, { id: 10701 }]
PicklistObject with id{ id: 955 }
EnumString value"urgent"
URLObject with href{ href: "https://facilio.com" }
File / SignatureFile 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 TypeHow to read the display value
PicklistCheck displayName first, then fall back to name. Example: record.priority?.displayName ?? record.priority?.name
LookupUse name for the display label. Example: record.vendor?.name
Multi-select LookupEach item has name; iterate as needed
siteIdSpecial 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)
ParamTypeDescription
moduleNamestringModule link name (e.g., 'workorder', 'asset')
options.dataobjectField 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)
ParamTypeDescription
moduleNamestringModule link name
options.idnumberRecord ID to update
options.dataobjectFields 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)
ParamTypeDescription
moduleNamestringModule link name
options.idnumberRecord ID

Returns — An object with code, error, and the record under the module key:

FieldTypeDescription
codenumber0 on success
errornull | objectError details if any
{moduleName}objectThe 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)
ParamTypeDescription
moduleNamestringModule link name
options.viewNamestringView name (e.g., 'all', 'active')
options.filtersstringJSON-stringified filter object. See Filters
options.pagenumberPage number (1-based)
options.perPagenumberRecords per page
options.orderBystringField link name to sort by
options.orderTypestring'asc' or 'desc'
options.includeParentFilterbooleanInclude parent module filters
options.withCountbooleanInclude total count in response

Returns{ list, code, meta, error }:

FieldTypeDescription
listarrayRecords. Always an array — empty when no results or on error.
codenumber0 on success
errornull | objectError details if any. When set, list is still present as empty array.
metaobjectPresent 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)
ParamTypeDescription
moduleNamestringModule link name
options.idnumberRecord 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)
ParamTypeDescription
fileFileA 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']  }})
  • value is 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#

OperatorDescription
"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#

OperatorDescription
"="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#

OperatorValue 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#

OperatorValue
"is"['true'] or ['false']

Lookup / Picklist operators#

OperatorValue
"is"['recordId']
"isn't"['recordId']

Enum operators#

OperatorValue
"is"['enumValue']
"isn't"['enumValue']
"value is"['enumValue']
"value isn't"['enumValue']

Common operators (all field types)#

OperatorValue
"is empty"[]
"is not empty"[]

Filter examples#

Use caseFilter
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: [] }  })});