This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

REST APIs

Kianda’s REST Application Programming Interface (API) can be used to perform operations or methods such as create, update and get/retrieve items on a number of key areas that include:

  • Processes - namely process designs created by administrators or designers in Kianda Designer
  • Instances - namely instances of processes or records created by form users who have saved or submitted details in a process instance
  • Tasks - namely scheduled tasks created by administrators or instigated by processes, as seen in the Scheduled tasks function within Administration

The following pages introduce APIs for the above. In all cases Authentication is required for requests.

1 - Authentication

Introduction

The framework used for authentication in Kianda is OAuth 2.0. This framework uses industry-standard protocol for authorisation focusing on simplifying client developer practices, and at the same time providing specific authorisation flows for applications. The OAuth 2.0 framework uses Bearer type tokens to authorise access to the platform for individual users. This type of token is required by Kianda to perform any Create, Read, Update and Delete (CRUD) requests to external Application Programming Interfaces (APIs).

When working within Kianda, there is no need for the Bearer token when making API requests during widget, rule or field creation because the Bearer token is already retrieved as part of a user login. If you may want to create an application outside of Kianda however, this Bearer token needs to be provided for any CRUD operations to the API. There are two methods to retrieve the Bearer token:

Click on the links above to go the the relevant sections.

Retrieving Bearer token using a POST request

You can retrieve a bearer token using a POST request where the content body type is is set to application, x-www-form-urlencoded.

The request will look like https://domain.com/token where the domain is your company, for example https://green-itr.kianda.com/token . For the request to be valid, you need to pass the following form parameters to the body of the request:

ParameterValue
username:your Kianda username
password:your Kianda password
scope:your Kianda subscription ID
grant_type:password

The Response Body will be as follows:

{
    "access_token": "<Bearer access_token",
    "token_type": "bearer",
    "expires_in": 299,
    "userName": "<Provided username>",
    "userId": "<Application userId>",
    "subscriptionId": "<SubscriptionID>",
    "securityStamp": "<Token Security token (Guid)>",
    "hostURL": "<Your kianda domain>",
    ".issued": "<Token Issued Date and time>",
    ".expires": "<Token Issued Date and time>"
}

You can obtain the scope value by going to Administration > Subscription > Subscription Details > Subscription Id.

Subscription Id

Retrieving Bearer token using DevTools

You can retrieve your Bearer token using Chrome DevTools, making sure you are logged into Kianda. When logged in, open Chrome DevTools by:

  1. Right clicking your mouse anywhere on the screen.
  2. Click on Inspect in the dialog box.
  3. Open the Network tab.
  4. Click on the info request.
  5. In the Header tab, scroll down to authorisation. You can find your Bearer token here.

What’s next Idea icon

To learn more about Kianda’s API go to Instance API.

2 - Instances

The Instances API lets you create, retrieve, update and delete Kianda process instances. An instance is an individual process record, such as one incident report or one inspection. A process design defines the forms, fields and rules used by those records.

For integrations that set field values or change form properties, use the mapping-based create and update endpoints. Use the document endpoints when your integration works with a complete Kianda instance JSON document.

Endpoint reference

All paths are relative to your workspace URL.

MethodPathPurpose
POST/api/instances/createCreate an instance from a process design and field mappings.
POST/api/instances/createBulkCreate multiple instances using an array of create requests.
PATCH/api/instances/{name}/updateUpdate an instance using field and form mappings.
PATCH/api/instances/updateBulkUpdate multiple instances using an array of update requests.
GET/api/instances/{name}Get an instance document.
GET/api/instances/{name}/versionGet instance version information.
PUT/api/instances/{name}Update using an instance document.
POST/api/instancesSubmit an instance document.
DELETE/api/instances/{name}Delete an instance.
POST/api/instances/bulkdeleteDelete multiple instances.
GET/api/instances/{name}/fieldsGet selected fields from an instance.

Authentication and request format

Send requests to the workspace that contains the target process and instances. Obtain a bearer access token as described in Authentication, and use an account with permission to perform the requested operation.

Include these headers on requests with a JSON body:

Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json
Content-Type: application/json

GET requests and the single-instance DELETE request have no request body; the Content-Type header is unnecessary for those examples.

Run the examples

The cURL examples use Bash-style environment variables and cURL 7.76.0 or later. They include --fail-with-body so HTTP responses with a status of 400 or above produce a non-zero exit status while retaining the response body.

Set these variables before running an example:

export KIANDA_BASE_URL="https://your-workspace.kianda.com"
export KIANDA_ACCESS_TOKEN="YOUR_ACCESS_TOKEN"

Set KIANDA_BASE_URL to your workspace’s base URL, without a trailing slash. Use your workspace’s custom domain if applicable.

Process, instance, form and field identifiers in the examples are illustrative. Replace them with identifiers from your workspace. Example field values must also be valid for the target field and its configuration.

Examples are independent. For operations on existing instances, replace the sample instance name with an actual instance name from your workspace.

Identifiers and property names

IdentifierMeaningExample
ProcessNameThe identifier of a process design, despite the property name.incident-report
{name}The name of an existing process instance, used in the URL.incident-report-42
InstanceNameThe instance name supplied in an update request body.incident-report-42
FieldNameA field’s internal name, unique within the process.description
FormNameA form’s internal unique name.incident-details
CurrentFormNameThe internal name of the form to set as the current workflow form.review

Use internal field and form names when constructing mappings. Display labels and titles may differ from these names. An instance document’s id and name are separate properties; the routes containing {name} use the instance name.

Mapping request properties use the spelling and casing shown in this reference, such as FieldsMappings, FieldName and InstanceName. Instance documents contain properties such as name, forms, value and text.

Field mappings

Both create and update requests use InstanceRequestFieldMapping objects in FieldsMappings.

PropertyJSON typeDescription
FieldNameStringInternal name of the field to target. Corresponds to field.name.
ValueAny JSON valueValue to assign to field.value. Supply the JSON structure expected by the target field.
TextStringText to assign to field.text, for example the display text associated with a selected value.
VisibleBoolean or nulltrue shows the field; false hides it. An omitted or null setting does not request a visibility change.
EnabledBoolean or nulltrue enables the field; false disables it. An omitted or null setting does not request an enabled-state change.

For example, this mapping assigns a location value and display text, and explicitly shows and enables the field:

{
  "FieldName": "location",
  "Value": "dublin-depot",
  "Text": "Dublin depot",
  "Visible": true,
  "Enabled": true
}

Value is represented by JToken in the request model. It can therefore carry a JSON string, number, boolean, object, array or null. The target field determines which of those representations is valid. For example, send a numeric JSON value when the field expects a number.

Value and Text target separate properties. When your change requires both a stored value and corresponding display text, supply both. For updates, include mappings for the fields you intend to target. The nullable behaviour of Visible and Enabled should not be used as a general rule for clearing or preserving Value and Text.

