Docs › API reference › Farm books & tasks

Farm books & tasks

The farm's custom books (logs, inventory, costs…), calendar and automation rules: read tables, read/add/edit rows.

57 operations · base /api/v1/office

GET/api/v1/office/apps

List apps (paginated)

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
pageintqueryno—
pageSizeintqueryno—
searchstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/apps" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "hasNextPage": true,
  "hasPreviousPage": true,
  "items": [
    {
      "createdAt": "2026-10-28T07:30:00Z",
      "description": "…",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "name": "…",
      "updatedAt": "2026-10-28T07:30:00Z"
    }
  ],
  "page": 1,
  "pageSize": 1,
  "totalCount": 1,
  "totalPages": 1
}
GET/api/v1/office/apps/{appId}/dashboards

List dashboards of an app

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
appIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/apps/<appId>/dashboards" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "appId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "createdAt": "2026-10-28T07:30:00Z",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "layout": {
      "filters": [
        {
          "id": "…",
          "kind": "…",
          "label": "…",
          "targets": [
            null
          ]
        }
      ],
      "widgets": [
        {
          "aggregation": "…",
          "columns": [
            null
          ],
          "compare": "…",
          "dateField": "…",
          "dateGrouping": "…",
          "filter": {
            "conditions": null,
            "conjunction": null,
            "groups": null,
            "hasCriteria": null
          },
          "format": {
            "decimals": null,
            "prefix": null,
            "style": null,
            "suffix": null
          },
          "groupField": "…",
          "h": 1,
          "id": "…",
          "limit": 1,
          "orientation": "…",
          "seriesField": "…",
          "sort": "…",
          "stacked": true,
          "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "target": 1.5,
          "text": "…",
          "title": "…",
          "type": "…",
          "valueField": "…",
          "w": 1,
          "x": 1,
          "y": 1
        }
      ]
    },
    "name": "…",
    "position": 1,
    "updatedAt": "2026-10-28T07:30:00Z"
  }
]
GET/api/v1/office/apps/{appId}/tables

List tables of an app

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
appIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/apps/<appId>/tables" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "appId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "name": "…",
    "position": 1
  }
]
GET/api/v1/office/apps/{appId}/tables/{tableId}

Get a table

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
appIdGUIDpathyes—
tableIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/apps/<appId>/tables/<tableId>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "appId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "name": "…",
  "position": 1
}
GET/api/v1/office/apps/{id}

Get an app

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/apps/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "createdAt": "2026-10-28T07:30:00Z",
  "description": "…",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "name": "…",
  "updatedAt": "2026-10-28T07:30:00Z"
}
GET/api/v1/office/automation-logs

Run log, newest first

`result` filters by CODE: success · skipped · failed. Omit to return all results.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
automationIdGUIDqueryno—
resultstringqueryno—
pageintqueryno—
pageSizeintqueryno—
enrollmentIdGUIDqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automation-logs" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "items": [
    {
      "automationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "detail": "…",
      "detailKey": "…",
      "enrollmentId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "result": "…",
      "runAt": "2026-10-28T07:30:00Z",
      "stepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "subjectId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    }
  ],
  "page": 1,
  "pageSize": 1,
  "total": 1
}
GET/api/v1/office/automation-logs/metrics

Operational metrics for Automation in the company

Within `days` days (1–90): row counts by result, `failureRate`, `quotaBlocked` (number of times skipped due to the monthly run quota being exhausted), the monthly quota, and the queue: `activeRuns`, `dueRuns` (due but not yet picked up by the runner), `oldestDueSeconds` (how long the oldest due run has been waiting).

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
daysintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automation-logs/metrics" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "activeRuns": 1,
  "days": 1,
  "dueRuns": 1,
  "failed": 1,
  "failureRate": 1.5,
  "oldestDueSeconds": 1,
  "quota": {
    "limit": 1,
    "month": "…",
    "percent": 1.5,
    "used": 1
  },
  "quotaBlocked": 1,
  "skipped": 1,
  "success": 1,
  "total": 1
}
GET/api/v1/office/automation-logs/runs

History by RUN, newest first

A run = one data row passing through the rule once (grouped by `enrollmentId`). Each run: start/end, step count, failed/skipped/done counts and an overall `result` (failed > success > skipped). Open a run's details: `GET /automation-logs?enrollmentId=`. Server-side filters: `result` (success|failed|skipped|running) · `createdBy` (me|user ID — the rule's creator) · `from`/`to` (run start time, inclusive) · `search` (rule name, or exact run/row/rule ID).

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
automationIdGUIDqueryno—
pageintqueryno—
pageSizeintqueryno—
resultstringqueryno—
createdBystringqueryno—
fromdatequeryno—
todatequeryno—
searchstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automation-logs/runs" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "items": [
    {
      "automationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "automationName": "…",
      "endedAt": "2026-10-28T07:30:00Z",
      "enrollmentId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "failed": 1,
      "result": "…",
      "skipped": 1,
      "startedAt": "2026-10-28T07:30:00Z",
      "status": "…",
      "steps": 1,
      "subjectId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "subjectName": "…",
      "succeeded": 1
    }
  ],
  "page": 1,
  "pageSize": 1,
  "total": 1
}
GET/api/v1/office/automation-logs/stats

