Provision API v1

Resources 00 Resources

Resources

Resources are the reference data your organization keeps in Provision: suppliers, customers, products, product categories, equipment, chemicals, employees, areas, lots, recipes and documents. Each kind is one dataset in GET /v1/datasets, with a key that begins resources_, and each exports and pages through the same endpoint and cursor rules as every other dataset.

Unlike form datasets, their core columns are the same for every customer, so this page lists them. On top of those, every resource dataset except resources_documents adds a column for each custom attribute your organization defines for that kind of resource; see Custom attribute columns. Read the exact list from GET /v1/datasets, and treat this page as the meaning of each core column.

What every resource dataset shares

  • id is the resource's uuid, and the key to upsert on. The resource select columns in form datasets (<field>_id) join to it.
  • last_modified is when the resource itself last changed, in UTC. It is the cursor column, as everywhere. No resource dataset has *_local timestamps.
  • The dataset has no displayName, and only some of its fixed columns have a label — though every custom attribute column has one, the attribute's name. Fall back to key.
  • Deleting a resource removes its row, silently; see Deleted records stop being exported. Archiving does not remove a document; see Documents.
  • A name can be blank while the id beside it is filled. site_name, site_path, product_name and the other columns naming a related record are read from that record as it stands now, so deleting it empties the name and leaves the id in place — deliberately, so the row itself is not dropped. A roll-up keyed on site_path silently loses those rows, and the id no longer joins to anything in the related dataset.
  • The CSV dialect is the same as for every dataset; see Reading the values.
  • Two columns join a first and last name with a space (contact_name on resources_customers, name on resources_employees). When both parts are missing they export as a single space, not NULL or an empty string, so trim before testing for emptiness.

Custom attribute columns

Every resource dataset except resources_documents adds one column per custom attribute defined for that kind of resource, after the core columns. The column is named from the attribute's key, following the naming rules, and a name that clashes with a core column gets a numeric suffix. Its label is the attribute's name.

Custom attribute typeColumn typeValue
NumbernumberThe number
DatedateThe date
DateTimedateTimeThe date and time
Document, SingleDocumenttextThe names of the linked documents, joined by a comma and a space
SelecttextThe option's stored key, not the label users see in Provision, and not affected by renaming the option
MultiSelecttextA JSON array of the stored option keys, sorted: ["gmp","haccp"]. Not a comma-joined list — parse it as JSON
Any other typetextThe stored value

A value that does not fit its type exports as empty. A Number attribute holding N/A or 12 kg, or a Date that is not written year first, exports as nothing, not as its original text. Only that cell is emptied; the rest of the row and the export are unaffected. The value is usually still intact in Provision and worth correcting there.

A custom attribute can take a name that means something elsewhere. What is reserved is the dataset's own core columns plus the four names the export owns — id, last_modified, row_index and row_seq, which is internal numbering the cursor is built on and never appears in a CSV — and those four are reserved whether or not the dataset publishes a column of that name. Everything else is fair game, so an attribute whose key is "Site Name" or "Record ID" on a resource without those columns becomes a site_name or record_id column holding the attribute's value, while one keyed "Row Index" gets a numeric suffix instead. See Site, status and record columns.

List columns

Where a resource links to many of something, the export flattens the links into one text column of names joined by a comma and a space:

DatasetList columns
resources_suppliersproducts, parent_names
resources_customersproducts
resources_productscustomers, sites, suppliers, allergens
resources_chemicalssites
resources_employeesteams, sites
resources_documentssites, teams
Every dataset with custom attributeseach Document and SingleDocument custom attribute

They hold names, not ids, so use them for display, not joins. A name containing a comma looks like two names, so splitting on , is unreliable. To model the relationships themselves, use the datasets on both sides.

A sites list is not a site column. It lists site names, and has nothing to do with the site_id / site_name / site_path columns that identify the one site a form row belongs to. Do not join it to a site dimension.

List columns go stale in an incremental sync. Renaming a product changes the products value of every supplier and customer listing it, without moving their last_modified, so the cursor never offers those rows again. Renaming a supplier does the same to the parent_names of every supplier beneath it. Re-read resource datasets in full on a schedule if these columns matter; see Upsert, do not append.

Site, status and record columns

Some column names mean one thing on form datasets and something else, or nothing reserved, here.

Site columns. Only three resource datasets have a site: resources_lots, resources_areas and resources_equipment. Each has site_id, site_name and site_path, read the same way as a form dataset's. On every other resource dataset those names are not reserved, so a column called site_name or site_path there is a custom attribute, and joining it to your sites produces nonsense.

status. On resources_suppliers, resources_lots and resources_recipes it is that resource's own status, unrelated to a submission's status.