Background execution

Create and update requests support TriggerField and ExecuteInSeries:

PropertyJSON typeDescription
TriggerFieldStringInternal name of the field to schedule as a background task.
ExecuteInSeriesStringAccepts "yes" or "no". Set "yes" to request that tasks created by the trigger field execute one after another. Set "no" when serial execution is not being requested.

For example, a request can include:

{
  "TriggerField": "submit",
  "ExecuteInSeries": "yes"
}

This is a request fragment: include these properties in a create or update body. ExecuteInSeries uses strings; the visibility and enabled properties use JSON booleans.

Background processing is scheduled separately from the API request. Receiving the HTTP response does not establish that the scheduled work has finished. ExecuteInSeries describes execution of the triggered tasks; it does not define the processing order of items in a bulk API request.

Create an instance

POST /api/instances/create

Creates an instance from the process design identified by ProcessName, applying the supplied field mappings. Use this endpoint when you have a process design identifier and values to populate.

Request body

One CreateInstanceRequest object:

PropertyJSON typeDescription
ProcessNameStringIdentifier of the process design from which to create the instance.
FieldsMappingsArray of field mappingsField values, text and presentation properties to apply. See Field mappings.
TriggerFieldStringField to schedule as a background task. See Background execution.
ExecuteInSeriesString"yes" or "no", controlling whether the triggered tasks are requested to execute in series.
StatusString or nullProcess instance status to set. Use null to ignore this setting.

Use the status values supported by the target process. This reference does not define a fixed status enumeration.

Example

curl --fail-with-body --request POST \
  "${KIANDA_BASE_URL}/api/instances/create" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
    "ProcessName": "incident-report",
    "FieldsMappings": [
      {
        "FieldName": "description",
        "Value": "Loose handrail reported at the loading bay.",
        "Text": "Loose handrail reported at the loading bay."
      },
      {
        "FieldName": "location",
        "Value": "dublin-depot",
        "Text": "Dublin depot",
        "Visible": true,
        "Enabled": true
      }
    ],
    "Status": null
  }'

Add TriggerField and ExecuteInSeries when background execution is part of the operation.

Success response

Returns 200 OK with a JSON object:

{
  "success": true,
  "instanceID": "example-created-instance-id"
}
PropertyDescription
successtrue in the successful response.
instanceIDIdentifier returned by the create result’s id property (result.id). The example identifier is illustrative.

Create multiple instances

POST /api/instances/createBulk

Creates multiple instances using the same request model as Create an instance. Each array item identifies its process design and supplies its own mappings and execution settings.

Request body

A top-level JSON array of CreateInstanceRequest objects:

[
  {
    "ProcessName": "incident-report",
    "FieldsMappings": [
      {
        "FieldName": "description",
        "Value": "Loose handrail at the loading bay.",
        "Text": "Loose handrail at the loading bay."
      }
    ]
  },
  {
    "ProcessName": "incident-report",
    "FieldsMappings": [
      {
        "FieldName": "description",
        "Value": "Damaged floor marking in the warehouse.",
        "Text": "Damaged floor marking in the warehouse."
      }
    ]
  }
]

Save the array as create-requests.json, then submit it:

curl --fail-with-body --request POST \
  "${KIANDA_BASE_URL}/api/instances/createBulk" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data-binary @create-requests.json

The array itself is the request body. Each item has the same properties described for a single create request.

Success response

Returns 200 OK with a JSON object:

{
  "success": true,
  "instanceIDs": [
    "example-created-instance-id-1",
    "example-created-instance-id-2"
  ]
}
PropertyDescription
successtrue in the successful response.
instanceIDsArray of instance identifiers collected during creation. The example identifiers are illustrative.

The property name is instanceIDs for bulk creation. The response does not include a per-item result object alongside each identifier.

Update an instance

PATCH /api/instances/{name}/update

Applies field and form mappings to an existing instance. It can also set the process status, select the current workflow form and schedule a trigger field.

Path parameter

ParameterTypeDescription
nameStringName of the instance to update.

Request body

One UpdateInstanceRequest object:

PropertyJSON typeDescription
InstanceNameStringName of the instance to update. Use the same instance name as the URL.
FieldsMappingsArray of field mappingsField changes to apply. Uses the same mapping model as create.
TriggerFieldStringField to schedule as a background task.
ExecuteInSeriesString"yes" or "no" for execution of triggered tasks.
StatusStringProcess instance status to set.
FormMappingsArray of form mappingsForm visibility, enabled-state or status changes. See the model below.
CurrentFormNameStringOptional internal form name to set as the current workflow form.

The request supplies the instance name in both the URL and InstanceName. Keep these values identical.

Form mappings

Each InstanceRequestFormMapping targets one form:

PropertyJSON typeDescription
FormNameStringInternal unique name of the form to target.
VisibleBoolean or nullOptional visibility setting: true shows the form; false hides it.
EnabledBoolean or nullOptional enabled setting: true enables the form; false disables it.
StatusStringOptional status to assign to this form.

Omit or use null for form visibility and enabled settings when you are not requesting a change to those flags. Process status, individual form status and the current workflow form are separate settings.

Example: update a field and select the review form

curl --fail-with-body --request PATCH \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42/update" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
    "InstanceName": "incident-report-42",
    "FieldsMappings": [
      {
        "FieldName": "description",
        "Value": "Loading bay handrail isolated pending repair.",
        "Text": "Loading bay handrail isolated pending repair."
      }
    ],
    "FormMappings": [
      {
        "FormName": "review",
        "Visible": true,
        "Enabled": true
      }
    ],
    "CurrentFormName": "review"
  }'

To set statuses, add the process Status at the top level and the form Status inside the relevant FormMappings item. Use accepted status values for the process and form. Selecting CurrentFormName sets the current workflow form; use TriggerField when you also need to schedule background execution.

Success response

Returns 200 OK with a JSON object:

{
  "success": true,
  "instanceID": "incident-report-42"
}
PropertyDescription
successtrue in the successful response.
instanceIDThe InstanceName supplied in the request body.

Update multiple instances

PATCH /api/instances/updateBulk

Applies multiple update requests. Each item has the same structure as Update an instance, including its own InstanceName.

Request body

A top-level JSON array of UpdateInstanceRequest objects:

[
  {
    "InstanceName": "incident-report-42",
    "FieldsMappings": [
      {
        "FieldName": "description",
        "Value": "Handrail repair has been arranged.",
        "Text": "Handrail repair has been arranged."
      }
    ]
  },
  {
    "InstanceName": "incident-report-43",
    "FieldsMappings": [
      {
        "FieldName": "description",
        "Value": "Replacement floor markings have been ordered.",
        "Text": "Replacement floor markings have been ordered."
      }
    ]
  }
]

Save the array as update-requests.json, then submit it:

curl --fail-with-body --request PATCH \
  "${KIANDA_BASE_URL}/api/instances/updateBulk" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data-binary @update-requests.json

The bulk route has no {name} segment. Each item identifies its target using InstanceName.

Success response

Returns 200 OK with a JSON object:

{
  "success": true
}

This success response contains an overall success flag. It does not include instance identifiers, updated documents or individual update results.

Get an instance document

GET /api/instances/{name}

Retrieves the full JSON document for an instance, including its identity, version, forms and fields.

Example

curl --fail-with-body --request GET \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json"

Response

The response is the instance JSON document. The following abbreviated example illustrates its structure; identifier and version strings are placeholders, and additional document properties are omitted.

{
  "id": "example-instance-id",
  "name": "incident-report-42",
  "version": "example-version",
  "forms": [
    {
      "title": "Incident details",
      "name": "incident-details",
      "fields": [
        {
          "name": "description",
          "value": "Loose handrail reported at the loading bay.",
          "text": "Loose handrail reported at the loading bay."
        }
      ]
    }
  ]
}

Use the actual full response when your integration needs an instance document for a later document update. The example above is a structural excerpt, not a complete write payload.

Get instance version information

GET /api/instances/{name}/version

Retrieves modification, version and status information without retrieving the full instance document.

Example

curl --fail-with-body --request GET \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42/version" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json"

Response

A JSON object containing these properties:

PropertyDescription
modifiedThe instance’s modification value, returned from Modified.
versionThe instance’s version, returned from Version.
idThe instance document’s id.
statusThe process instance’s status, returned from Status.

Treat these as server-supplied metadata.

Update using an instance document

PUT /api/instances/{name}

Updates an instance using a Kianda instance JSON document as the request body. Use this endpoint when your integration already handles the document structure, including forms and fields. For targeted changes expressed as mappings, use Update an instance.

Request body

The instance JSON document itself. Preserve its structure and properties that your integration is not intentionally changing.

A typical document-editing sequence is:

  1. Retrieve the instance using GET /api/instances/{name}.
  2. Edit the relevant properties in the returned document.
  3. Send the resulting document to PUT /api/instances/{name} for the same instance.

For example, retrieve the current document into instance.json:

curl --fail-with-body --request GET \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --output instance.json

Check that the request succeeded and the file contains the instance document. After making the intended edits, submit it:

curl --fail-with-body --request PUT \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data-binary @instance.json

Response

The controller returns a JSON document.

Submit an instance document

POST /api/instances

Accepts an instance JSON document directly. Use this route when your integration constructs a valid Kianda instance document. To create an instance from a process design identifier and field mappings, use Create an instance.

Request body

The instance JSON document itself, prepared with the structure required by the process. The abbreviated GET example is not a complete document-creation schema.

Example

Save the prepared document as new-instance.json, then submit it:

curl --fail-with-body --request POST \
  "${KIANDA_BASE_URL}/api/instances" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data-binary @new-instance.json

Response

The controller returns a JSON document.

Delete an instance

DELETE /api/instances/{name}

Deletes the instance identified by its name. No request body is required.

Example

curl --fail-with-body --request DELETE \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json"

Response

The controller returns a JSON document.

Delete multiple instances

POST /api/instances/bulkdelete

Deletes multiple instances in one request.

Request body

A top-level JSON array of strings identifying the instances to delete:

[
  "incident-report-42",
  "incident-report-43"
]

Example

curl --fail-with-body --request POST \
  "${KIANDA_BASE_URL}/api/instances/bulkdelete" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '["incident-report-42", "incident-report-43"]'

The body is the string array itself. The action’s parameter name, instances, is not a JSON wrapper property.

Success response

Returns 200 OK. With Accept: application/json, the response body is a JSON string:

"Completed"

A JSON-aware client parses this response into the string Completed. There is no success property in this response.

Get selected fields

GET /api/instances/{name}/fields

Retrieves selected fields from the instance document. No request body is required.

Parameters

ParameterLocationTypeDescription
namePathStringName of the instance to read.
namesQuery stringStringField selector using internal field names. The action parameter defaults to an empty string when omitted. Specify a field name explicitly for a selective read.

Example: retrieve one field

curl --fail-with-body --get \
  "${KIANDA_BASE_URL}/api/instances/incident-report-42/fields" \
  --header "Authorization: Bearer ${KIANDA_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --data-urlencode "names=description"

This example selects the field whose internal name is description. --data-urlencode encodes the query parameter value.

Response

Returns the selected fields from the instance document.

Response handling

Read the HTTP status and response body for each operation. The successful responses for create, createBulk, the mapping-based single update, updateBulk and bulkdelete all use 200 OK.

Parse the body according to the endpoint. The create and update responses documented above are JSON objects; bulkdelete returns the JSON string "Completed" when JSON is requested. Other response formats are described in their endpoint sections. Error status codes and error response schemas are not specified in this reference.

The source of the instanceID response value is endpoint-specific: create returns result.id, while the mapping-based single update returns request.InstanceName. Use the instance name for routes containing {name}; the create return statement alone does not establish whether its returned identifier is interchangeable with that name.

This reference does not specify bulk atomicity, rollback, item ordering, retry deduplication or per-item error reporting. After an uncertain result, establish what was applied before repeating a write or an entire batch.

3 - Summaries API

Search Kianda instance data, build condition groups, retrieve paged lists, and calculate tile and chart aggregates.

The Summaries API searches the indexed properties of Kianda process instances. It is the central data-access API used by list, tile, chart, and filter widgets to retrieve selected fields and calculate aggregates across large collections of instance documents.

A request describes the process scope, conditions, fields, and result type. Kianda applies the current user’s instance permissions and executes the query against an optimized summary index. A successful HTTP response contains a JSON array; the objects in that array depend on the requested action.

ActionUse it toSuccessful result with data
listRetrieve selected properties from matching instances.An array of summary records.
tileCalculate a count, sum, or average.An array containing one aggregate result, with the populated value in properties.value.
chartGroup records by a field and calculate aggregate series.An array containing a grouped result with properties.labels, properties.values1, and, when configured, properties.values2.

Designers normally compose conditions through Kianda’s conditions editor. The JSON examples in this page explain the resulting API contract and can also be used by external integrations. Page widgets use the same query concepts through Kianda’s client store.

1. How instance data becomes searchable

Kianda stores selected representations of instance fields in shallow, highly indexed tables. This allows a query to search, sort, and aggregate field data without loading every complete instance document.

The index uses these representations:

Indexed representationSourcePurpose
shortTextA short text representation from field.text.Text search, displayed values, and alphabetical sorting.
dateValueThe value of a date field, together with applicable internal date properties.Date comparisons and chronological sorting.
numberValueThe value of a number field.Numeric comparisons, sorting, and aggregation.