The four stat tiles at the top of the log screen

Counts per result CODE over the last `days` days (1–90).

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
automationIdGUIDqueryno—
daysintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automation-logs/stats" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "failed": 1,
  "skipped": 1,
  "success": 1,
  "total": 1
}
GET/api/v1/office/automation-templates

List the company's templates, newest first

`steps` is an ordered summary (step type + action) so the template gallery can show a line like "Send message → Wait → Branch".

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automation-templates" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "createdAt": "2026-10-28T07:30:00Z",
    "createdBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "description": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "name": "…",
    "sourceAutomationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "stepCount": 1,
    "steps": [
      {
        "actionType": "…",
        "stepType": "…"
      }
    ],
    "triggerConfig": "…",
    "triggerType": "…"
  }
]
GET/api/v1/office/automations

Danh sách automation

Paginated at the database. Filters: `status` (`active`·`inactive`·`draft`·`paused`·`archived`) · `failing=true` (has failed runs in the last 7 days) · `triggerType` · `createdBy` (`me` or user ID) · `tableId` · `actionType`; sort: `sort` (`updated`·`created`·`creator`·`name`, default `created`). Each row includes `stepCount`, `lastRunAt`, `runs7d`, `failed7d`, `createdById`, `createdByName`, `updatedAt`, `triggerConfig`, `stepActionTypes[]` — `steps` is left empty and loaded only when opening the details.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
pageintqueryno—
pageSizeintqueryno—
searchstringqueryno—
statusstringqueryno—
triggerTypestringqueryno—
createdBystringqueryno—
tableIdGUIDqueryno—
actionTypestringqueryno—
sortstringqueryno—
failingboolqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "hasNextPage": true,
  "hasPreviousPage": true,
  "items": [
    {
      "createdBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "createdById": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "createdByName": "…",
      "description": "…",
      "failed7d": 1,
      "graphVersion": 1,
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "lastRunAt": "2026-10-28T07:30:00Z",
      "name": "…",
      "parentAutomationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "parentStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "runs7d": 1,
      "source": "…",
      "status": "…",
      "stepActionTypes": [
        "…"
      ],
      "stepCount": 1,
      "steps": [
        {
          "actionType": "…",
          "branchIndex": 1,
          "branchLabel": "…",
          "conditionConfig": "…",
          "config": "…",
          "falseNextStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "groupId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "groupKind": "…",
          "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "loopAutomationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "name": "…",
          "nextStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "order": 1,
          "splitRatio": 1,
          "stepType": "…",
          "trueNextStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "waitConfig": "…"
        }
      ],
      "triggerConfig": "…",
      "triggerType": "…",
      "updatedAt": "2026-10-28T07:30:00Z"
    }
  ],
  "page": 1,
  "pageSize": 1,
  "totalCount": 1,
  "totalPages": 1
}
GET/api/v1/office/automations/ai-columns/catalog

Catalog of AI column modes

AI column modes usable in automations. `available: false` means the feature is not enabled for this workspace: the column can still be configured but does not generate content yet.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/ai-columns/catalog" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "available": true,
  "modes": [
    {
      "labelKey": "…",
      "mode": "…",
      "needsOptions": true,
      "needsRange": true
    }
  ]
}
GET/api/v1/office/automations/catalog

Catalog of triggers/actions available for building automations

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/catalog" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "actions": [
    {
      "configFields": [
        {
          "description": "…",
          "input": "…",
          "label": "…",
          "name": "…",
          "options": [
            null
          ],
          "optionsSource": "…",
          "required": true,
          "type": "…"
        }
      ],
      "description": "…",
      "group": "…",
      "label": "…",
      "type": "…"
    }
  ],
  "steps": [
    {
      "configFields": [
        {
          "description": "…",
          "input": "…",
          "label": "…",
          "name": "…",
          "options": [
            null
          ],
          "optionsSource": "…",
          "required": true,
          "type": "…"
        }
      ],
      "description": "…",
      "group": "…",
      "label": "…",
      "type": "…"
    }
  ],
  "triggers": [
    {
      "configFields": [
        {
          "description": "…",
          "input": "…",
          "label": "…",
          "name": "…",
          "options": [
            null
          ],
          "optionsSource": "…",
          "required": true,
          "type": "…"
        }
      ],
      "description": "…",
      "group": "…",
      "label": "…",
      "type": "…"
    }
  ]
}
GET/api/v1/office/automations/merge-fields

Catalog of {{…}} variables insertable into action configuration