record_id. No resource dataset has one, so a record_id column on a resource dataset is a custom attribute, and joining it to submission record codes produces nonsense.

row_index. Reserved here too. A custom attribute that slugifies to row_index does not take the name: it gets a numeric suffix (row_index_2) instead, so no resource dataset publishes a row_index column and afterRowIndex is rejected on all of them. Only grid datasets have one; see Terms these pages use.

Check the columns GET /v1/datasets reports for the handful you rely on, rather than assuming either way.

Suppliers

Dataset resources_suppliers. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the supplier.
nametextName of the supplier.
descriptiontextFree-text description of the supplier.
website_urltextSupplier's website address.
statustextStatus recorded for the supplier.
markettextMarket recorded for the supplier.
typetextType recorded for the supplier.
street1textFirst street line of the supplier's address.
street2textSecond street line of the supplier's address.
citytextCity of the supplier's address.
regiontextState or region of the supplier's address.
zip_codetextPostal code of the supplier's address.
countrytextCountry of the supplier's address.
productstextProducts linked to this supplier, as names joined by a comma and a space.
parent_namestextParent suppliers this supplier sits under, as names joined by a comma and a space.
last_modifieddateTimeWhen this supplier was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Customers

Dataset resources_customers. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the customer.
nametextName of the customer.
descriptiontextFree-text description of the customer.
website_urltextCustomer's website address.
phone_numbertextCustomer's phone number.
street1textFirst street line of the customer's address.
street2textSecond street line of the customer's address.
citytextCity of the customer's address.
regiontextState or region of the customer's address.
zip_codetextPostal code of the customer's address.
countrytextCountry of the customer's address.
contact_nametextFull name of the customer's contact, first and last name together.
contact_emailtextEmail address of the customer's contact.
contact_phonetextPhone number of the customer's contact.
productstextProducts linked to this customer, as names joined by a comma and a space.
last_modifieddateTimeWhen this customer was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Products

Dataset resources_products. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the product.
nametextName of the product.
descriptiontextFree-text description of the product.
product_codetextCode identifying the product.
product_typetextProduct type: RawMaterial, WorkInProgress, FinishedGood or Packaging; anything else appears as its stored number.
product_category_nametextName of the category the product is in.
allergen_statustextAllergen status recorded for the product.
allergenstextAllergens recorded for the product, joined by a comma and a space; empty when none are recorded.
default_shelf_life_quantitynumberDefault shelf life of the product, as a number counted in the unit below.
default_shelf_life_unittextUnit the default shelf life is counted in.
customerstextCustomers linked to this product, as names joined by a comma and a space.
sitestextSites linked to this product, as names joined by a comma and a space.
supplierstextSuppliers linked to this product, as names joined by a comma and a space.
last_modifieddateTimeWhen this product was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Product categories

Dataset resources_product_categories. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the product category.
nametextName of the product category.
descriptiontextFree-text description of the product category.
parent_nametextName of the category this category sits under.
last_modifieddateTimeWhen this product category was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Equipment

Dataset resources_equipment. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the equipment.
nametextName of the equipment.
maketextMake of the equipment.
modeltextModel of the equipment.
serial_numbertextSerial number of the equipment.
site_nametextName of the site the equipment belongs to.
site_iduuidUnique identifier of the site the equipment belongs to.
site_pathtextFull position of that site in the site hierarchy, from the top level down.
area_nametextName of the area the equipment is in.
last_modifieddateTimeWhen this equipment was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Chemicals

Dataset resources_chemicals. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the chemical.
nametextName of the chemical.
typetextType recorded for the chemical.
gradetextGrade recorded for the chemical.
production_methodtextProduction method recorded for the chemical.
sitestextSites linked to this chemical, as names joined by a comma and a space.
last_modifieddateTimeWhen this chemical was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Employees

Dataset resources_employees. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the employee.
nametextFull name of the employee, first and last name together.
job_titletextJob title of the employee.
access_leveltextThe employee's access level in the organization.
teamstextTeams the employee belongs to, as names joined by a comma and a space.
sitestextSites the employee is assigned to, as names joined by a comma and a space.
last_modifieddateTimeWhen this employee was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Areas

Dataset resources_areas. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the area.
nametextName of the area.
descriptiontextFree-text description of the area.
typetextType recorded for the area.
sizenumberSize of the area, counted in the unit below.
size_unittextUnit the area size is counted in.
area_pathtextFull position of the area in the area hierarchy, from the top level down.
parent_nametextName of the area this area sits under.
site_iduuidUnique identifier of the site the area belongs to.
site_nametextName of the site the area belongs to.
site_pathtextFull position of that site in the site hierarchy, from the top level down.
last_modifieddateTimeWhen this area was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