A summary is a query result over this indexed data. It is not an editable process model, and changing a returned object does not update the underlying instance. Use the instance’s name with the appropriate Instances API operation when you need to work with the document itself.

What is indexed

Fields outside tables are indexed automatically. This includes fields inside panels and dialogs.

DataSearch coverage
Ordinary instance fields outside tablesAutomatically indexed using the applicable text, date, or number representation.
Fields inside panels and dialogsIndexed in the same way as other fields outside tables.
Cells and fields inside tablesTable contents cannot be addressed by a Summaries search.
Custom field widgetsTheir field.text representation is automatically searchable.
Arbitrary properties inside a custom field’s structured valueThese properties are not independently searchable.
Client-calculated list columns such as ___CUSTOM_FIELD13Calculated by the client and deliberately omitted from server results.

When a custom field needs to participate in searches, maintain a useful field.text representation. Storing a nested object in field.value does not automatically make each nested property queryable.

Indexing is asynchronous

After an instance document is updated, a background job updates its searchable field data. This typically completes in less than a second, but it is asynchronous: an immediately repeated query can briefly return the previous indexed values.

Treat a successful instance save and a refreshed summary result as separate events. If a workflow must confirm the saved document immediately, use the instance operation’s result or retrieve the instance; refresh summary-based views after the index catches up.

Permissions apply to records

The endpoint is available to authenticated users, including ordinary users. Instance permissions apply to all three actions, including the records contributing to counts, sums, averages, and charts.

Field visibility inside a document is a presentation setting. It does not provide field-level API security. Use instance permissions to control access to the record.

2. Endpoint and first request

POST https://{workspace-domain}/api/summaries
Authorization: Bearer {access-token}
Content-Type: application/json
Accept: application/json

Use the workspace’s domain and the authenticated user’s bearer token. See Authentication for token acquisition.

The controller accepts a query in the request body:

[HttpPost]
public async Task<IEnumerable<Models.Summary>> Post(
    [FromBody] Models.Query query)

The following request retrieves the first page of action instances, ordered by their custom ID:

{
  "action": "list",
  "info": {
    "process": "action",
    "queryType": "all",
    "page": 0,
    "sortFieldType": "fields/field-textbox",
    "isOData": true
  },
  "orderBy": "processCustomID",
  "orderAscending": false,
  "fields": [
    "__NAME",
    "__STATUS",
    "processCustomID",
    "ACT_TXTSIN_Desc",
    "ACT_DATE_DueDate"
  ],
  "conditions": [],
  "rowLimit": 30
}

Save the JSON as query.json and send it, for example, with curl:

curl --request POST \
  'https://your-workspace.kianda.com/api/summaries' \
  --header "Authorization: Bearer $KIANDA_ACCESS_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --dump-header response-headers.txt \
  --data-binary @query.json

Set KIANDA_ACCESS_TOKEN to your token before running the command. Replace the process and field names with names present in your workspace. The headers are saved separately because list pagination uses the total-items response header.

For list queries, supply a nonempty fields array. The examples also set the action, page size, relationship filter, and sorting explicitly so their intent is clear.

3. Request reference

Top-level query properties

The server’s Query model exposes the following properties:

PropertyJSON typePurpose
actionStringResult type: list, tile, or chart.
infoObjectProcess scope and action-specific settings. The server model uses JObject.
fieldsArray of stringsField and system-property names requested from indexed storage. Required for list queries. See field projection for automatically added properties.
conditionsArray of condition groupsStructured query conditions. Use [] when no explicit conditions are needed.
orderByStringField or system-property name used to sort a list.
orderAscendingBooleantrue for ascending order; false for descending order.
rowLimitIntegerMaximum row count the request asks the server to load. Use a positive value. A value of 0 is converted to 1.
filterStringText to search for using the separate text-filter facility.
filterByStringField or system-property name searched by filter.
filterModeStringText-filter mode. See text filters.
idStringPresent in the shared server model; not used by the request patterns on this page. List-widget result identity uses info.id.
pagingStringPresent in the shared server model; not used by the page-number workflow on this page. List pagination uses info.page and the total-items header.

There is no fixed upper limit for rowLimit in the described implementation. Larger row counts and more requested fields increase the amount of work and data transferred. Use bounded pages for interactive lists.

The tile and chart examples retain the row limits used by those request patterns. Do not interpret a tile’s rowLimit: 1 as a documented instruction to aggregate only one instance.

PropertyTypePurpose
processStringOne process’s unique name. If blank or omitted, the query can search across processes accessible to the user.
queryTypeStringAdditional relationship filter: all, assignedTo, createdBy, or modifiedBy.
pageIntegerZero-based list page. 0 is the first page; 1 is the second.
isListWidgetBooleanEnables list-widget result identities that isolate cached summaries by widget.
idStringThe widget identifier used with isListWidget; also appears as the result identifier in the chart examples.
isODataBooleanEnables additional typed or related field properties, such as date _utc, numeric _number, and user _email properties. It does not change the JSON body into an OData response envelope.
sortFieldTypeStringSelects the indexed representation used for sorting: text, date, or number.
additionalSortingsArrayAdditional sorting configuration carried by built-in list widgets. The examples here use a single explicit sort and do not define a descriptor format for additional sorts.
isFilterWidgetBooleanEnables filter-widget-specific result identities to avoid client-store identity collisions.
filterWidgetIdStringIdentifies the filter widget when isFilterWidget is used.

Tile-specific properties are described in Tile queries. Chart-specific properties are described in Chart queries.

processSource and isPartner are deprecated and should be omitted from new Summaries requests, even if they appear in older widget code.

Query type and user relationships

queryType adds a relationship filter to the query’s matching conditions and instance permissions:

ValueMeaning
allRecords matching the conditions that the current user can access.
assignedToMatching records assigned to the current user.
createdByMatching records created by the current user.
modifiedByMatching records modified by the current user.

For example, use assignedTo to build a “My actions” list. Use all for matching records regardless of those particular relationships, while retaining normal instance permissions.

Query across specific processes

Set info.process to a process name to restrict a query to that process. To select several specific processes, leave info.process blank or omit it and add conditions on __PROCESS_NAME, joined with or.

This condition group selects action or observation instances:

[
  {
    "id": "process-filter",
    "group": "and",
    "conditions": [
      {
        "operator": "eq",
        "arg1": {
          "name": "__PROCESS_NAME",
          "type": "__Field"
        },
        "arg2": {
          "text": "action",
          "type": "text"
        },
        "group": "or"
      },
      {
        "operator": "eq",
        "arg1": {
          "name": "__PROCESS_NAME",
          "type": "__Field"
        },
        "arg2": {
          "text": "observation",
          "type": "text"
        },
        "group": "or"
      }
    ]
  }
]

This is a conditions fragment, not a complete request. Request the field names needed for the selected processes and handle properties that are absent from a particular record.

4. List query example