For the "insert variable" field of the rule builder. `triggerType` = the rule's trigger code ⇒ adds the `system` group (`now`, `today`, `createdBy`) and a `trigger` group based on the code (e.g. `before.<column>`, `changedFields`, `trigger.runNumber`, `trigger.clickedByName`).`tableId` = the rule's trigger table; if empty, only the trigger data group is returned. Each item has a `token` — the text placed inside `{{ }}`. Every text field in the configuration of EVERY action accepts variables; a variable that cannot be resolved at run time stays verbatim in the output (Test run lists them under `unresolved`). `automationId` + `stepId` ⇒ adds a `scope = "step"` group (with `stepId`) for EACH Find rows / Add rows step preceding that step: `steps.<step code>.recordIds` · `.count` · `.<Column name>` · `.first.<Column name>`. A `stepId` not yet in the rule (a step about to be added) ⇒ treated as the last step. Phase 4: `message_received` ⇒ `trigger.text` · `senderName` · `attachments` · `mentionNames` · `channelName` · `link`…; `service_event` ⇒ `trigger.payload.<key>` from the catalog of `eventType` (a parameter, or read from the configuration of `automationId`).

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDqueryno—
triggerTypestringqueryno—
automationIdGUIDqueryno—
stepIdGUIDqueryno—
eventTypestringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/merge-fields" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "fields": [
      {
        "example": "…",
        "label": "…",
        "token": "…"
      }
    ],
    "label": "…",
    "scope": "…",
    "stepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
  }
]
GET/api/v1/office/automations/quota

The company's monthly run quota

`{ month: "yyyy-MM" (Vietnam time), used, limit, percent }`. A run = one rule trigger (child runs of a loop are not counted). Over 100% ⇒ new runs are skipped and the log records the reason `quota_exceeded`; users' data operations do not fail.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/quota" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "limit": 1,
  "month": "…",
  "percent": 1.5,
  "used": 1
}
GET/api/v1/office/automations/service-events

Catalog of events from other software (service_event trigger)

`[{ service, label, events: [{ code, label, requiresFilter, perMinuteCap, keys: [{ key, label, type, token }] }] }]` — software → event → data key (Vietnamese labels). `code` goes into `eventType` of the WHEN configuration; `key` goes into `filters.groups[].rules[].key`; `token` is the insertable variable (`trigger.payload.<key>`). `type`: text · number · date · datetime · id · boolean. This catalog is exactly the list of system events currently received — a rule whose `eventType` is no longer here is `event_unknown` (cannot be re-enabled).

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/service-events" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "events": [
      {
        "code": "…",
        "keys": [
          {
            "key": null,
            "label": null,
            "token": null,
            "type": null
          }
        ],
        "label": "…",
        "perMinuteCap": 1,
        "requiresFilter": true
      }
    ],
    "label": "…",
    "service": "…"
  }
]
GET/api/v1/office/automations/suggestions

Automation suggestions tailored to the company (Suggestions tab)

Up to 3 cards `[{ kind, triggerType, actionType, tableId, tableName, fieldId, fieldName, offsetDays, evidenceCount, evidenceDays, existingAutomationId, existingAutomationName, existingStatus, existingRuns, existingFailed }]` built from real data: `date_expiring` = a Date column named like "Expiry date" with rows due within the next 30 days (suggests an "On date" rule, 30 days before); `busy_table` = a table with many new rows in the last 30 days that no rule listens to yet. `existingAutomationId` present = the company already has this rule (with run/failure counts over the last 30 days). The server returns only codes + numbers; the wording is translated by the UI. Read-only.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/suggestions" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "actionType": "…",
    "eventType": "…",
    "evidenceCount": 1,
    "evidenceDays": 1,
    "existingAutomationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "existingAutomationName": "…",
    "existingFailed": 1,
    "existingRuns": 1,
    "existingStatus": "…",
    "fieldId": "…",
    "fieldName": "…",
    "kind": "…",
    "offsetDays": 1,
    "service": "…",
    "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "tableName": "…",
    "triggerType": "…"
  }
]
GET/api/v1/office/automations/summary

Counts for the Automation Center

`{ total, active, inactive, mine, byTrigger: { [trigger code]: n }, archived, failing }` — `inactive` = all rules not Active; `archived` ⊂ `inactive`; `failing` = rules with failed runs in the last 7 days.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/summary" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "active": 1,
  "archived": 1,
  "byTrigger": {
    "key": 1
  },
  "failing": 1,
  "inactive": 1,
  "mine": 1,
  "total": 1
}
GET/api/v1/office/automations/{id}