area_path is the area hierarchy, not the site one. It is built by the same rule as site_path — the area's own id and every area above it, outermost first, joined by dots — so whatever parses one parses the other. This dataset carries both: read area_path for the area tree and site_path for the site tree, and do not join one to the other.

Lots

Dataset resources_lots. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the lot.
codetextCode identifying the lot.
descriptiontextFree-text description of the lot.
statustextStatus recorded for the lot.
quantitynumberQuantity held in the lot, counted in the unit below.
unittextUnit the lot quantity is counted in.
expiry_datedateDate the lot expires.
date_receiveddateDate the lot was received.
date_produceddateDate the lot was produced.
product_iduuidUnique identifier of the product this lot is of.
product_nametextName of the product this lot is of.
site_iduuidUnique identifier of the site the lot belongs to.
site_nametextName of the site the lot belongs to.
site_pathtextFull position of that site in the site hierarchy, from the top level down.
last_modifieddateTimeWhen this lot was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

expiry_date, date_received and date_produced are date columns: a calendar day, with no time or offset.

Recipes

Dataset resources_recipes. Adds custom attribute columns.

ColumnTypeMeaning
iduuidUnique identifier of the recipe.
nametextName of the recipe.
descriptiontextFree-text description of the recipe.
statustextStatus recorded for the recipe.
output_quantitynumberQuantity the recipe produces, counted in the unit below.
output_unittextUnit the produced quantity is counted in.
has_unpublished_changesbooleanTrue when the recipe has changes that have not been published.
output_product_iduuidUnique identifier of the product the recipe produces.
output_product_nametextName of the product the recipe produces.
last_modifieddateTimeWhen this recipe was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Documents

Dataset resources_documents. Adds no custom attribute columns, so its columns are the same for every customer.

ColumnTypeMeaning
iduuidUnique identifier of the document.
nametextName of the document.
typetextType recorded for the document.
abouttextShort note on what the document is about.
versiontextVersion label of the document's currently published version.
is_archivedbooleanTrue when the document is archived.
sitestextSites linked to this document, as names joined by a comma and a space.
teamstextTeams linked to this document, as names joined by a comma and a space.
last_modifieddateTimeWhen this document was last changed.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

Archived documents keep exporting. Archiving a document leaves its row in place with is_archived t, so filter on that column for a list of current documents. It says only whether the document is archived: a draft, one in review and a rejected one all export with is_archived f, like a published document.

resources_documents is the only resource dataset with such a column. Others export their rows whatever state they are in — an archived employee is in resources_employees with nothing marking it — and lose a row only when the resource is deleted.

Resources 01 Deviations

Deviations

A deviation is a value flagged as out of spec on one field of one submission. The deviations dataset has one row per deviation: the field's key and label, the recorded value, a severity, and how, or whether, it was resolved, alongside the submission, step and site it came from.

Its columns are the same for every customer: it takes no custom attributes, and has no resources_ prefix. Deviations come from your forms, so the dataset moves with your submissions, and deleting a submission removes its deviations.

Columns

ColumnTypeMeaning
iduuidUnique identifier of the deviation.
codetextCode identifying the deviation.
severitytextSeverity recorded for the deviation.
statustextDeviation status: Resolved, InProgress or Open.
is_resolvedbooleanTrue when the deviation has been resolved.
resolution_typetextHow it was resolved: LinkedResolutionRecord or Comment; empty while unresolved.
field_keytextIdentifier of the form field the deviation was raised on.
field_labeltextLabel of the form field the deviation was raised on.
display_valuetextThe value recorded in that field.
row_idtextIdentifier of the grid row the deviation was raised on, for fields inside a grid.
workflow_nametextName of the form; kept for existing dashboards and superseded by form_name.
form_nametextName of the form the deviation was raised on.
submission_iduuidUnique identifier of the submission the deviation was raised on.
record_idtextCode identifying the record the deviation was raised on.
submission_statustextStatus of the submission the deviation was raised on.
is_archivedbooleanTrue when the record holding the deviation is archived.
step_nametextName of the form step the deviation was raised on.
step_statustextStatus of that step.
site_nametextName of the site the submission belongs to.
site_iduuidUnique identifier of the site the submission belongs to.
site_pathtextFull position of that site in the site hierarchy, from the top level down.
assigned_totextWho the deviation is assigned to: the assigned person's name, or the assigned team's name when no person is set.
assigned_user_nametextName of the person the deviation is assigned to.
assigned_team_nametextName of the team the deviation is assigned to.
supplier_nametextName of the supplier the deviation is attributed to.
commenttextComment recorded with the deviation.
resolution_commenttextComment recorded when the deviation was resolved.
resolved_bytextName of the person who resolved the deviation.
resolved_atdateTimeWhen the deviation was resolved, in UTC.
resolved_at_locallocalDateTimeWhen the deviation was resolved, in the site's time zone.
signed_bytextName of the person who signed the resolution.
signed_atdateTimeWhen the resolution was signed, in UTC.
signed_at_locallocalDateTimeWhen the resolution was signed, in the site's time zone.
linked_record_codetextCode of the record linked as the deviation's resolution.
linked_record_statustextStatus of the record linked as the deviation's resolution.
linked_record_sourcetextSource of the record linked as the deviation's resolution.
linked_resolution_commenttextComment recorded on the deviation about its linked resolution record.
created_atdateTimeWhen the deviation was created, in UTC.
created_at_locallocalDateTimeWhen the deviation was created, in the site's time zone.
last_modifieddateTimeWhen the deviation was last changed, in UTC.
last_modified_locallocalDateTimeWhen the deviation was last changed, in the site's time zone.
_cursortextThis row’s paging position, added by the export rather than stored. Opaque: send it back as cursor and do not parse it. See the sync loop