The following request selects actions whose status is Follow-up. It includes the list-widget identity settings used by Kianda’s built-in list widget.

{
  "action": "list",
  "info": {
    "process": "action",
    "id": "b84cb3d7-7638-481e-98ac-a35b52ddc2da",
    "isListWidget": true,
    "queryType": "all",
    "page": 0,
    "sortFieldType": "fields/field-textbox",
    "isOData": true
  },
  "orderAscending": false,
  "orderBy": "processCustomID",
  "fields": [
    "__NAME",
    "__STATUS",
    "__CREATED_BY",
    "processCustomID",
    "ACT_TXTSIN_Desc",
    "ACT_DATE_DueDate",
    "ACT_USER_ResponsibleUsers"
  ],
  "conditions": [
    {
      "id": "follow-up-filter",
      "group": "and",
      "conditions": [
        {
          "operator": "eq",
          "arg1": {
            "text": "Status",
            "name": "__STATUS",
            "type": "__Field"
          },
          "arg2": {
            "text": "Follow-up",
            "type": "text"
          },
          "group": "and"
        }
      ]
    }
  ],
  "rowLimit": 30
}

The following response excerpt shows one representative row, with example display text and user details. A real page can contain up to the requested number of records.

[
  {
    "id": "ef0d79ba-49dd-4cd3-8e65-747fefb2fbd0-b84cb3d7-7638-481e-98ac-a35b52ddc2da",
    "name": "ef0d79ba-49dd-4cd3-8e65-747fefb2fbd0",
    "assignTo": [],
    "owners": [],
    "status": "Follow-up",
    "processName": "action",
    "modified": "2026-09-30T13:15:51.547+00:00",
    "created": "2026-09-30T13:14:02.103+00:00",
    "createdBy": "049e635c-6ac8-4d47-a16d-edab750a8103",
    "properties": {
      "__NAME": "ef0d79ba-49dd-4cd3-8e65-747fefb2fbd0",
      "__STATUS": "Follow-up",
      "__CREATED_BY": "049e635c-6ac8-4d47-a16d-edab750a8103",
      "__PROCESS_NAME": "action",
      "__CREATED": "2026-09-30T13:14:02.103",
      "__MODIFIED": "2026-09-30T13:15:51.547",
      "processCustomID": "ACT_2026_00143",
      "ACT_TXTSIN_Desc": "Clear standing water near the access route",
      "ACT_DATE_DueDate": "30/09/2026",
      "ACT_DATE_DueDate_utc": "2026-09-29T23:00:00",
      "ACT_USER_ResponsibleUsers": "Example User",
      "ACT_USER_ResponsibleUsers_email": "example.user@example.com"
    }
  }
]

When no list records match, the response body is:

[]

Use name for instance operations

With info.isListWidget: true, a list result’s identity is constructed using the instance name and widget ID:

Summary.id = Summary.name + "-" + info.id

This allows multiple list widgets on the same page to cache their results independently in IndexedDB. Two widgets can display the same instance with different projected fields without sharing the same summary-record identity.

Use Summary.name when an action needs to retrieve, open, update, or otherwise address the underlying instance. Do not split the composite id: instance names can themselves contain hyphens, and they are not always GUIDs.

5. List results and field projection

Summary model properties

The server’s Summary model has the following properties. Their presence depends on the action and available data; tile and chart results use only a subset of this model.

PropertyJSON typeMeaning
idStringSummary result identity. It may include a widget-specific suffix.
nameStringUnderlying instance identifier used for instance operations.
titleString or nullTitle metadata, when supplied.
assignToArray of strings or nullAssignment information.
ownersArray of strings or nullOwnership information.
statusStringInstance status.
versionString or nullInstance version metadata.
processNameString or nullProcess name.
modifiedDate/time string or nullInstance modification time.
createdDate/time string or nullInstance creation time.
createdByString or nullCreator identifier.
modifiedByString or nullModifier identifier.
propertiesObjectProjected field values, system properties, or action-specific aggregate data.

Optional members can be omitted from the serialized response. The list example does not include every property declared by the model. Consumers should read the properties relevant to their action rather than requiring every model member to exist.

Requested fields and automatically added properties

The fields array identifies data to retrieve from summary storage. The result may also contain system properties and companion values.

These system properties are automatically included in every list result’s properties dictionary for offline sorting and filtering:

  • __NAME
  • __PROCESS_NAME
  • __CREATED
  • __MODIFIED

Other selected system properties can appear both as top-level summary metadata and in properties. For example, an explicitly requested __STATUS can accompany the top-level status.

With info.isOData: true, additional properties can include:

Example propertyPurpose
ACT_DATE_DueDateDisplay text for the selected date field.
ACT_DATE_DueDate_utcIts UTC date representation, useful for sorting and data processing.
<number-field>_numberNumeric companion data.
ACT_USER_ResponsibleUsersDisplay text for the selected user field.
ACT_USER_ResponsibleUsers_emailRelated email information.

Do not assume that a companion key is present for every empty field. A blank date field can appear as "" without an accompanying _utc property, while a blank user field can also have an empty _email property.

Date display strings and typed companion strings serve different purposes. For example, 30/09/2026 is display text, while the sample _utc value is 2026-09-29T23:00:00. The sample’s _utc string has no explicit timezone suffix; preserve its UTC meaning deliberately when converting it in a client, rather than relying on ambiguous automatic date parsing.

Field names are exact storage names

Use field names as stored by the process designer. Names containing characters such as ? are preserved, including:

ACT_LSTSIN_Priority?inlineButtons
OBS_LSTSIN_TopicType?radioCards

Do not remove the suffix or treat it as a URL query string. Use bracket access for such property names:

const priority = summary.properties["ACT_LSTSIN_Priority?inlineButtons"];

A ___CUSTOM_FIELD* entry refers to a client-calculated list column. It can appear in widget configuration but is deliberately omitted from the API response. The widget calculates that column after loading the server data.

System-property names

These are the internal system-field identifiers available to the query model:

IdentifierRepresents
__NAMEInstance name used to address the instance.
__UNIQUE_IDInternal unique-ID property. Use name for the instance operations described on this page.
__PROCESS_NAMEProcess name.
__PROCESS_TITLEProcess title.
__STATUSInstance status.
__VERSIONInstance version.
__PROCESS_VERSIONProcess version.
__CREATEDCreation date/time.
__CREATED_BYCreator.
__MODIFIEDModification date/time.
__MODIFIED_BYModifier.
__ASSIGN_TOAssignment information.
__SECURITY_USERSInstance security-user information.

Use type: "__Field" when a condition argument refers to one of these system fields. Selectors generated by the conditions editor supply the appropriate metadata.

6. Condition groups and query operators

The conditions property contains groups of conditions. Each group represents parentheses in the generated query expression.

There is one level of groups: a group contains conditions, and a condition cannot contain another group.