Get an automation (with steps)

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "createdBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "createdById": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "createdByName": "…",
  "description": "…",
  "failed7d": 1,
  "graphVersion": 1,
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "lastRunAt": "2026-10-28T07:30:00Z",
  "name": "…",
  "parentAutomationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "parentStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "runs7d": 1,
  "source": "…",
  "status": "…",
  "stepActionTypes": [
    "…"
  ],
  "stepCount": 1,
  "steps": [
    {
      "actionType": "…",
      "branchIndex": 1,
      "branchLabel": "…",
      "conditionConfig": "…",
      "config": "…",
      "falseNextStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "groupId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "groupKind": "…",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "loopAutomationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "name": "…",
      "nextStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "order": 1,
      "splitRatio": 1,
      "stepType": "…",
      "trueNextStepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "waitConfig": "…"
    }
  ],
  "triggerConfig": "…",
  "triggerType": "…",
  "updatedAt": "2026-10-28T07:30:00Z"
}
GET/api/v1/office/automations/{id}/diagnosis

Diagnostics: why a rule runs / does not run

Checks in order (`status` · `trigger` · `steps` · `quota` · `recent_failures`), `canRun` = no blocking check failed, the 5 most recent SKIPS with translated reasons, and the most recent failure. Read-only.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/<id>/diagnosis" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "canRun": true,
  "checks": [
    {
      "blocking": true,
      "code": "…",
      "detail": "…",
      "ok": true
    }
  ],
  "lastFailure": {
    "automationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "detail": "…",
    "detailKey": "…",
    "enrollmentId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "result": "…",
    "runAt": "2026-10-28T07:30:00Z",
    "stepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "subjectId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
  },
  "recentSkips": [
    {
      "automationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "detail": "…",
      "detailKey": "…",
      "enrollmentId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "result": "…",
      "runAt": "2026-10-28T07:30:00Z",
      "stepId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "subjectId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    }
  ],
  "status": "…"
}
GET/api/v1/office/automations/{id}/overlaps

Other rules with the same trigger doing the same thing

Other ENABLED rules of the company with the same trigger type, the same listening scope (table, column, event type, channel — filters ignored) and at least one action type in common with this rule, with `sharedActions`. Warning only: with different filters the two rules may never run together; the user decides. Maximum 10.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/<id>/overlaps" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "name": "…",
    "sharedActions": [
      "…"
    ]
  }
]
GET/api/v1/office/automations/{id}/webhook/sample

Data sample + key tree

`{ sample, sampleSource: listen|manual, sampleAt, listening, listenUntil, keys: [{ name, path: "trigger.payload.a.b", type, example, children }] }`. `path` is the variable inserted into the step configuration. No sample yet ⇒ sample null, keys [].

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/automations/<id>/webhook/sample" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "keys": [
    {
      "children": [
        {
          "children": [
            null
          ],
          "example": "…",
          "name": "…",
          "path": "…",
          "type": "…"
        }
      ],
      "example": "…",
      "name": "…",
      "path": "…",
      "type": "…"
    }
  ],
  "listenUntil": "2026-10-28T07:30:00Z",
  "listening": true,
  "sample": null,
  "sampleAt": "2026-10-28T07:30:00Z",
  "sampleSource": "…"
}
GET/api/v1/office/calendar-preferences

My calendar screen settings

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/calendar-preferences" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "dayEndHour": 1,
  "dayStartHour": 1,
  "defaultEventMinutes": 1,
  "defaultView": "…",
  "showDeclined": true,
  "showWeekends": true,
  "timeZone": "…",
  "weekStartDay": 1
}
GET/api/v1/office/calendars

Calendars I am subscribed to (left column)

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/calendars" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "color": "…",
    "description": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "isMine": true,
    "isSubscribed": true,
    "isVisible": true,
    "kind": "…",
    "name": "…",
    "ownerId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "ownerName": "…",
    "role": "…"
  }
]
GET/api/v1/office/calendars/subscribable

Calendars available to subscribe to

Returns only calendars the caller is ACTUALLY allowed to see: shared calendars and holiday calendars.

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
termstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/calendars/subscribable" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "color": "…",
    "description": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "isMine": true,
    "isSubscribed": true,
    "isVisible": true,
    "kind": "…",
    "name": "…",
    "ownerId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "ownerName": "…",
    "role": "…"
  }
]
GET/api/v1/office/connection-keys

List issued keys

NEVER returns the actual key — only the identifying `prefix`. `status` is a CODE: active · revoked.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/connection-keys" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "createdAt": "2026-10-28T07:30:00Z",
    "expiresAt": "2026-10-28T07:30:00Z",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "lastUsedAt": "2026-10-28T07:30:00Z",
    "name": "…",
    "prefix": "…",
    "status": "…"
  }
]
GET/api/v1/office/dashboards/{id}/widgets/{widgetId}/data

Figures for one tile, computed per the viewer's permissions

