API Reference
Every call of the External Data API with its permission, parameters, a sample request and a sample response. Search to jump to a call. The External Data API guide explains sign-in, permissions and the rules behind them.
No call matches. Try a path segment such as attachments, or a permission such as entries:write.
<base URL>/external/v1/, for example https://your-host/persivapps/service/external/v1/me. Sign in with POST /external/v1/auth/login, then send Authorization: Bearer <access_token>. In the samples, {{base_url}} and {{access_token}} are the Postman collection's variables.
Getting started
POST /external/v1/auth/login
#
Sign in with the client ID and secret; returns an access token (1 hour) and a refresh token.
Errors follow OAuth 2.0: {"error": "invalid_client" | "invalid_scope", "error_description": "…"}.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
client_id | body | string | Yes | The client ID |
client_secret | body | string | Yes | The secret (or send both as HTTP Basic) |
scope | body | string | No | Space-separated permissions, to get a token with fewer |
curl -X POST "{{base_url}}/external/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"client_id": "{{client_id}}", "client_secret": "{{client_secret}}"}'{
"access_token": "pvx_at_9c1f…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "entries:read entries:write",
"refresh_token": "pvx_rt_47d2…"
}
POST /external/v1/auth/token
#
OAuth 2.0 token endpoint: client_credentials, or refresh_token to renew.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
grant_type | body | string | Yes | client_credentials or refresh_token |
refresh_token | body | string | No | With refresh_token; each works once |
client_id | body | string | Yes | The client ID |
client_secret | body | string | Yes | The secret |
curl -X POST "{{base_url}}/external/v1/auth/token" \
-H "Content-Type: application/json" \
-d '{"grant_type": "refresh_token", "refresh_token": "{{refresh_token}}", "client_id": "{{client_id}}", "client_secret": "{{client_secret}}"}'{
"access_token": "pvx_at_5be0…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "entries:read entries:write",
"refresh_token": "pvx_rt_a812…"
}
GET /external/v1/me
#
This client, the permissions of the current token, and the SmartTables each covers.
Use it to check what a token can do before calling anything else.
curl -X GET "{{base_url}}/external/v1/me" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"client": {
"name": "Acme Logistics",
"client_id": "ext.acme-logistics.1a2b3c4d"
},
"credential": {
"name": "Production server",
"expires_at": null
},
"permissions": [
{
"permission": "entries:read",
"smarttables": [
{
"id": 61,
"name": "Dispatch Log"
}
]
},
{
"permission": "entries:write",
"smarttables": [
{
"id": 61,
"name": "Dispatch Log"
}
]
}
]
}
GET /external/v1/reference/postman
#
A Postman collection of just the calls this token may use (?base_url= sets the default host).
Import the file in Postman, fill in client_secret, then run "Sign in".
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
base_url | query | string | No | Your API base URL, set as the collection's base_url variable |
curl -X GET "{{base_url}}/external/v1/reference/postman?base_url=https%3A%2F%2Fyour-host%2Fpersivapps%2Fservice" \
-H "Authorization: Bearer {{access_token}}"(a file: application/json)
GET /external/v1/reference/pdf
#
The API reference as a PDF, with just the calls this token may use.
At most 10 per 10 minutes.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
base_url | query | string | No | Your API base URL, shown in the samples |
curl -X GET "{{base_url}}/external/v1/reference/pdf?base_url=https%3A%2F%2Fyour-host%2Fpersivapps%2Fservice" \
-H "Authorization: Bearer {{access_token}}"(a file: application/pdf)
Entries
GET /external/v1/smarttables/{smarttable_id}/entries
#
List entries of a SmartTable (paged; search, filters, sort, created/updated time window).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
page | query | integer | No | Page, from 1 |
page_size | query | integer | No | 50, 100 (default), 200 or 500 |
search | query | string | No | Matches any field's value |
filters | query | JSON array | No | e.g. [{"column_id": "8", "operator": "equals", "value": "Arrived"}]; at most 20 |
sort | query | string | No | A field id, or created_at, updated_at, observation_number, entry_id |
dir | query | string | No | asc or desc (default) |
submitted | query | string | No | 1 = submitted only, 0 = drafts only |
created_after | query | ISO 8601 | No | Created at or after (no offset = UTC) |
created_before | query | ISO 8601 | No | Created before |
updated_after | query | ISO 8601 | No | Changed at or after — use it to fetch what changed since your last run |
updated_before | query | ISO 8601 | No | Changed before |
deleted | query | string | No | 1 lists deleted rows instead (needs entries:delete) |
curl -X GET "{{base_url}}/external/v1/smarttables/61/entries?page=1&page_size=100&updated_after=2026-10-01T00%3A00%3A00Z&sort=updated_at&dir=asc" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"entries": [
{
"smarttable_id": 61,
"smarttable_data_id": 189862,
"smarttable_data_entry_id": 195569,
"observation_number": 1,
"values": {
"1": "Truck MH12AB1234",
"3": 12.5,
"8": "Arrived"
},
"is_submitted": false,
"is_deleted": false,
"created_at": "2026-10-12T09:41:07.512Z",
"updated_at": "2026-10-12T09:41:07.512Z",
"created_by": "Acme Logistics (integration)"
}
],
"page": 1,
"page_size": 100,
"total_count": 1,
"total_pages": 1
}
GET /external/v1/smarttables/data/{smarttable_data_id}
#
Read one row (an observation of an entry).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X GET "{{base_url}}/external/v1/smarttables/data/189862" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"row": {
"smarttable_id": 61,
"smarttable_data_id": 189862,
"smarttable_data_entry_id": 195569,
"observation_number": 1,
"values": {
"1": "Truck MH12AB1234",
"3": 12.5,
"8": "Arrived"
},
"is_submitted": false,
"is_deleted": false,
"created_at": "2026-10-12T09:41:07.512Z",
"updated_at": "2026-10-12T09:41:07.512Z",
"created_by": "Acme Logistics (integration)"
}
}
GET /external/v1/entries/{smarttable_data_entry_id}
#
Read an entry with all its observations.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_entry_id | path | integer | Yes | An entry id |
curl -X GET "{{base_url}}/external/v1/entries/195569" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"smarttable_data_entry_id": 195569,
"observations": [
{
"smarttable_id": 61,
"smarttable_data_id": 189862,
"smarttable_data_entry_id": 195569,
"observation_number": 1,
"values": {
"1": "Truck MH12AB1234",
"3": 12.5,
"8": "Arrived"
},
"is_submitted": false,
"is_deleted": false,
"created_at": "2026-10-12T09:41:07.512Z",
"updated_at": "2026-10-12T09:41:07.512Z",
"created_by": "Acme Logistics (integration)"
}
]
}
DELETE /external/v1/smarttables/data/{smarttable_data_id}
#
Delete a row (soft delete; can be restored).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X DELETE "{{base_url}}/external/v1/smarttables/data/189862" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Deleted",
"smarttable_data_id": 189862
}
POST /external/v1/smarttables/data/{smarttable_data_id}/restore
#
Restore a deleted row.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X POST "{{base_url}}/external/v1/smarttables/data/189862/restore" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Restored",
"smarttable_data_id": 189862
}
DELETE /external/v1/smarttables/data/{smarttable_data_id}/permanent
#
Delete a row permanently (cannot be undone).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X DELETE "{{base_url}}/external/v1/smarttables/data/189862/permanent" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Deleted permanently",
"smarttable_data_id": 189862
}
POST /external/v1/smarttables/data/{smarttable_data_id}/unsubmit
#
Unsubmit a submitted row so it can be edited again.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X POST "{{base_url}}/external/v1/smarttables/data/189862/unsubmit" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Unsubmitted",
"smarttable_data_id": 189862
}
POST /external/v1/smarttables/data/{smarttable_data_id}/release-lock
#
Release the edit lock on a row someone left open.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X POST "{{base_url}}/external/v1/smarttables/data/189862/release-lock" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Edit lock released",
"smarttable_data_id": 189862
}
POST /external/v1/smarttables/data/save
#
Create an entry, or a new observation of an entry this client owns.
Required fields are checked by the entry form, not by the save: send every field the SmartTable needs.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | body | integer | Yes | The SmartTable to save into |
smarttable_values | body | object | Yes | Field values keyed by field id; a table field takes an array |
is_submit | body | boolean | No | true submits (and starts any approval workflow); default saves a draft |
client_op_id | body | string | No | Your unique id for this save; a repeat returns the original row (200, duplicate: true) |
smarttable_data_entry_id | body | integer | No | Add a new observation to one of your entries instead |
observation_number | body | integer | No | With smarttable_data_entry_id: which observation |
attachments__<field_id> | form | file | No | Files, when sent as multipart/form-data (smarttable_values as a JSON string) |
curl -X POST "{{base_url}}/external/v1/smarttables/data/save" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_id": 61, "smarttable_values": {"1": "Truck MH12AB1234", "3": 12.5, "8": "Arrived"}, "is_submit": false, "client_op_id": "acme-dispatch-000123"}'{
"status": "success",
"message": "Saved",
"duplicate": false,
"smarttable_id": 61,
"smarttable_data_id": 189862,
"smarttable_data_entry_id": 195569,
"observation_number": 1
}
PUTPATCHPOST /external/v1/smarttables/data/{smarttable_data_id}/update
#
Update fields of a saved row.
PUT, PATCH and POST are all accepted. Only rows this client created, unless it may change any entry.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
smarttable_values | body | object | Yes | Only the fields to change; the rest keep their values |
cleared_fields | body | array of string | No | Field ids to blank (an empty string means "no change") |
cleared_attachments | body | array of string | No | Attachment field ids to empty |
is_submit | body | boolean | No | true submits a draft |
curl -X PUT "{{base_url}}/external/v1/smarttables/data/189862/update" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_values": {"8": "Unloaded"}, "cleared_fields": ["3"]}'{
"status": "success",
"message": "Updated",
"smarttable_id": 61,
"smarttable_data_id": 189862,
"smarttable_data_entry_id": 195569,
"observation_number": 1
}Bulk operations
POST /external/v1/bulk/delete
#
Delete many rows (soft delete; can be restored). Body: {"smarttable_data_ids": [...]}.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_ids | body | array of integer | Yes | Row ids, at most 500 |
curl -X POST "{{base_url}}/external/v1/bulk/delete" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_data_ids": [189862, 189863, 999999]}'{
"status": "success",
"deleted": [
189862,
189863
],
"failed": [
{
"id": 999999,
"error": "Not found"
}
]
}
POST /external/v1/bulk/restore
#
Restore many deleted rows. Body: {"smarttable_data_ids": [...]}.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_ids | body | array of integer | Yes | Row ids, at most 500 |
curl -X POST "{{base_url}}/external/v1/bulk/restore" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_data_ids": [189862, 189863]}'{
"status": "success",
"restored": [
189862,
189863
],
"failed": []
}
POST /external/v1/bulk/delete-permanently
#
Permanently delete many rows (cannot be undone). Body: {"smarttable_data_ids": [...]}.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_ids | body | array of integer | Yes | Row ids, at most 500 |
curl -X POST "{{base_url}}/external/v1/bulk/delete-permanently" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_data_ids": [189862]}'{
"status": "success",
"deleted": [
189862
],
"failed": []
}
POST /external/v1/bulk/update-version
#
Move many rows to the latest approved schema and/or display version. Body: {"smarttable_data_ids": [...], "update": "entry" | "display" | "both"}.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_ids | body | array of integer | Yes | Row ids, at most 500 |
update | body | string | No | entry, display or both (default) |
curl -X POST "{{base_url}}/external/v1/bulk/update-version" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_data_ids": [189862], "update": "both"}'{
"status": "success",
"updated": [
{
"id": 189862,
"entry_version_id": 412,
"display_version_id": 233
}
],
"failed": []
}
POST /external/v1/smarttables/{smarttable_id}/bulk-upload
#
Add rows to a relational SmartTable from an Excel file (multipart, key "file"; column headers = field names).
Relational SmartTables only. At most 10 uploads per hour.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
file | form | file | Yes | .xlsx or .xls, at most 10 MB; first row = field names |
curl -X POST "{{base_url}}/external/v1/smarttables/64/bulk-upload" \
-H "Authorization: Bearer {{access_token}}" \
-F "file=@vehicles.xlsx"{
"status": "success",
"smarttable_id": 64,
"message": "Bulk upload completed",
"total_rows": 120,
"added": 118,
"failed": 2,
"errors": [
"Row 14: Vehicle number is required",
"Row 87: duplicate Vehicle number"
]
}Attestation and eSign
GET /external/v1/smarttables/data/{smarttable_data_id}/attestation
#
A row's attestation and eSign status.
attested_by is null while the row is not attested.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X GET "{{base_url}}/external/v1/smarttables/data/189862/attestation" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"attestation": {
"smarttable_data_id": 189862,
"attested": true,
"attested_by": {
"user_id": 431,
"name": "Acme Logistics (integration)"
},
"esign": {
"status": null,
"transaction_id": null
}
}
}
POST /external/v1/smarttables/data/{smarttable_data_id}/attestation
#
Attest a row with a signature image; it is recorded as signed by this integration.
Only a submitted row. Recorded as signed by this integration.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
image | body | string (base64) or file | Yes | PNG or JPEG signature, at most 1 MB; or multipart field "image" |
curl -X POST "{{base_url}}/external/v1/smarttables/data/189862/attestation" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"image": "iVBORw0KGgoAAAANSUhEUgAA..."}'{
"status": "success",
"attestation": {
"smarttable_data_id": 189862,
"attested": true,
"attested_by": {
"user_id": 431,
"name": "Acme Logistics (integration)"
},
"esign": {
"status": null,
"transaction_id": null
}
}
}
DELETE /external/v1/smarttables/data/{smarttable_data_id}/attestation
#
Remove a row's attestation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X DELETE "{{base_url}}/external/v1/smarttables/data/189862/attestation" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"attestation": {
"smarttable_data_id": 189862,
"attested": false,
"attested_by": null,
"esign": {
"status": null,
"transaction_id": null
}
}
}Attachments
GET /external/v1/smarttables/data/{smarttable_data_id}/attachments
#
List a row's attachments.
Files are grouped by attachment field id.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X GET "{{base_url}}/external/v1/smarttables/data/189862/attachments" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_data_id": 189862,
"attachments": {
"6": [
{
"filename": "0001_3f9a1c2b7d4e_weighbridge-slip.pdf",
"path": "smarttables/data/189862/attachments/6/0001_3f9a1c2b7d4e_weighbridge-slip.pdf"
}
]
}
}
GET /external/v1/smarttables/data/{smarttable_data_id}/attachments/{field_id}/{filename}
#
Download one attachment.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
field_id | path | integer | Yes | The attachment field id |
filename | path | string | Yes | A filename from the list call |
curl -X GET "{{base_url}}/external/v1/smarttables/data/189862/attachments/6/0001_3f9a1c2b7d4e_weighbridge-slip.pdf" \
-H "Authorization: Bearer {{access_token}}"(a file: application/octet-stream)
POST /external/v1/smarttables/data/{smarttable_data_id}/attachments/{field_id}
#
Upload files to an attachment field (multipart, key "files").
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
field_id | path | integer | Yes | The attachment field id |
files | form | file | Yes | One or more files (repeat the key), at most 20 |
curl -X POST "{{base_url}}/external/v1/smarttables/data/189862/attachments/6" \
-H "Authorization: Bearer {{access_token}}" \
-F "files=@weighbridge-slip.pdf"{
"status": "success",
"smarttable_data_id": 189862,
"field_id": "6",
"files": [
"0001_3f9a1c2b7d4e_weighbridge-slip.pdf"
]
}
DELETE /external/v1/smarttables/data/{smarttable_data_id}/attachments/{field_id}/{filename}
#
Remove one attachment.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
field_id | path | integer | Yes | The attachment field id |
filename | path | string | Yes | The stored filename |
curl -X DELETE "{{base_url}}/external/v1/smarttables/data/189862/attachments/6/0001_3f9a1c2b7d4e_weighbridge-slip.pdf" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Removed",
"smarttable_data_id": 189862,
"field_id": "6",
"filename": "0001_3f9a1c2b7d4e_weighbridge-slip.pdf"
}Comments and notes
GET /external/v1/smarttables/data/{smarttable_data_id}/comments
#
List a row's comments and notes.
kind is "note" for notes added in the app, else "comment".
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X GET "{{base_url}}/external/v1/smarttables/data/189862/comments" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_data_id": 189862,
"comments": [
{
"text": "Weighbridge slip attached.",
"author": "Asha Patel",
"at": "2026-10-12T10:02:11Z",
"kind": "comment",
"attachments": []
}
]
}
POST /external/v1/smarttables/data/{smarttable_data_id}/comments
#
Add a comment to a row.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
text | body | string | Yes | Plain text, at most 5,000 characters |
curl -X POST "{{base_url}}/external/v1/smarttables/data/189862/comments" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"text": "Unloaded at gate 3."}'{
"status": "success",
"message": "Comment added",
"smarttable_data_id": 189862
}Approval status
GET /external/v1/entries/{smarttable_data_entry_id}/approval
#
An entry's approval status, with earlier rounds.
Read only: approvers act in the app. Signatures are never returned. A SmartTable without a workflow returns just "approval_enabled": false.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_entry_id | path | integer | Yes | An entry id |
curl -X GET "{{base_url}}/external/v1/entries/195569/approval" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_data_entry_id": 195569,
"approval_enabled": true,
"approval": {
"approval_workflow_enabled": true,
"interleaved": false,
"total_steps": 2,
"current_step": 2,
"current_entry_step": null,
"steps_done": 1,
"steps_pending": 1,
"is_fully_approved": false,
"is_rejected": false,
"is_published": false,
"published_at": null,
"waiting_for_approval": true,
"approved_at": null,
"steps": [
{
"step": 1,
"label": "Step 1",
"mode": "any",
"approvers": [
12,
15
],
"approvers_list": [
{
"name": "Asha Patel"
},
{
"name": "Vikram Rao"
}
],
"status": "approved",
"approved_by": [
{
"name": "Asha Patel"
}
],
"pending_approvers": [],
"comment": "Looks fine"
}
],
"publish_notification_users": [],
"email_publish_notification_users": [],
"publish_email_settings": {
"subject": "",
"body": ""
}
}
}
GET /external/v1/entries/{smarttable_data_entry_id}/approval/history
#
Earlier approval rounds of an entry (rejected and resubmitted).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_entry_id | path | integer | Yes | An entry id |
curl -X GET "{{base_url}}/external/v1/entries/195569/approval/history" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_data_entry_id": 195569,
"rounds": []
}Exports
POST /external/v1/bulk/pdf
#
Download many entry PDFs as one zip. Body: {"smarttable_data_entry_ids": [...]} (at most 50).
Entries you can't read are left out and listed in the X-Skipped-Entry-Ids header. At most 5 per 5 minutes.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_entry_ids | body | array of integer | Yes | Entry ids, at most 50 |
include_attachments | body | boolean | No | Merge attached PDFs (default true) |
curl -X POST "{{base_url}}/external/v1/bulk/pdf" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_data_entry_ids": [195569, 195570], "include_attachments": false}'(a file: application/zip)
GET /external/v1/entries/{smarttable_data_entry_id}/pdf
#
Download an entry's PDF (its display layout).
At most 30 PDFs per minute.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_entry_id | path | integer | Yes | An entry id |
include_attachments | query | string | No | false leaves attached PDFs out |
curl -X GET "{{base_url}}/external/v1/entries/195569/pdf?include_attachments=false" \
-H "Authorization: Bearer {{access_token}}"(a file: application/pdf)
SmartTables
GET /external/v1/smarttables
#
List the SmartTables this client can read.
curl -X GET "{{base_url}}/external/v1/smarttables" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttables": [
{
"smarttable_id": 61,
"name": "Dispatch Log",
"is_approved": true,
"is_relational": false,
"observation_count": 1,
"version": 4
}
]
}
GET /external/v1/smarttables/{smarttable_id}
#
A SmartTable with its current fields (schema).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable": {
"smarttable_id": 61,
"name": "Dispatch Log",
"is_approved": true,
"is_relational": false,
"observation_count": 1,
"version": 4,
"fields": [
{
"id": 1,
"name": "Truck number",
"ui_smarttable_element": "text",
"optional": false,
"hide": false,
"isDisabled": false,
"show_in_entries_list": true,
"accordion": "Vehicle",
"smarttable_section": "Dispatch",
"row": "",
"table": false,
"table_no": "",
"auto_increment": false,
"min_value_allowed": "",
"max_value_allowed": "",
"acceptance_criteria": "",
"allowed_data": "",
"properties": "",
"hide_for_observation_number": "",
"autofill_from_observation1": false,
"attachment": "",
"attachment_max_count": "",
"remarks": false,
"default": ""
}
]
}
}
GET /external/v1/smarttables/{smarttable_id}/versions
#
A SmartTable's schema versions.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/versions" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"versions": [
{
"version": 4,
"approved": true,
"source": "sharepoint",
"created_at": "2026-10-01T08:00:00Z",
"field_count": 12
}
]
}
POST /external/v1/smarttables
#
Create a SmartTable from a field list (it then waits for approval in the app).
Needs smarttables:write on all SmartTables.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
name | body | string | Yes | At most 255 characters |
fields | body | array | Yes | Fields with the schema builder's columns |
is_relational | body | boolean | No | Default true |
observation_count | body | integer | No | 1 to 50 |
curl -X POST "{{base_url}}/external/v1/smarttables" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"name": "Dispatch Log", "is_relational": false, "observation_count": 1, "fields": [{"name": "Truck number", "ui_smarttable_element": "text"}, {"name": "Weight (t)", "ui_smarttable_element": "number", "optional": true}]}'{
"status": "success",
"smarttable_id": 88,
"name": "Dispatch Log",
"message": "Created; it is usable once approved in the app"
}
PUT /external/v1/smarttables/{smarttable_id}/schema
#
Change a SmartTable's fields (creates a new version).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
fields | body | array | Yes | The full field list; keep existing ids |
allow_remove | body | boolean | No | Allow leaving out existing fields |
allow_type_change | body | boolean | No | Allow changing a field's type |
curl -X PUT "{{base_url}}/external/v1/smarttables/61/schema" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"fields": [{"id": 1, "name": "Truck number", "ui_smarttable_element": "text"}, {"name": "Driver phone", "ui_smarttable_element": "text", "optional": true}]}'{
"status": "success",
"smarttable_id": 61,
"version": 5,
"message": "Saved; a new version may need approval in the app"
}
DELETE /external/v1/smarttables/{smarttable_id}
#
Delete a SmartTable.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X DELETE "{{base_url}}/external/v1/smarttables/61" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Deleted",
"smarttable_id": 61
}Display layouts
GET /external/v1/smarttables/{smarttable_id}/display
#
A SmartTable's display (print) layout: the latest approved version, or ?version=N.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
version | query | integer | No | A version number (default the latest approved) |
include_unapproved | query | string | No | 1 to include versions not approved yet |
curl -X GET "{{base_url}}/external/v1/smarttables/61/display?version=3" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"display": {
"version": 3,
"approved": true,
"created_at": "2026-09-20T07:30:00Z",
"layout": {
"cells": [
{
"address": "B2",
"row": 1,
"column": 1,
"value": "<pa_1>",
"font": {
"bold": true,
"name": "Calibri",
"size": 11
},
"column_width": 18,
"row_height": 15
}
]
}
}
}
GET /external/v1/smarttables/{smarttable_id}/display/versions
#
A SmartTable's display layout versions.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/display/versions" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"versions": [
{
"version": 3,
"approved": true,
"created_at": "2026-09-20T07:30:00Z"
}
]
}SharePoint and Google Sheets
GET /external/v1/smarttables/{smarttable_id}/source
#
Where a SmartTable's schema comes from (SharePoint, Google Sheets or the schema builder).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/source" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"source": "sharepoint",
"url": "https://contoso.sharepoint.com/sites/ops/Shared%20Documents/dispatch.xlsx",
"sync_locked": false
}
POST /external/v1/smarttables/{smarttable_id}/sync
#
Refresh a SmartTable from its spreadsheet (new versions may need approval in the app).
At most 20 refreshes and creates per hour.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X POST "{{base_url}}/external/v1/smarttables/61/sync" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"source": "sharepoint",
"versions_updated": true,
"entry_version": 5,
"display_version": 3
}
POST /external/v1/smarttables/from-source
#
Create a SmartTable from a SharePoint or Google Sheets file (it then waits for approval in the app).
Needs smarttables.sources:write and smarttables:write, both on all SmartTables.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
name | body | string | Yes | At most 255 characters |
sharepoint_url | body | string | No | https link on *.sharepoint.com |
google_sheets_url | body | string | No | https link on docs.google.com (instead of sharepoint_url) |
is_relational | body | boolean | No | Default false |
observation_count | body | integer | No | 1 to 50 |
curl -X POST "{{base_url}}/external/v1/smarttables/from-source" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"name": "Vehicle Master", "sharepoint_url": "https://contoso.sharepoint.com/sites/ops/Shared%20Documents/vehicles.xlsx", "is_relational": true}'{
"status": "success",
"smarttable_id": 89,
"name": "Vehicle Master",
"message": "Created; it is usable once approved in the app"
}SmartTable settings
GET /external/v1/smarttables/{smarttable_id}/settings
#
A SmartTable's settings.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/settings" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"settings": {
"observation_count": 1,
"submit_button_label": "Submit",
"show_observation_number": false,
"show_min_max_values": true,
"is_autosave_enabled": true,
"autosave_enabled_by_default": false,
"enable_attestation": false,
"require_submitter_signature": false,
"enable_notification_comments": false,
"enable_notes": false,
"enable_entry_access_control": false,
"autosave_interval": 60,
"freeze_columns_fields": [
1
],
"filter_fields": [
8
],
"pdf_filename_fields": [
1
],
"primary_field_id": null,
"entries_page_size": 100,
"show_entries": "all",
"show_entries_attribute_id": null,
"submit_admin_users": [],
"unsubmit_admin_users": [],
"attest_users": [],
"submit_notification_users": [],
"offline_enabled": false,
"compress_attachments": true
}
}
PATCH /external/v1/smarttables/{smarttable_id}/settings
#
Change some of a SmartTable's settings (only the keys sent).
Saves a new settings version and returns all settings.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
<setting> | body | any | Yes | Only the settings to change (see the guide for the list) |
curl -X PATCH "{{base_url}}/external/v1/smarttables/61/settings" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"submit_button_label": "Send", "autosave_interval": 30}'{
"status": "success",
"smarttable_id": 61,
"version": 7,
"settings": {
"observation_count": 1,
"submit_button_label": "Send",
"show_observation_number": false,
"show_min_max_values": true,
"is_autosave_enabled": true,
"autosave_enabled_by_default": false,
"enable_attestation": false,
"require_submitter_signature": false,
"enable_notification_comments": false,
"enable_notes": false,
"enable_entry_access_control": false,
"autosave_interval": 30,
"freeze_columns_fields": [
1
],
"filter_fields": [
8
],
"pdf_filename_fields": [
1
],
"primary_field_id": null,
"entries_page_size": 100,
"show_entries": "all",
"show_entries_attribute_id": null,
"submit_admin_users": [],
"unsubmit_admin_users": [],
"attest_users": [],
"submit_notification_users": [],
"offline_enabled": false,
"compress_attachments": true
}
}Approval workflow
GET /external/v1/smarttables/{smarttable_id}/approval-workflow
#
A SmartTable's approval workflow.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/approval-workflow" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"approval_workflow": {
"enabled": true,
"interleaved": false,
"step0": {
"enabled": false,
"notify_on_later_steps": false,
"deadline_days": 0
},
"steps": [
{
"step": 1,
"mode": "any",
"approvers": [
12,
15
],
"notify_on_later_steps": false,
"deadline_days": 2
}
],
"on_publish": {
"notify_users": [],
"email_users": [
30
],
"email": {
"subject": "Approved",
"body": "Please find the PDF attached.",
"signature": ""
}
}
}
}
PUT /external/v1/smarttables/{smarttable_id}/approval-workflow
#
Replace a SmartTable's approval workflow (applies to entries created afterwards).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
enabled | body | boolean | Yes | false turns approvals off |
steps | body | array | No | 1 to 20 steps: mode any|all, approvers (user ids), deadline_days |
step0 | body | object | No | enabled, notify_on_later_steps, deadline_days |
on_publish | body | object | No | notify_users, email_users, email {subject, body, signature} |
curl -X PUT "{{base_url}}/external/v1/smarttables/61/approval-workflow" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "steps": [{"mode": "any", "approvers": [12, 15], "deadline_days": 2}, {"mode": "all", "approvers": [20]}]}'{
"status": "success",
"smarttable_id": 61,
"version": 6,
"approval_workflow": {
"enabled": true,
"interleaved": false,
"step0": {
"enabled": false,
"notify_on_later_steps": false,
"deadline_days": 0
},
"steps": [
{
"step": 1,
"mode": "any",
"approvers": [
12,
15
],
"notify_on_later_steps": false,
"deadline_days": 2
}
],
"on_publish": {
"notify_users": [],
"email_users": [
30
],
"email": {
"subject": "Approved",
"body": "Please find the PDF attached.",
"signature": ""
}
}
}
}SmartTable Steps
GET /external/v1/smarttables/{smarttable_id}/steps
#
A SmartTable's steps and who is assigned to each.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/steps" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"steps": [
{
"step_number": 1,
"step_name": "Gate in",
"sheet_step_name": "Gate in",
"field_count": 6,
"assignees": {
"users": [
12
]
},
"resolved_users": [
{
"id": 12,
"name": "Asha Patel"
}
],
"show_to_later_steps": false
}
]
}
PUT /external/v1/smarttables/{smarttable_id}/steps
#
Set who is assigned to each step (steps left out are deactivated).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
steps | body | array | Yes | step_number + assignees {users, attributes}; left out = deactivated |
curl -X PUT "{{base_url}}/external/v1/smarttables/61/steps" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"steps": [{"step_number": 1, "assignees": {"users": [12]}}]}'{
"status": "success",
"smarttable_id": 61,
"steps": [
{
"step_number": 1,
"step_name": "Gate in",
"sheet_step_name": "Gate in",
"field_count": 6,
"assignees": {
"users": [
12
]
},
"resolved_users": [
{
"id": 12,
"name": "Asha Patel"
}
],
"show_to_later_steps": false
}
]
}Access
GET /external/v1/smarttables/{smarttable_id}/access
#
Who has access to a SmartTable, and with which role.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/access" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"access": [
{
"user_id": 12,
"name": "Asha Patel",
"username": "asha.patel",
"role": "admin",
"is_api_client": false
}
]
}
POST /external/v1/smarttables/{smarttable_id}/access
#
Give users access to a SmartTable (role: admin, user or viewer).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
user_ids | body | array of integer | Yes | Active users of your organization |
role | body | string | No | admin, user (default) or viewer |
curl -X POST "{{base_url}}/external/v1/smarttables/61/access" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"user_ids": [12, 15], "role": "user"}'{
"status": "success",
"smarttable_id": 61,
"granted": [
15
],
"already_had_access": [
12
],
"role": "user"
}
PUT /external/v1/smarttables/{smarttable_id}/access/{user_id}
#
Change a user's role on a SmartTable.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
user_id | path | integer | Yes | A user id of your organization |
role | body | string | Yes | admin, user or viewer |
force | body | boolean | No | Go ahead although the user holds an in-progress step |
curl -X PUT "{{base_url}}/external/v1/smarttables/61/access/15" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"role": "viewer"}'{
"status": "success",
"smarttable_id": 61,
"user_id": 15,
"role": "viewer"
}
DELETE /external/v1/smarttables/{smarttable_id}/access/{user_id}
#
Remove a user's access to a SmartTable.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
user_id | path | integer | Yes | A user id of your organization |
force | query | string | No | true: remove although the user holds an in-progress step |
curl -X DELETE "{{base_url}}/external/v1/smarttables/61/access/15" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Access removed",
"smarttable_id": 61,
"user_id": 15
}
GET /external/v1/access/users
#
The organization's users (id, name, username), to give access to.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
search | query | string | No | Name or username |
page | query | integer | No | From 1 |
curl -X GET "{{base_url}}/external/v1/access/users?search=asha" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"users": [
{
"user_id": 12,
"name": "Asha Patel",
"username": "asha.patel"
}
],
"page": 1,
"page_size": 100,
"total_count": 1
}
GET /external/v1/smarttables/{smarttable_id}/entry-access
#
A SmartTable's entry access rules (who can view, edit and administer its rows).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/entry-access" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"feature_enabled_on_server": true,
"enabled": true,
"rules": {
"view": {
"match_creator_attribute": "5"
},
"edit": {
"creator_only": true
},
"admin": []
},
"show_entries": "all"
}
PUT /external/v1/smarttables/{smarttable_id}/entry-access
#
Set a SmartTable's entry access rules and switch them on or off (new version).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
enabled | body | boolean | No | Switch entry access control on or off |
rules | body | object | No | view / edit / admin: users, attributes, creator_only, match_creator_attribute, or null |
curl -X PUT "{{base_url}}/external/v1/smarttables/61/entry-access" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "rules": {"view": {"match_creator_attribute": "5"}, "edit": {"creator_only": true, "users": [12]}}}'{
"status": "success",
"smarttable_id": 61,
"feature_enabled_on_server": true,
"enabled": true,
"rules": {
"view": {
"match_creator_attribute": "5"
},
"edit": {
"creator_only": true,
"users": [
12
]
},
"admin": []
},
"show_entries": "all"
}
PATCH /external/v1/smarttables/data/{smarttable_data_id}/access
#
Set who can view, edit or administer one row (overrides the SmartTable default).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
view | edit | admin | body | object or null | Yes | {"users": [...], "attributes": {attr id: [values]}}; null = back to the SmartTable default |
curl -X PATCH "{{base_url}}/external/v1/smarttables/data/189862/access" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"view": {"users": [12]}, "edit": null}'{
"status": "success",
"smarttable_data_id": 189862,
"access": {
"view": {
"users": [
12
]
}
}
}Folders
GET /external/v1/folders
#
List folders.
curl -X GET "{{base_url}}/external/v1/folders" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"folders": [
{
"folder_id": 7,
"name": "Dispatch",
"smarttable_ids": [
61,
62
],
"shared_with": [
{
"user_id": 12,
"name": "Asha Patel"
}
]
}
]
}
POST /external/v1/folders
#
Create a folder (needs folders:write on all folders).
Needs folders:write on all folders.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
name | body | string | Yes | At most 255 characters |
curl -X POST "{{base_url}}/external/v1/folders" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"name": "Dispatch"}'{
"status": "success",
"folder": {
"folder_id": 7,
"name": "Dispatch",
"smarttable_ids": [],
"shared_with": []
}
}
PATCH /external/v1/folders/{folder_id}
#
Rename a folder.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
folder_id | path | integer | Yes | A folder id |
name | body | string | Yes | At most 255 characters |
curl -X PATCH "{{base_url}}/external/v1/folders/7" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"name": "Dispatch (North)"}'{
"status": "success",
"folder": {
"folder_id": 7,
"name": "Dispatch (North)",
"smarttable_ids": [
61,
62
],
"shared_with": [
{
"user_id": 12,
"name": "Asha Patel"
}
]
}
}
PUT /external/v1/folders/{folder_id}/smarttables
#
Set a folder's SmartTables (a SmartTable is in at most one folder).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
folder_id | path | integer | Yes | A folder id |
smarttable_ids | body | array of integer | Yes | The folder's SmartTables, at most 500 |
curl -X PUT "{{base_url}}/external/v1/folders/7/smarttables" \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{"smarttable_ids": [61, 62]}'{
"status": "success",
"folder": {
"folder_id": 7,
"name": "Dispatch",
"smarttable_ids": [
61,
62
],
"shared_with": [
{
"user_id": 12,
"name": "Asha Patel"
}
]
}
}
DELETE /external/v1/folders/{folder_id}
#
Delete a folder (its SmartTables are not deleted).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
folder_id | path | integer | Yes | A folder id |
curl -X DELETE "{{base_url}}/external/v1/folders/7" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"message": "Deleted",
"folder_id": 7
}History
GET /external/v1/smarttables/{smarttable_id}/history
#
A SmartTable's history: versions, approvals, settings changes, bulk uploads.
Times are in IST (the app's display time).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/history" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"history": [
{
"event": "ENTRY_VERSION_CREATED",
"action": "ENTRY_VERSION_CREATED",
"timestamp": "2026-10-01 13:30:00",
"performed_by": "Asha Patel",
"details": {
"version": 5,
"approved": 1
}
}
]
}
GET /external/v1/smarttables/{smarttable_id}/settings-log
#
A SmartTable's settings changes (latest 100).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_id | path | integer | Yes | The SmartTable id |
curl -X GET "{{base_url}}/external/v1/smarttables/61/settings-log" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_id": 61,
"changes": [
{
"id": 85235,
"event": "SMART_TABLE_SETTINGS_UPDATED",
"timestamp": "2026-10-02 11:42:00",
"user_name": "Asha Patel",
"details": {
"autosave_interval": "30",
"submit_button_label": "Send"
}
}
]
}
GET /external/v1/smarttables/data/{smarttable_data_id}/history
#
A row's history: saves, submits, approvals, deletes.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
smarttable_data_id | path | integer | Yes | A row (observation) id |
curl -X GET "{{base_url}}/external/v1/smarttables/data/189862/history" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"smarttable_data_id": 189862,
"history": [
{
"event": "SMART_TABLE_DATA_SAVED",
"timestamp": "2026-10-12 15:11:07",
"performed_by": "Acme Logistics (integration)",
"details": []
}
]
}Users (read only)
GET /external/v1/users
#
List the organization's users (paged; search, role, active, attribute filters).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
search | query | string | No | Name, username or email |
role | query | string | No | A role name |
active | query | string | No | 1 active, 0 inactive |
attribute_id | query | integer | No | Users with this attribute set |
attribute_value | query | string | No | With attribute_id: that exact value |
page | query | integer | No | From 1; 100 per page |
curl -X GET "{{base_url}}/external/v1/users?search=asha&active=1" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"users": [
{
"user_id": 12,
"name": "Asha Patel",
"username": "asha.patel",
"email": "asha.patel@example.com",
"role": "User",
"active": true,
"mfa_enabled": false,
"attributes": [
{
"attribute_id": 5,
"name": "Department",
"value": "Logistics"
}
],
"created_at": "2026-03-02T05:10:00Z",
"updated_at": "2026-09-28T11:02:43Z"
}
],
"page": 1,
"page_size": 100,
"total_count": 1,
"total_pages": 1
}
GET /external/v1/users/{user_id}
#
One user.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
user_id | path | integer | Yes | A user id of your organization |
curl -X GET "{{base_url}}/external/v1/users/12" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"user": {
"user_id": 12,
"name": "Asha Patel",
"username": "asha.patel",
"email": "asha.patel@example.com",
"role": "User",
"active": true,
"mfa_enabled": false,
"attributes": [
{
"attribute_id": 5,
"name": "Department",
"value": "Logistics"
}
],
"created_at": "2026-03-02T05:10:00Z",
"updated_at": "2026-09-28T11:02:43Z"
}
}
GET /external/v1/users/{user_id}/smarttables
#
The SmartTables a user has been given access to, and their role on each (only SmartTables this client may read the access of).
Lists only SmartTables your access:read covers.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
user_id | path | integer | Yes | A user id of your organization |
curl -X GET "{{base_url}}/external/v1/users/12/smarttables" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"user_id": 12,
"smarttables": [
{
"smarttable_id": 61,
"name": "Dispatch Log",
"role": "admin"
}
]
}
GET /external/v1/roles
#
The organization's roles.
curl -X GET "{{base_url}}/external/v1/roles" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"roles": [
{
"role_id": 3,
"name": "User"
}
]
}
GET /external/v1/user-attributes
#
The organization's user attributes (definitions).
curl -X GET "{{base_url}}/external/v1/user-attributes" \
-H "Authorization: Bearer {{access_token}}"{
"status": "success",
"attributes": [
{
"attribute_id": 5,
"name": "Department",
"type": "TEXT_INPUT",
"default_value": null,
"is_filter": true
}
]
}Errors
Errors come back as {"status": "error", "error": "…", "code": "…"}. Program against code.
| Status | code | Meaning |
|---|---|---|
| 400 | invalid_request | A value is missing or wrong; the message says which. |
| 400 | rejected | The SmartTable's own rules refused it (validation, adding off, submitted and locked). |
| 401 | — | Missing, expired or invalid token. |
| 403 | permission_denied | The token lacks the permission; details.required_permission names it. |
| 404 | not_found | Doesn't exist, isn't covered by your permission, or (for changes) isn't yours. |
| 409 | conflict codes | not_approved, not_deleted, not_submitted, steps_pending, sync_locked, … |
| 429 | rate_limited | Too many requests; wait and retry. |
Generated 2026-10-12 from the API itself; every sample is checked against the live API before release.