StructurePropertyMeaning
Condition groupconditionsArray of conditions inside this group.
Condition groupgroupand or or connector between groups.
Condition groupidEditor identity included when groups are serialized.
ConditionoperatorExact operator identifier.
Conditionarg1Left-hand field or system-property reference.
Conditionarg2Comparison input or prepared date boundaries, when required.
Conditiongroupand or or connector between conditions within the group.
ConditionidEditor identity included when conditions are serialized.

The condition and condition-group UI models default their group property to and. Preserve the serialized connectors emitted by the editor.

For example, a process group joined internally with or, followed by a status group joined internally with or, can express:

(process is action OR process is observation)
AND
(status is Follow-up OR status is Open)

Use the editor to construct mixed conditions and grouping. Do not add a nested group object where an individual condition is expected.

Argument references

Argument types distinguish form fields, system fields, and literal text:

typeMeaningTypical argument
fieldA form-field reference.{"name":"ACT_DATE_DueDate","type":"field","fieldType":"fields/field-date"}
__FieldA system-property reference.{"name":"__STATUS","type":"__Field"}
textLiteral text.{"text":"Follow-up","type":"text"}

For a field reference, name selects the indexed field. Its optional text is the selector’s display label, not the field’s current contents. fieldType supplies type metadata for operations that need it.

Date ranges use arg2.date1 and arg2.date2. The conditions editor supplies the appropriate argument representation for the selected control; retain that representation for numeric, boolean, and other typed comparisons rather than substituting an invented argument schema.

Comparison, text, blank, and membership operators

Operator identifiers are listed with their exact spelling.

OperatorUI labelBehaviour
eqEqualsEquality comparison.
neqNot equalsInequality comparison.
containsContainsText contains the supplied value.
startsWithStarts withText begins with the supplied value.
gtGreater thanGreater-than comparison.
gteGreater or equalGreater-than-or-equal comparison.
ltLess thanLess-than comparison.
lteLess or equalLess-than-or-equal comparison.
isblankIs blankSQL null or blank check.
notblankNot blankComplementary nonblank check.
matchMatches patternSQL LIKE pattern matching.
nomatchDoes not match patternSQL NOT LIKE pattern matching.
IsUserOrMemberIs Current User Or MemberCompares a user-picker field with the current user or the user’s groups. Uses the authenticated user context; no arg2 is required.

String comparisons use case-insensitive SQL comparison. This describes comparison of field data; it does not establish case-insensitive spelling for property names, operators, or other API option values.

Date operators

OperatorUI label
isTodayIs Today
isBeforeTodayIs Before Today
isAfterTodayIs After Today
isThisWeekIs This Week
isPrevWeekIs Previous Week
isNextWeekIs Next Week
isThisMonthIs This Month
isPrevMonthIs Previous Month
isNextMonthIs Next Month
isThisYearIs This Year
isPrevYearIs Previous Year
isNextYearIs Next Year
isBetweenDatesIs Between Days

Date conditions require the client-side preparation described next. Relative operator names alone do not replace that preparation.

7. Prepare date conditions before sending

Kianda prepares date conditions on the client so date selections can use client location awareness together with the workspace’s regional settings.

The helper used by the built-in list widget is:

this.get("ruleEngine").parseDateConditions(conditions);

It is called before the same conditions object is included in the request. Use this side-effect-based calling pattern; the built-in list integration does not use a returned array or await a Promise from this helper.

Relative selections such as “Is Before Today” or “Is This Year” are resolved to explicit UTC boundaries in arg2.date1 and arg2.date2. The posted query can retain its original relative operator name alongside those prepared boundaries.

For example, this condition was prepared for a query on 20 October 2026:

{
  "operator": "isBeforeToday",
  "arg1": {
    "text": "Due date",
    "name": "ACT_DATE_DueDate",
    "type": "field",
    "fieldType": "fields/field-date"
  },
  "arg2": {
    "name": "",
    "date1": "1926-10-20T21:42:28.679Z",
    "date2": "2026-10-19T22:59:59.000Z"
  },
  "group": "and"
}

These are captured example boundaries, not reusable constants for every overdue query. Recompute relative dates before issuing a new request.

A custom integration can copy the serialized settings before resolving dates:

const savedConditions = this.get("widget.settings.conditions") || [];
const conditions = JSON.parse(JSON.stringify(savedConditions));

this.get("ruleEngine").parseDateConditions(conditions);

This fragment assumes the component already has access to the rule engine. The copy is appropriate because serialize=true stores plain objects in settings; resolving dates in the request copy avoids rewriting the persistent configuration.

An external REST client does not have access to the Ember helper. It must prepare explicit UTC date boundaries itself for the intended regional/calendar period. Use isBetweenDates for an explicitly selected range, as demonstrated by the tile example. Avoid hard-coding one UTC offset for all dates, since the relevant offset can vary over the calendar.

8. Pagination and sorting

Pagination uses a response header

List requests use:

  • info.page: the zero-based page index.
  • rowLimit: the requested page size.
  • The total-items response header: the total number of matching items.

The JSON body remains an array of summaries. There is no meta or totalItems object added to the raw REST body.

For the second page of the first-request example, keep its query settings and change:

query.info.page = 1;

Given a parsed totalItems header and a query with an explicit page size:

const pageSize = query.rowLimit === 0 ? 1 : query.rowLimit;
const currentPage = query.info.page;

const pageCount = totalItems === null
  ? null
  : Math.ceil(totalItems / pageSize);

const hasNextPage = totalItems === null
  ? null
  : (currentPage + 1) * pageSize < totalItems;

In this client example, null means the total header was not available; it is not a zero-result count.

For example, a total of 75 items with rowLimit: 30 gives three pages:

info.pageUser-facing pageExpected items, if the matching data stays unchanged
0130
1230
2315

Reset the page to 0 when changing the process scope, conditions, relationship filter, or search text. Refresh the total count with the new results.

Choose the correct sort representation

orderBy identifies the field. orderAscending chooses the direction. info.sortFieldType determines which indexed representation SQL uses.

info.sortFieldTypeSort representation
Omitted, empty, or an ordinary text-field typeAlphabetical sorting by shortText.
DateTimeChronological sorting by the indexed date value.
fields/field-dateChronological sorting by the indexed date value.
NumberNumeric sorting by the indexed number value.
fields/field-numberNumeric sorting by the indexed number value.

For example, the following request fragment selects an ascending numeric sort:

{
  "orderBy": "DATAMS_NUM_EmployeeHours",
  "orderAscending": true,
  "info": {
    "sortFieldType": "fields/field-number"
  }
}

Merge these settings into the complete query; this fragment does not include the remaining request properties.

Without the number type, displayed values such as "10" and "2" are sorted as text. Similarly, sorting formatted display dates alphabetically is different from chronological date sorting.