unavailable = table_missing (table deleted) | no_access (the tile reads a column/table the viewer is not allowed to see).

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—
widgetIdstringpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/dashboards/<id>/widgets/<widgetId>/data" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "buckets": [
    {
      "count": 1,
      "key": "…",
      "value": 1.5
    }
  ],
  "comparePeriod": {
    "from": "…",
    "previousFrom": "…",
    "previousTo": "…",
    "to": "…"
  },
  "count": 1,
  "deltaPercent": 1.5,
  "groups": [
    {
      "count": 1,
      "key": "…",
      "series": [
        {
          "count": 1,
          "key": "…",
          "value": 1.5
        }
      ],
      "value": 1.5
    }
  ],
  "previousValue": 1.5,
  "rows": [
    {
      "cells": {
        "key": null
      },
      "recordId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    }
  ],
  "seriesKeys": [
    "…"
  ],
  "target": 1.5,
  "truncated": true,
  "type": "…",
  "unavailable": "…",
  "value": 1.5,
  "widgetId": "…"
}
GET/api/v1/office/events

Events within a time range

Used for week and month calendar views. Maximum query range is 120 days. eventType and status are returned as English CODES. truncated=true means the list was cut by a safety cap (too many events or too many recurrences in the visible window) — narrow the range to see everything.

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
fromdatequeryno—
todatequeryno—
eventTypestringqueryno—
mineOnlyboolqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/events" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "entries": [
    {
      "allDay": true,
      "attendeeCount": 1,
      "calendarColor": "…",
      "calendarId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "contentVisible": true,
      "endAt": "2026-10-28T07:30:00Z",
      "eventId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "eventType": "…",
      "fromPersonalCalendar": true,
      "id": "…",
      "isRecurring": true,
      "meetingUrl": "…",
      "myResponse": "…",
      "occurrenceStart": "2026-10-28T07:30:00Z",
      "organizerId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "roomNames": [
        "…"
      ],
      "startAt": "2026-10-28T07:30:00Z",
      "status": "…",
      "title": "…"
    }
  ],
  "truncated": true
}
GET/api/v1/office/events/{id}

Get an event with its attendees and booked rooms

occurrenceStart is the ORIGINAL timestamp of one occurrence in a recurring series — when provided, the title, time, description and location returned are the version WITH that occurrence's exceptions APPLIED, not the series-wide version. Omit for non-recurring events, or to view/edit the whole series (scope=all).

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—
occurrenceStartdatequeryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/events/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "allDay": true,
  "attendees": [
    {
      "email": "…",
      "isOptional": true,
      "isOrganizer": true,
      "responseNote": "…",
      "responseStatus": "…",
      "userId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    }
  ],
  "calendarId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "chatChannelId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "description": "…",
  "endAt": "2026-10-28T07:30:00Z",
  "eventType": "…",
  "fromPersonalCalendar": true,
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "location": "…",
  "meetingProvider": "…",
  "meetingRemovalPending": true,
  "meetingUrl": "…",
  "organizerId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "pushErrorKey": "…",
  "pushPending": true,
  "recurrenceRule": "…",
  "remindBeforeMinutes": 1,
  "reminders": [
    {
      "channel": "…",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "minutesBefore": 1
    }
  ],
  "rooms": [
    {
      "bookingId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "name": "…",
      "roomId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "status": "…"
    }
  ],
  "startAt": "2026-10-28T07:30:00Z",
  "status": "…",
  "syncedWithGoogle": true,
  "timeProposals": [
    {
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "note": "…",
      "occurrenceStart": "2026-10-28T07:30:00Z",
      "proposedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "proposedByName": "…",
      "proposedEndAt": "2026-10-28T07:30:00Z",
      "proposedStartAt": "2026-10-28T07:30:00Z",
      "status": "…"
    }
  ],
  "title": "…"
}
GET/api/v1/office/events/{id}.ics

Download the event's .ics calendar file

For signed-in users INSIDE the company (organizer/attendee/calendar shared at a sufficient level). External guests use the separate public link in the invitation — see PublicCalendarController, NOT this endpoint.

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/events/<id>.ics" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
"…"
GET/api/v1/office/farm/device-controls

List command tickets

status: pending · dispatched · rejected · expired. scope: mine (tickets I can approve) · all.

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
statusstringqueryno—
scopestringqueryno—
takeintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/farm/device-controls" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "approverIds": [
      "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    ],
    "automationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "canDecide": true,
    "createdAt": "2026-10-28T07:30:00Z",
    "decidedAt": "2026-10-28T07:30:00Z",
    "decidedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "deviceId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "deviceLabel": "…",
    "expiresAt": "2026-10-28T07:30:00Z",
    "family": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "idx": 1,
    "iotCommandId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "note": "…",
    "reason": "…",
    "status": "…",
    "value": 1
  }
]
GET/api/v1/office/farm/device-controls/emergency-stop

EMERGENCY STOP status of the farm's automatic device control

Scope: office.automation.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/farm/device-controls/emergency-stop" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "canChange": true,
  "changedAt": "2026-10-28T07:30:00Z",
  "changedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "stopped": true
}
GET/api/v1/office/farm/device-controls/rules/{automationId}/approval