It borrows some columns from the submission, with the meanings the envelope columns give them: record_id, site_id, site_name, site_path and is_archived. Its *_local timestamps are its own, describing the deviation, read the same way as a form dataset's. id is the deviation's own id.

step_name and step_status are the recording step the flagged field sits on. A deviation is only ever raised on a recording step, so a verification step never appears here.

form_name and workflow_name are the same value — the name of the form the submission was made against. Workflow is our older word for a form, and workflow_name is kept only so dashboards built on it keep working; the two are filled from one expression and cannot differ. Build on form_name, and expect workflow_name to be retired in a later version.

comment is a standalone note on the deviation, which can be added, changed or removed at any time — not a record of what was said when the deviation was raised. linked_record_source says where the linked resolution record came from; treat its values as opaque unless we have told you otherwise.

Joining a deviation to its submission

Join on submission_id. It holds the same uuid as the submission dataset's id, and it is the only column that makes that join. record_id beside it is the human-readable record code: good for display, not the submission dataset's key.

row_id cannot reach a grid row. It is set when the deviation was raised on a field inside a grid, but no grid dataset publishes a matching id: a grid row is identified by id plus row_index, and row_index is a position. So row_id tells you that the deviation came from a grid row, not which one. Treat it as an opaque marker.

Status and resolution

  • status is the deviation's state: Open, InProgress or Resolved. The submission's own status is submission_status. Every change to it moves last_modified, so an incremental sync offers the row again: linking a record sets a column on the deviation row, and resolving writes its resolution to a table of its own and restamps the deviation, so Open → InProgress → Resolved all reach you. That holds however it was resolved — with a comment, by editing that comment, or by completing the linked record. Other columns are less well behaved; see Keeping deviations current.
  • is_resolved is the column that says whether it was resolved. A linked_record_code is set as soon as a record is linked as the intended resolution, before it resolves anything: such a row is InProgress with is_resolved f, possibly indefinitely. See Record and deviation codes.
  • A resolution can carry a signature, given when the deviation is resolved with a comment. That is where signed_by, signed_at and signed_at_local come from. They are empty for a resolution without a signature, including one completed through a linked record, and an unresolved deviation never has them.
  • code is the deviation's own code, in its own format and on its own counter; see Record and deviation codes.

Keeping deviations current

A deviation's last_modified only follows the deviation row itself. Resolution is the exception worth knowing about, and it is handled: resolving writes to a table of its own and restamps the deviation, so status, is_resolved, resolution_type, resolution_comment, resolved_by and the resolved_at and signed_* timestamps all reach an incremental consumer. A deviation does not keep showing as open after someone resolved it.

What still escapes the cursor are the columns the deviation only displays: the submission, step and site columns, the linked record's linked_record_status, the names of the employee, team and supplier, and the standalone comment, which is stored beside the deviation rather than on it. Those belong to other records, and changing one of those records moves its own last_modified, not the deviation's. If you report on them, re-read deviations in full on a schedule, as Upsert, do not append describes for resource list columns.

A person's name can also be missing where a person really is set. assigned_user_name, resolved_by and signed_by are read from your employee directory, so someone with no live employee record there — a Provision Admin, or an employee since deleted — leaves them empty on a deviation that was assigned, resolved or signed. assigned_to then falls back to the team's name, so such a row reads as team-assigned although a person is assigned. Read assigned_user_name and assigned_team_name rather than inferring which of the two assigned_to holds, and treat an empty resolved_by on a resolved deviation as an unresolvable person, not as an unresolved deviation.