The built-in list widget obtains the sort type from the selected field’s fieldType or type. Carry that metadata through when users change the sort field.

9. Text filters

The separate text-filter properties let a client search a named field without constructing a condition group for the text search:

PropertyExampleMeaning
filter"fra"Search text.
filterBy"country"Field to search; system-property names are also supported.
filterMode"contains"Search mode.

The following filter-widget-style request searches country text in observation instances:

{
  "action": "list",
  "info": {
    "process": "observation",
    "page": 0,
    "isFilterWidget": true,
    "filterWidgetId": "41ad30c0-103f-49cb-b251-ffc10479a40d",
    "isOData": true
  },
  "fields": [
    "country",
    "processCountryCode"
  ],
  "conditions": [],
  "filter": "fra",
  "filterBy": "country",
  "filterMode": "contains",
  "rowLimit": 500,
  "orderAscending": false
}

Prefix matching is also supported. A captured prefix-search request from the built-in filter widget uses "filterMode": "startswith". Preserve the emitted mode spelling when reusing filter-widget configuration. This setting is separate from the condition operator named startsWith.

For explicitly grouped text logic, use the contains, startsWith, match, or nomatch condition operators through the conditions editor.

10. Tile queries

Tile queries calculate a single aggregate.

info.tileAggregateField requirement
countCount matching instances.info.field is not required.
sumSum a number field across matching data.Select a number field.
avgAverage a number field across matching data.Select a number field.

For sum and average tiles, the built-in configuration UI restricts field selection to fields/field-number.

Count matching instances

This request counts action instances assigned to the current user:

{
  "action": "tile",
  "info": {
    "process": "action",
    "queryType": "assignedTo",
    "tile": "count"
  },
  "conditions": [],
  "rowLimit": 1
}

The instance permissions and relationship filter apply to the records being counted. A count tile does not require an expression field.

Sum a number field over a date range

This request sums employee hours using explicitly prepared UTC date boundaries:

{
  "action": "tile",
  "info": {
    "process": "hours-worked-data",
    "field": "DATAMS_NUM_EmployeeHours",
    "queryType": "all",
    "tile": "sum"
  },
  "fields": [
    "DATAMS_NUM_EmployeeHours"
  ],
  "conditions": [
    {
      "id": "date-filter-group",
      "group": "and",
      "conditions": [
        {
          "operator": "isBetweenDates",
          "arg1": {
            "name": "processDate",
            "type": "field",
            "fieldType": "fields/field-date"
          },
          "arg2": {
            "date1": "2026-09-30T23:00:00.000Z",
            "date2": "2026-10-31T23:59:59.999Z"
          },
          "group": "and"
        }
      ]
    }
  ],
  "rowLimit": 1
}

Example response:

[
  {
    "properties": {
      "value": 1249.92
    }
  }
]

Read the aggregate from the result object’s properties.value. Do not expect the instance metadata shown in a list response to accompany an aggregate result.

For an average, use "tile": "avg" with the appropriate number field and conditions.

Handle an absent aggregate

Tile consumers must handle both an empty result array and a returned result with no usable aggregate value. A missing aggregate is different from a numeric zero.

This helper reads the confirmed populated-value shape while retaining an explicit no-value state:

function getTileValue(summaries) {
  const result = summaries && summaries[0];
  const properties = result && result.properties;

  if (!properties ||
      !Object.prototype.hasOwnProperty.call(properties, "value")) {
    return null;
  }

  return properties.value;
}

A legitimate value of 0 is preserved. The caller can display a no-data state for null instead of silently reporting a zero.

11. Chart queries

Chart queries group matching records by a field and calculate series values for those groups. Kianda’s built-in chart widgets render the resulting datasets using Chart.js.

info propertyPurpose
labelsField whose values form the groups and returned labels.
field1Field used by the first aggregate series.
exp1First series’ aggregation expression. The examples use Count.
field2Optional field for a second series.
exp2Second series’ aggregation expression. A second field is also required.
idIdentifier returned with the chart result in the examples.
chartTypeChart configuration; the examples use pie and bar.
sortLabelsLabel-sorting configuration from the chart settings; the examples use desc.
labelFormatLabel-formatting configuration from the chart settings; the examples use text.

In query terms, labels supplies the grouping field, while each selected series field supplies values for its aggregate. Chart aggregation supports count, sum, and average. Preserve the expression values emitted by the chart settings; the requests below use the Count spelling emitted by the built-in chart settings.

Include the grouping and series field names in fields. The same field can appear more than once when it is used for both labels and a series, as in the built-in requests below.

One series: observations by topic

{
  "action": "chart",
  "info": {
    "process": "observation",
    "queryType": "all",
    "chartType": "pie",
    "labels": "OBS_LSTSIN_TopicType?radioCards",
    "field1": "OBS_LSTSIN_TopicType?radioCards",
    "exp1": "Count",
    "id": "c4e6c595-12a9-4641-908f-8418e15dbe2e",
    "sortLabels": "desc",
    "labelFormat": "text"
  },
  "fields": [
    "OBS_LSTSIN_TopicType?radioCards",
    "OBS_LSTSIN_TopicType?radioCards"
  ],
  "conditions": [],
  "rowLimit": 30
}

Example response:

[
  {
    "id": "c4e6c595-12a9-4641-908f-8418e15dbe2e",
    "properties": {
      "labels": [
        "Unsafe observation",
        "Positive observation",
        "Improvement idea"
      ],
      "values1": [
        6,
        2,
        1
      ]
    }
  }
]

Values correspond by array position: labels[0] identifies the group for values1[0]. Keep labels and all series aligned when transforming or rendering the data.

Two series

A second series requires field2 as well as its expression. An exp2 property by itself does not create values2.

{
  "action": "chart",
  "info": {
    "process": "observation",
    "queryType": "all",
    "chartType": "bar",
    "labels": "processProject",
    "field1": "processProject",
    "field2": "OBS_YN_SWAUsed",
    "exp1": "Count",
    "exp2": "Count",
    "id": "3d1e106e-59cd-4712-91f1-e78135552783",
    "sortLabels": "desc",
    "labelFormat": "text"
  },
  "fields": [
    "processProject",
    "processProject",
    "OBS_YN_SWAUsed"
  ],
  "conditions": [],
  "rowLimit": 30
}

With both series configured, consume properties.values1 and properties.values2 alongside the shared properties.labels.

When no usable chart properties are found, the chart data contains empty label and value arrays. Consumers should also tolerate an empty result array before attempting to access its first item.

12. Build conditions in the Kianda UI

The reusable conditions editor is:

{{rules/rule-conditions
  showProcessProperties=true
  isCompact=true
  btnText=""
  serialize=true
  conditions=this.widget.settings.conditions
  process=this.process}}