Auto-run approval status of a rule

valid = the approval stamp still matches the rule and table data (editing the rule / schedule invalidates it).

Scope: office.automation.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
automationIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/farm/device-controls/rules/<automationId>/approval" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "approved": true,
  "approvedAt": "2026-10-28T07:30:00Z",
  "approvedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "automationId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "canApprove": true,
  "valid": true
}
GET/api/v1/office/meeting-minutes

Minutes of a meeting

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
eventIdGUIDqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/meeting-minutes" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "actionItems": [
    {
      "assigneeId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "description": "…",
      "dueAt": "2026-10-28T07:30:00Z",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "taskId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    }
  ],
  "artifactsFetchedAt": "2026-10-28T07:30:00Z",
  "decisions": "…",
  "eventId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "publishedAt": "2026-10-28T07:30:00Z",
  "recordedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "recordingUrl": "…",
  "summary": "…",
  "transcriptText": "…"
}
GET/api/v1/office/meeting-rooms

List meeting rooms

minCapacity/equipment/building filter right in the room picker — equipment requires the room to have ALL requested codes.

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
activeOnlyboolqueryno—
minCapacityintqueryno—
equipmentobjectqueryno—
buildingstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/meeting-rooms" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "autoReleaseMinutes": 1,
    "building": "…",
    "capacity": 1,
    "equipment": [
      "…"
    ],
    "floor": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "isActive": true,
    "location": "…",
    "maxBookingMinutes": 1,
    "name": "…",
    "requiresApproval": true
  }
]
GET/api/v1/office/meeting-rooms/{id}/busy-slots

Busy time slots of a room

Called by the UI as soon as the user picks a room, to grey out unavailable slots.

Scope: office.calendar.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—
fromdatequeryno—
todatequeryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/meeting-rooms/<id>/busy-slots" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "bookedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "endAt": "2026-10-28T07:30:00Z",
    "eventId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "eventTitle": "…",
    "startAt": "2026-10-28T07:30:00Z"
  }
]
GET/api/v1/office/tables/{tableId}/fields

List fields of a table

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/fields" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "description": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "isHidden": true,
    "isPrimary": true,
    "name": "…",
    "position": 1,
    "property": "…",
    "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "type": 1,
    "uiType": "…"
  }
]
GET/api/v1/office/tables/{tableId}/fields/{fieldId}

Get a field

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
fieldIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/fields/<fieldId>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "description": "…",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "isHidden": true,
  "isPrimary": true,
  "name": "…",
  "position": 1,
  "property": "…",
  "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "type": 1,
  "uiType": "…"
}
POST/api/v1/office/tables/{tableId}/records

Create a record

Mobile writes while offline: send the X-Submission-Id header (device-generated uuid) + X-Captured-At (actual capture time, ISO-8601). Resending the same ID ⇒ returns the existing row, no duplicate is created.

Scope: office.base.record.manageTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
datastringbodyno—

Example

curl -X POST "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "data": null }'

Sample response

201 Created
null
POST/api/v1/office/tables/{tableId}/records/aggregate

Aggregate by column (sum · average · min · max · count)

The five figures of the footer bar, computed over the CURRENTLY FILTERED set — send exactly the filters the grid is applying. Summed on the server, not in the grid: the grid only holds a few hundred rows around the scroll position, so summing what it holds would make the figures JUMP as the user scrolls. Columns outside the viewable scope are excluded from the result. This is not a formula engine: no syntax, no `A1:A10` ranges, nothing is stored.

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
fieldIdsobjectbodyno—
filterobjectbodyno—

Example

curl -X POST "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/aggregate" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "fieldIds": [ "0190a3c2-5b1e-7c3d-8e4f-000000000001" ], "filter": { "conditions": [ { "fieldId": "…", "operator": "…", "value": null } ], "conjunction": "…", "groups": [ { "conditions": [ { "fieldId": null, "operator": null, "value": null } ], "conjunction": "…", "groups": [ { "conditions": null, "conjunction": null, "groups": null, "hasCriteria": null } ], "hasCriteria": true } ], "hasCriteria": true } }'

Sample response

200 OK
[
  {
    "average": 1.5,
    "count": 1,
    "fieldId": "…",
    "max": 1.5,
    "min": 1.5,
    "numericCount": 1,
    "sum": 1.5
  }
]
POST/api/v1/office/tables/{tableId}/records/batch

Create multiple records (up to 1000, all-or-nothing)

Scope: office.base.record.manageTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
recordsobjectbodyno—

Example

curl -X POST "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/batch" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "records": [ null ] }'

Sample response

201 Created
null
PUT/api/v1/office/tables/{tableId}/records/batch

Update multiple records (up to 1000, all-or-nothing)

Scope: office.base.record.manageTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
itemsobjectbodyno—

