Let an outside system, such as a vendor, an ERP or a weighbridge, work with your SmartTables over a secure API: entries, attachments, settings, approval workflows, access and folders. The same rules apply as in the app.
Overview
The vendor gets its own client ID and secret, not a PersivApps user account. It signs in to get a short-lived access token, then calls the API with it. Every call goes through the same logic the app uses: formulas, autofill, auto-numbered fields, approval workflows, notifications, automations and the audit trail all run as if a person had done it.
Base URL: your PersivApps API address, for example https://your-host/persivapps/service. Every path below starts with <base URL>/external/v1/. A trailing slash is optional.
Every call with sample requests and responses: the API Reference, searchable, with a downloadable Postman collection and PDF.
Machine-readable reference:GET <base URL>/external/v1/openapi.json describes every call, for tools such as Postman.
Earlier paths:/external/auth/login, /external/smarttables/data/save and /external/smarttables/data/<id>/update (without /v1) still work and behave the same.
What a vendor can and can't do
Only what it has permission for. Each vendor is given permissions such as entries:read or smarttables.settings:write. Each call below lists the permission it needs; a token without it gets permission_denied.
Only the SmartTables (or folders) its permission covers. Each permission covers all of your organization's SmartTables, chosen ones, or those in chosen folders. Anything outside returns "not found", the same as an ID that doesn't exist. Nothing in another organization is ever reachable.
Only its own entries, by default. Updating, deleting, restoring and changing attachments work only on entries the vendor created, unless it is allowed to change any entry.
Only these calls. The vendor's token is refused everywhere else in PersivApps, and these calls don't accept a normal user's login. The vendor can't sign in to the app; what it saves shows as created by a dedicated integration user named after it.
Users are read only. A vendor with users:read can list users, roles and user attributes, but never create, change or disable users, or see passwords and signatures.
Never: custom scripts, automations, changing users or passwords, organizations, or the organization's system administrator account.
GET /external/v1/me lists the vendor's permissions and the SmartTables each one covers.
Authentication
Send the client ID and secret in the body, or as HTTP Basic authentication:
Send the access token on every call as Authorization: Bearer <access_token>. It lasts 1 hour.
To renew, sign in again, or exchange the refresh token at POST <base URL>/external/v1/auth/token with grant_type=refresh_token plus your client ID and secret. Each refresh token works once.
scope (optional): a space-separated list of permissions, to get a token with fewer permissions than the vendor has. The response's scope lists what the token can do. Asking only for permissions the vendor doesn't have returns invalid_scope.
Limits on your secret. A secret can have an expiry date and can be limited to your servers' IP addresses. If sign-in suddenly returns 401 from a new server, or after a date, ask us to update it.
Call
Permission
What it does
GET /external/v1/me
any
This client, the permissions of the current token, and the SmartTables each covers
Requests, responses and errors
JSON in and out, except file uploads (multipart/form-data) and downloads.
Field IDs: entry values are keyed by field ID, the id of each field in the SmartTable's schema (GET /external/v1/smarttables/<id>).
Two IDs per entry:smarttable_data_entry_id identifies an entry; smarttable_data_id identifies one row (an observation) of it. Most row calls take the row ID.
Paging: lists take page (from 1) and page_size, and return total_count and total_pages.
Successful responses have "status": "success".
Errors come back as {"status": "error", "error": "…", "code": "…"}. Program against code; the error text may change.
Status
code
Meaning
400
invalid_request
The request is missing something or has a wrong value. The message says what.
400 / 403
rejected
The SmartTable's own rules refused it: a validation failed, adding entries is off, or the entry is submitted and locked.
401
—
The token is missing, expired or invalid, or the sign-in credentials were wrong.
403
permission_denied
The token doesn't have the permission this call needs. details.required_permission names it.
404
not_found
It doesn't exist, isn't covered by the vendor's permission, or (for changes) wasn't created by this vendor.
405
method_not_allowed
That method isn't available on this path.
409
not_approved, not_deleted, steps_pending
The SmartTable isn't approved yet; the row to restore isn't deleted; or the user holds an in-progress step (send force to go ahead).
Only a submitted row can be attested; the row isn't attested; entry access control is off on this server; the SmartTable isn't built from a spreadsheet; or it is locked against spreadsheet sync.
429
rate_limited or —
Too many requests. Wait, then retry.
Sign-in and token errors follow the OAuth 2.0 format instead: {"error": "invalid_client" | "invalid_grant" | "invalid_scope" | "unsupported_grant_type", "error_description": "…"}.
Entries
Call
Permission
What it does
GET /external/v1/smarttables/<smarttable_id>/entries
entries:read
List entries of a SmartTable (paged; search, filters, sort, created/updated time window)
GET /external/v1/smarttables/data/<smarttable_data_id>
entries:read
Read one row (an observation of an entry)
GET /external/v1/entries/<smarttable_data_entry_id>
Field values keyed by field ID. A table field takes an array, one value per row.
is_submit
No
true submits the entry and starts any approval workflow. The default saves a draft.
client_op_id
No, recommended
Your own unique ID for this save. Sending the same ID again, say after a timeout, returns the original entry (status 200, "duplicate": true) instead of creating a second one.
smarttable_data_entry_id
No
Adds a new observation to one of your entries instead of a new entry. Use it with observation_number.
⚠️ Required fields aren't enforced
Required fields are checked by the entry form, not by the save itself, as in the app. Make sure your system sends every field the SmartTable needs.
Send only the fields you want to change; the others keep their values.
An empty string means "no change", not "clear". To blank a field, list its ID in cleared_fields.
is_submit: true submits a draft. A submitted entry can be changed only if the SmartTable's settings allow it.
List entries
page_size is 50, 100, 200 or 500 (default 100).
search matches any field's value. sort is a field ID or created_at, updated_at, observation_number, entry_id, with dir=asc|desc. submitted=1|0 filters on submitted.
filters is a JSON list, for example [{"column_id": "3", "operator": "equals", "value": "Arrived"}]; at most 20.
updated_after, updated_before, created_after, created_before limit the list to a time window, as an ISO 8601 date (2026-10-01, midnight UTC) or date-time (2026-10-01T09:30:00+05:30; no offset means UTC). after includes the moment, before excludes it. To fetch only what changed since your last run, send updated_after with the time you last fetched and sort=updated_at&dir=asc.
deleted=1 lists deleted rows instead, and needs entries:delete.
The SmartTable's own "Show entries" setting applies: on a SmartTable set to show users only their own entries, the vendor sees only the entries it created.
Delete, restore and admin actions
Delete is a soft delete; POST …/restore brings the row back.
entries:admin deletes permanently (cannot be undone), unsubmits a submitted row, and releases an edit lock someone left open. These aren't limited to the vendor's own entries.
Bulk operations
Call
Permission
What it does
POST /external/v1/bulk/delete
entries.bulk:delete
Delete many rows (soft delete; can be restored). Body: {"smarttable_data_ids": [...]}
POST /external/v1/bulk/restore
entries.bulk:delete
Restore many deleted rows. Body: {"smarttable_data_ids": [...]}
POST /external/v1/bulk/delete-permanently
entries.bulk:admin
Permanently delete many rows (cannot be undone). Body: {"smarttable_data_ids": [...]}
POST /external/v1/bulk/update-version
entries.bulk:admin
Move many rows to the latest approved schema and/or display version. Body: {"smarttable_data_ids": [...], "update": "entry" | "display" | "both"}
POST /external/v1/smarttables/<smarttable_id>/bulk-upload
entries.bulk:write
Add rows to a relational SmartTable from an Excel file (multipart, key "file"; column headers = field names)
Send up to 500 row IDs as {"smarttable_data_ids": [...]}. Each ID is checked on its own: the response lists what was done and, under failed, each ID that wasn't with the reason. An ID the vendor may not use is reported as "Not found".
Bulk delete and restore, like single ones, work only on rows the vendor created unless it may change any entry. Permanent delete and the version update (entries.bulk:admin) aren't limited to its own rows.
Version update moves rows to the SmartTable's latest approved schema ("update": "entry"), display layout ("display") or both (default). Fields removed from the schema since a row was saved stop showing for it.
Excel upload works on relational SmartTables only: multipart/form-data, the workbook under file (.xlsx or .xls, at most 10 MB), first row = field names. Up to 10 uploads per hour per vendor.
Attachments
Call
Permission
What it does
GET /external/v1/smarttables/data/<smarttable_data_id>/attachments
entries.attachments:read
List a row's attachments
GET /external/v1/smarttables/data/<smarttable_data_id>/attachments/<field_id>/<filename>
entries.attachments:read
Download one attachment
POST /external/v1/smarttables/data/<smarttable_data_id>/attachments/<field_id>
entries.attachments:write
Upload files to an attachment field (multipart, key "files")
Upload with multipart/form-data, each file under the key files, up to 20 per call.
Download: the list call returns each file's path; fetch it with GET <base URL>/external/v1/<path>.
You can also attach files while creating or updating an entry: send that request as multipart/form-data, smarttable_values as a JSON string, and each file under attachments__<field_id>.
GET /external/v1/smarttables/data/<smarttable_data_id>/comments
entries.comments:read
List a row's comments and notes
POST /external/v1/smarttables/data/<smarttable_data_id>/comments
entries.comments:write
Add a comment to a row
Comments are plain text, up to 5,000 characters. The list includes notes added in the app.
Approval status
Call
Permission
What it does
GET /external/v1/entries/<smarttable_data_entry_id>/approval
entries.approvals:read
An entry's approval status, with earlier rounds
GET /external/v1/entries/<smarttable_data_entry_id>/approval/history
entries.approvals:read
Earlier approval rounds of an entry (rejected and resubmitted)
Read-only: approvers still approve or reject in the app or from their notification. The status lists each step, who approved it and any comment; signatures are never returned. An entry whose SmartTable has no approval workflow returns "approval_enabled": false.
Attestation and eSign
Call
Permission
What it does
GET /external/v1/smarttables/data/<smarttable_data_id>/attestation
entries.attestation:read
A row's attestation and eSign status
POST /external/v1/smarttables/data/<smarttable_data_id>/attestation
entries.attestation:write
Attest a row with a signature image; it is recorded as signed by this integration
Attest a submitted row with a signature image: multipart/form-data with the file under image, or JSON {"image": "<base64>"}. PNG or JPEG, at most 1 MB.
The attestation is recorded as signed by the vendor's integration user, not by a person, and the row's history shows it.
eSign (Aadhaar / eMudhra) is read only: the status call returns whether a row's document was e-signed and the transaction ID. Starting an eSign needs a person's own mobile number and OTP, so it can only be done in the app.
Exports
Call
Permission
What it does
GET /external/v1/entries/<smarttable_data_entry_id>/pdf
entries.exports:read
Download an entry's PDF (its display layout)
POST /external/v1/bulk/pdf
entries.exports:read
Download many entry PDFs as one zip. Body: {"smarttable_data_entry_ids": [...]} (at most 50)
The PDF is the entry's printed layout. Add include_attachments=false to leave attached PDFs out. Up to 30 PDFs per minute per vendor.
Many at once:POST …/bulk/pdf with {"smarttable_data_entry_ids": [...]} (at most 50) returns one zip. Entries the vendor can't read are left out and listed in the X-Skipped-Entry-Ids response header. Up to 5 zips per 5 minutes per vendor.
SmartTables and schema
Call
Permission
What it does
GET /external/v1/smarttables
smarttables:read
List the SmartTables this client can read
GET /external/v1/smarttables/<smarttable_id>
smarttables:read
A SmartTable with its current fields (schema)
GET /external/v1/smarttables/<smarttable_id>/versions
smarttables:read
A SmartTable's schema versions
POST /external/v1/smarttables
smarttables:write
Create a SmartTable from a field list (it then waits for approval in the app)
PUT /external/v1/smarttables/<smarttable_id>/schema
smarttables:write
Change a SmartTable's fields (creates a new version)
DELETE /external/v1/smarttables/<smarttable_id>
smarttables:delete
Delete a SmartTable
A field has the same columns as the schema builder: name, ui_smarttable_element (text, textarea, number, date, month, time, dropdown, multi_select_dropdown, radio_button, button_group, checkbox, attachment), optional, hide, allowed_data, properties and the other columns in the SharePoint column reference.
Creating a SmartTable needs smarttables:write on all SmartTables. The new SmartTable waits for approval in the app before entries can be saved.
Changing the schema sends the full list of fields. Keep each existing field's id; a field without an id is added. Leaving out an existing field is refused unless you send "allow_remove": true, and changing a field's type unless "allow_type_change": true, because stored values are kept by field ID and would no longer show.
GET /external/v1/smarttables/<smarttable_id>/display
smarttables.display:read
A SmartTable's display (print) layout: the latest approved version, or ?version=N
GET /external/v1/smarttables/<smarttable_id>/display/versions
smarttables.display:read
A SmartTable's display layout versions
The display layout is the printed form, as it came from the spreadsheet's display sheet: every cell with its value, style and size, and <pa_…> placeholders where entry values go. Add version=N for an older version, or include_unapproved=1 to include versions not approved yet. Layouts change only through the spreadsheet; to get a filled-in document, download the entry's PDF.
SharePoint and Google Sheets
Call
Permission
What it does
GET /external/v1/smarttables/<smarttable_id>/source
smarttables.sources:read
Where a SmartTable's schema comes from (SharePoint, Google Sheets or the schema builder)
POST /external/v1/smarttables/<smarttable_id>/sync
smarttables.sources:write
Refresh a SmartTable from its spreadsheet (new versions may need approval in the app)
POST /external/v1/smarttables/from-source
smarttables.sources:write
Create a SmartTable from a SharePoint or Google Sheets file (it then waits for approval in the app)
Refresh re-reads the SmartTable's spreadsheet, the same as Refresh in the app. Changed versions may need approval in the app. A SmartTable locked against spreadsheet sync, or built in the schema builder, returns 409.
Create takes name, and sharepoint_url or google_sheets_url (an https link on *.sharepoint.com or docs.google.com), plus optional is_relational and observation_count. It needs both smarttables.sources:write and smarttables:write on all SmartTables, and the file must be shared with your organization's PersivApps connection.
Up to 20 refreshes and creates per hour per vendor.
Settings
Call
Permission
What it does
GET /external/v1/smarttables/<smarttable_id>/settings
Steps run in the order sent. mode is any (one approver is enough) or all.
Optional: step0 (enabled, notify_on_later_steps, deadline_days), and per step notify_on_later_steps.
The new workflow applies to entries created afterwards; entries already in progress keep the workflow they started with.
Send {"enabled": false} to turn approvals off.
SmartTable Steps
Call
Permission
What it does
GET /external/v1/smarttables/<smarttable_id>/steps
smarttables.steps:read
A SmartTable's steps and who is assigned to each
PUT /external/v1/smarttables/<smarttable_id>/steps
smarttables.steps:write
Set who is assigned to each step (steps left out are deactivated)
The steps themselves come from the SmartTable's schema; this sets who is assigned to each. Send {"steps": [{"step_number": 1, "assignees": {"users": [12]}}]}. A step left out is deactivated, not deleted.
Access
Call
Permission
What it does
GET /external/v1/smarttables/<smarttable_id>/access
access:read
Who has access to a SmartTable, and with which role
POST /external/v1/smarttables/<smarttable_id>/access
access:admin
Give users access to a SmartTable (role: admin, user or viewer)
PUT /external/v1/smarttables/<smarttable_id>/access/<user_id>
Set who can view, edit or administer one row (overrides the SmartTable default)
GET /external/v1/smarttables/<smarttable_id>/entry-access
access:read
A SmartTable's entry access rules (who can view, edit and administer its rows)
PUT /external/v1/smarttables/<smarttable_id>/entry-access
access:admin
Set a SmartTable's entry access rules and switch them on or off (new version)
Roles are admin (SmartTable admin), user and viewer.
Find user IDs with GET /external/v1/access/users?search=… (or the Users calls below, with users:read).
Only active users of your organization can be given access. The organization's system administrator account, and other API clients, can't be changed.
Entry-level access (PATCH …/data/<id>/access) overrides who can view, edit or admin one row, each as {"users": [...], "attributes": {...}} or null to go back to the SmartTable's default. It works when entry-level access is turned on.
Entry access rules (…/entry-access) are the SmartTable-wide defaults behind the per-row ones. PUT takes "enabled" (true/false) and/or "rules": for view, edit and admin, a rule with any of users, attributes (attribute ID → allowed values), creator_only: true and match_creator_attribute (an attribute ID: same value as the row's creator), or null to clear it. Actions you leave out keep their rule. It saves a new version of the SmartTable's settings, and returns 409 if entry access control is switched off on the server.
Unshare a folder: removes the user's 'user' role on its SmartTables
A SmartTable is in at most one folder: adding it to a folder takes it out of any other.
Sharing a folder gives its users the user role on the folder's SmartTables; unsharing removes that role again.
Creating a folder needs folders:write on all folders.
Users (read only)
Call
Permission
What it does
GET /external/v1/users
users:read
List the organization's users (paged; search, role, active, attribute filters)
GET /external/v1/users/<user_id>
users:read
One user
GET /external/v1/users/<user_id>/smarttables
users:read
The SmartTables a user has been given access to, and their role on each (only SmartTables this client may read the access of)
GET /external/v1/roles
users:read
The organization's roles
GET /external/v1/user-attributes
users:read
The organization's user attributes (definitions)
users:read is granted for the whole organization, never for chosen SmartTables.
A user has user_id, name, username, email, role, active, mfa_enabled, attributes (each with attribute_id, name, value) and timestamps. Passwords, signatures and sign-in data are never returned.
List filters: search (name, username or email), role, active=1|0, attribute_id with optional attribute_value. 100 per page.
The organization's system administrator account and API clients' integration users aren't listed.
…/users/<id>/smarttables lists the user's roles only on SmartTables the vendor's access:read covers.
History
Call
Permission
What it does
GET /external/v1/smarttables/<smarttable_id>/history
audit:read
A SmartTable's history: versions, approvals, settings changes, bulk uploads
GET /external/v1/smarttables/<smarttable_id>/settings-log
audit:read
A SmartTable's settings changes (latest 100)
GET /external/v1/smarttables/data/<smarttable_data_id>/history
audit:read
A row's history: saves, submits, approvals, deletes
The SmartTable history covers versions, approvals, settings changes and bulk uploads. A row's history covers saves, submits, approvals and deletes.
💡 Keep the secret secret
Treat the client secret like a password. Store it in the vendor system's secure configuration, never in client-side code or a shared document. If it leaks, contact us to have it replaced.