Binding or optionRole in this integration
showProcessProperties=trueMakes process/system properties available to the conditions editor.
isCompact=trueUses the compact editor presentation.
btnText=""Sets the editor button-text option.
serialize=trueSerializes condition groups to plain objects suitable for the settings hash.
conditionsBinds the saved condition groups to widget.settings.conditions.
processSupplies the process metadata used to select fields.

serialize=true does not mean the HTTP request should contain a JSON string inside conditions. It means the settings contain plain objects that can be included as an array in the query JSON.

The built-in list refresh flow:

  1. Reads the saved conditions and the selected fields.
  2. Resolves date boundaries using ruleEngine.parseDateConditions(conditions).
  3. Maps the selected fields to their stored names.
  4. Builds the query, including info.process, info.page, and sort metadata.
  5. Calls store.query("summary", query) for instance summary data.

The following fragment shows that query-construction path. It assumes the component has the same widget, fields, rule-engine, and store context as the built-in list integration; it is not a complete page-widget component.

const savedConditions = this.get("widget.settings.conditions") || [];
const conditions = JSON.parse(JSON.stringify(savedConditions));
const fieldNames = this.get("fields").mapBy("name");
const pageSize = Number(this.get("widget.settings.pageSize"));

if (fieldNames.length === 0) {
  throw new Error("Select at least one field for the list query.");
}

if (!Number.isInteger(pageSize) || pageSize < 1) {
  throw new Error("Configure a positive whole-number page size.");
}

this.get("ruleEngine").parseDateConditions(conditions);

const query = {
  action: "list",
  info: {
    process: this.get("widget.settings.processName"),
    id: this.get("widget.id"),
    isListWidget: true,
    queryType: this.get("widget.settings.queryType") || "all",
    page: 0,
    isOData: true
  },
  fields: fieldNames,
  conditions: conditions,
  rowLimit: pageSize
};

const pending = this.get("store").query("summary", query);

The full list implementation also handles cached results, a possible pending.onlinePromise, and subsequent record synchronization. Those are Kianda client-store behaviours. They are separate from the raw HTTP response, which contains an array plus the total-items header for lists.

Similarly, data.meta in widget code is client-side metadata. A direct REST consumer should read the HTTP header rather than expect data.meta in the returned JSON.

The built-in list client adds preferOnline before calling the store. This is absent from the server Query model, so the direct REST examples omit it. The separate datasource branch in the full refresh function calls dataService.queryFromWidget; it is not the instance-summary request path described here.

Page filter widgets can also generate conditions dynamically. Prepare the final conditions for the current request, including current date boundaries, before loading the results. Page-widget lifecycle, refresh coordination, and filter wiring belong in the page-widget development guide.

13. Call the API from JavaScript

This standalone HTTP helper sends a query, checks for an HTTP error, validates the array response, and reads the optional list count.

async function findSummaries(workspaceUrl, accessToken, query) {
  const endpoint = new URL("/api/summaries", workspaceUrl);

  const response = await fetch(endpoint, {
    method: "POST",
    headers: {
      Authorization: "Bearer " + accessToken,
      "Content-Type": "application/json",
      Accept: "application/json"
    },
    body: JSON.stringify(query)
  });

  const responseText = await response.text();

  if (!response.ok) {
    const error = new Error(
      "Summaries request failed (HTTP " + response.status + ")."
    );
    error.status = response.status;
    error.responseBody = responseText;
    throw error;
  }

  const summaries = JSON.parse(responseText);

  if (!Array.isArray(summaries)) {
    throw new Error("Expected a JSON array from the Summaries API.");
  }

  const totalHeader = response.headers.get("total-items");
  const parsedTotal = totalHeader === null || totalHeader.trim() === ""
    ? NaN
    : Number(totalHeader);

  const totalItems = Number.isSafeInteger(parsedTotal) && parsedTotal >= 0
    ? parsedTotal
    : null;

  return { summaries, totalItems };
}

{ summaries, totalItems } is the helper’s own return value; it is not the server’s JSON envelope. Read summaries according to the requested action. Tile and chart consumers should not depend on a list count header.

The helper preserves a zero count and leaves a missing or invalid count as null. It also retains the actual error response text without assuming a particular HttpError JSON property name.

14. Errors, performance, and troubleshooting

Error handling

On failure, the API returns an HTTP error instead of a successful summary array. Check the HTTP response status before interpreting the body as list or aggregate data.

The failure is logged under support/logs, using the category:

Instance | Summary find(Query)

Use the request’s action, process scope, selected fields, prepared conditions, and error response to investigate the failure. An empty successful query result is different from a failed request; do not convert an HTTP error into an empty list or a zero-valued tile.

Keep queries focused

The summary index is designed for fast searching across large collections, including hundreds of thousands of instance documents. Query cost still depends on the scope, requested properties, conditions, and amount of data returned.

  • Set info.process when the data belongs to one process.
  • Select the fields needed by the view.
  • Use a bounded rowLimit and page through lists.
  • Use a tile or chart action when the required output is an aggregate.
  • Include the correct sort type for numbers and dates.
  • Recompute relative date conditions when refreshing.
  • Account for the short asynchronous indexing interval after a save.

Troubleshooting reference

SymptomWhat to check
A recently saved value is not visible in a queryAllow for the asynchronous indexing job, then refresh the summary query.
A table-cell value cannot be foundTable contents are outside Summaries search coverage.
A custom field’s nested property cannot be foundCustom fields expose their field.text representation; arbitrary nested value properties are not independently indexed.
An expected calculated list column is absent___CUSTOM_FIELD* columns are computed by the client.
Numbers sort as 10, 2Supply Number or fields/field-number as info.sortFieldType.
Dates sort by their displayed charactersSupply DateTime or fields/field-date as the sort type.
An instance action cannot find the returned itemUse summary.name, not a widget-specific summary.id.
One list widget appears to reuse another widget’s summary dataCheck isListWidget and the distinct widget info.id values.
A pager cannot find the total in the JSON bodyRead the total-items response header.
A request with rowLimit: 0 returns one rowZero is normalized to one; use an explicit positive page size.
A relative date filter keeps using old boundariesRun parseDateConditions before sending the current query.
A chart has no second seriesConfigure both field2 and exp2.
A tile displays zero when no aggregate is availablePreserve a missing-value state instead of using a truthiness fallback.
Users see different list or aggregate resultsCheck instance permissions, queryType, conditions, and the current indexed data.
A hidden form field remains queryableField visibility is a document presentation setting; record access is controlled by instance permissions.
The request failsCheck the HTTP error response and the summary-query category in support/logs.

Verify an integration

Start with a known instance and a small field selection. Confirm its name, requested properties, and typed sort order. Then test the next page, an empty list, a populated and empty aggregate, and the relevant date filters.

Verify the intended results under the users who will run the integration, because both instance permissions and relationship filters affect the results. When a test updates an instance, allow for indexing before comparing the saved document with a summary query.