Example

curl -X PUT "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/batch" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "items": [ { "data": null, "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001", "replace": true } ] }'

Sample response

This endpoint does not declare a response schema yet — call it in the API Explorer to see the shape.

POST/api/v1/office/tables/{tableId}/records/groups

Row groups: group column value + row count, in the same order as records/list

Send the SAME filter/sort/groupFieldId as records/list — the grid accumulates row counts to place group headers. If the group column is outside view permissions ⇒ fieldHidden=true, with no groups.

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
filterobjectbodyno—
groupFieldIdstringbodyno—
sortobjectbodyno—

Example

curl -X POST "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/groups" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "filter": { "conditions": [ { "fieldId": "…", "operator": "…", "value": null } ], "conjunction": "…", "groups": [ { "conditions": [ { "fieldId": null, "operator": null, "value": null } ], "conjunction": "…", "groups": [ { "conditions": null, "conjunction": null, "groups": null, "hasCriteria": null } ], "hasCriteria": true } ], "hasCriteria": true }, "groupFieldId": "…", "sort": [ { "descending": true, "fieldId": "…" } ] }'

Sample response

200 OK
{
  "fieldHidden": true,
  "groups": [
    {
      "count": 1,
      "value": null
    }
  ],
  "tooMany": true,
  "total": 1
}
POST/api/v1/office/tables/{tableId}/records/list

List records (paginated + structured filter in the body)

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
colorRulesobjectbodyno—
filterobjectbodyno—
groupFieldIdstringbodyno—
pageintbodyno—
pageSizeintbodyno—
sortobjectbodyno—

Example

curl -X POST "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/list" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "colorRules": [ { "color": "…", "filter": { "conditions": [ { "fieldId": null, "operator": null, "value": null } ], "conjunction": "…", "groups": [ { "conditions": null, "conjunction": null, "groups": null, "hasCriteria": null } ], "hasCriteria": true } } ], "filter": { "conditions": [ { "fieldId": "…", "operator": "…", "value": null } ], "conjunction": "…", "groups": [ { "conditions": [ { "fieldId": null, "operator": null, "value": null } ], "conjunction": "…", "groups": [ { "conditions": null, "conjunction": null, "groups": null, "hasCriteria": null } ], "hasCriteria": true } ], "hasCriteria": true }, "groupFieldId": "…", "page": 1, "pageSize": 1, "sort": [ { "descending": true, "fieldId": "…" } ] }'

Sample response

200 OK
{
  "hasNextPage": true,
  "hasPreviousPage": true,
  "items": [
    {
      "createdAt": "2026-10-28T07:30:00Z",
      "data": "…",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "rowColor": "…",
      "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "updatedAt": "2026-10-28T07:30:00Z"
    }
  ],
  "page": 1,
  "pageSize": 1,
  "totalCount": 1,
  "totalPages": 1
}
GET/api/v1/office/tables/{tableId}/records/{recordId}

Get a record

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
recordIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/<recordId>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "createdAt": "2026-10-28T07:30:00Z",
  "data": "…",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "rowColor": "…",
  "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "updatedAt": "2026-10-28T07:30:00Z"
}
PUT/api/v1/office/tables/{tableId}/records/{recordId}

Update a record (merge by default; replace=true to overwrite)

Send `expectedValues` — a map of field_id → the value the UI is CURRENTLY SHOWING for exactly the cells being edited — to enable optimistic locking. If any cell has been changed by someone else, the call returns **409** with the list of conflicting cells and their current values, and **no cell is written**. Omit `expectedValues` to skip the check, as before — so existing clients keep their behaviour.

Scope: office.base.record.manageTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
recordIdGUIDpathyes—
datastringbodyno—
expectedValuesstringbodyno—
replaceboolbodyno—

Example

curl -X PUT "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/<recordId>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "data": null, "expectedValues": null, "replace": true }'

Sample response

This endpoint does not declare a response schema yet — call it in the API Explorer to see the shape.

GET/api/v1/office/tables/{tableId}/records/{recordId}/history

Edit history of a record, split by cell (filtered by column permissions)

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
recordIdGUIDpathyes—
limitintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/records/<recordId>/history" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "action": "…",
    "changes": [
      {
        "fieldId": "…",
        "fieldName": "…",
        "fieldType": 1,
        "newValue": null,
        "oldValue": null
      }
    ],
    "createdAt": "2026-10-28T07:30:00Z",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "userId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
  }
]
GET/api/v1/office/tables/{tableId}/trash

Trash — soft-deleted records of a table (paginated)

Only records of the current company; data is intact and can be restored or permanently deleted.

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
pageintqueryno—
pageSizeintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/trash" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "hasNextPage": true,
  "hasPreviousPage": true,
  "items": [
    {
      "createdAt": "2026-10-28T07:30:00Z",
      "data": "…",
      "deletedAt": "2026-10-28T07:30:00Z",
      "deletedBy": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "updatedAt": "2026-10-28T07:30:00Z"
    }
  ],
  "page": 1,
  "pageSize": 1,
  "totalCount": 1,
  "totalPages": 1
}
GET/api/v1/office/tables/{tableId}/views

List views of a table

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/views" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "isPublic": true,
    "name": "…",
    "property": "…",
    "publicToken": "…",
    "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "viewType": "…"
  }
]
GET/api/v1/office/tables/{tableId}/views/{viewId}

Get a view

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
viewIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/views/<viewId>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "isPublic": true,
  "name": "…",
  "property": "…",
  "publicToken": "…",
  "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "viewType": "…"
}
GET/api/v1/office/tables/{tableId}/views/{viewId}/calendar-data

Records within the date range of a Calendar view

Maps date fields (startField/endField) in property; from/to filter by start date.

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
viewIdGUIDpathyes—
fromdatequeryno—
todatequeryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/views/<viewId>/calendar-data" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "data": "…",
    "end": "2026-10-28T07:30:00Z",
    "recordId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "start": "2026-10-28T07:30:00Z"
  }
]
GET/api/v1/office/tables/{tableId}/views/{viewId}/chart-data

Aggregated data for a Chart view

Grouped per the configuration in property (groupField + aggregation count/sum/avg). The FE renders it.

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
tableIdGUIDpathyes—
viewIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tables/<tableId>/views/<viewId>/chart-data" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "aggregation": "…",
  "buckets": [
    {
      "count": 1,
      "groupKey": "…",
      "value": 1.5
    }
  ],
  "groupField": "…",
  "valueField": "…"
}
GET/api/v1/office/tasks/monitor

Monitoring screen: six stat tiles + team-wide table + each person's tasks

One call returns all three parts because they read THE SAME task set — splitting them would put the stat tiles and the table below at two different points in time with mismatched numbers. elapsedMinutes is the time ELAPSED since work started (started_at), NOT labour hours. loadState: overloaded · normal · free. isExact=false means the company exceeds the row cap so all figures are estimates. taskListId narrows ALL figures to one project — it only narrows and never reveals tasks the scope would not otherwise show. With taskListId, each member row also carries openCountAll = that person's open tasks across the whole scope. Each member's items are capped at 200 (overdue first); openTotal = the ACTUAL total of that person's open tasks in the same scope — compare with the number of items to show “showing n/N”. dueSoonDays = the “due soon” window currently applied (alongside staleAfterDays).

Scope: office.task.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
scopestringqueryno—
taskListIdGUIDqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tasks/monitor" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "dueSoonDays": 1,
  "isExact": true,
  "members": [
    {
      "current": {
        "elapsedMinutes": 1,
        "startedAt": "2026-10-28T07:30:00Z",
        "taskId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
        "title": "…"
      },
      "dueSoonCount": 1,
      "hasOnTimeData": true,
      "inProgressCount": 1,
      "items": [
        {
          "daysLate": 1,
          "dueAt": "2026-10-28T07:30:00Z",
          "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "isOverdue": true,
          "status": "…",
          "title": "…"
        }
      ],
      "lastActivityAt": "2026-10-28T07:30:00Z",
      "loadState": "…",
      "onTimeRate": 1,
      "openCount": 1,
      "openCountAll": 1,
      "openTotal": 1,
      "overdueCount": 1,
      "pendingReviewCount": 1,
      "staleCount": 1,
      "todoCount": 1,
      "userId": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
    }
  ],
  "staleAfterDays": 1,
  "summary": {
    "dueSoon": 1,
    "hasOnTimeData": true,
    "onTimeRate": 1,
    "open": 1,
    "overdue": 1,
    "stale": 1,
    "unassigned": 1
  }
}
GET/api/v1/office/tasks/workload

Workload per person

isOverloaded is relative to the overload threshold, default 10 open tasks; each row also returns overloadThreshold = the threshold applied. Workload is for REFERENCE ONLY, not for computing progress. taskListId narrows to one list; listGroupId narrows to one folder (team) INCLUDING all subfolders. With both, the INTERSECTION applies. A non-existent list/folder ⇒ 404.

Scope: office.task.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
taskListIdGUIDqueryno—
listGroupIdGUIDqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/tasks/workload" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "isOverloaded": true,
    "openCount": 1,
    "overdueCount": 1,
    "overloadThreshold": 1,
    "totalWorkload": 1.5,
    "userId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "workloadDay": 1.5,
    "workloadHour": 1.5,
    "workloadPoint": 1.5
  }
]
GET/api/v1/office/views/{viewId}/location

Trace back from a view ID to the table and app that contain it

Scope: office.base.record.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
viewIdGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/office/views/<viewId>/location" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "appId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "appName": "…",
  "tableId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "tableName": "…",
  "viewId": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "viewName": "…",
  "viewType": "…"
}