Skip to main content

Custom Tables

Overview

Custom Tables allow you to extend the Skills Workflow data model by creating your own tables with custom columns and data types. They are ideal for storing additional structured data that does not fit into standard document fields — for example, product catalogs, specification mappings, or lookup tables.

Custom tables support:

  • Custom schema — define your own columns with specific data types
  • Role-based permissions — control who can read and who can write
  • Full CRUD — create, read, update, and delete via the UI, SDK, or API
  • Query integration — read data using SQL queries with the CustomTable namespace
  • Import / Export — bulk data management via JSON files

  1. Go to Maintenance in the main menu
  2. Select the Custom Tables module

You will see a list of all existing custom tables in the system.

img

Custom Tables list in Maintenance

Creating a Custom Table

To create a new custom table:

  1. Click the + button in the Custom Tables list
  2. Enter the Table Name (must be unique, no spaces — use PascalCase, e.g. ProductCatalog)
  3. Define the Key Column — typically Oid with data type UniqueIdentifier (GUID)
  4. Add Columns with their names and data types

img

Creating a new custom table
note

Column names should use PascalCase (e.g. ProductName, IsActive). Once a column is created, its data type cannot be changed — only new columns can be added.


Managing Permissions

Each custom table has two permission roles:

  • Read Role — determines which users can read data from the table
  • Save Role — determines which users can insert, update, or delete data

To configure permissions:

  1. Select a custom table from the list
  2. In the Permissions panel, set the Read Role and Save Role
  3. Click Save

img-box-shadow

Configuring Read and Save roles

Viewing Data

After selecting a custom table, the data grid displays all stored rows with their column values.

The grid shows:

  • The key column (e.g. Oid)
  • All custom columns and their current values
  • A row count at the bottom

img

Custom table data grid

Reading Data via Queries

To read custom table data using SQL queries:

  1. Navigate to Maintenance → Queries
  2. Create or edit a query
  3. Set the Namespace to CustomTable
  4. Write your SQL referencing the table as [customtables].[YourTableName]

Example:

SELECT Oid, Name, Price, IsActive
FROM [customtables].[ProductCatalog]
WHERE IsActive = 1
ORDER BY Name
note

The CustomTable namespace is required for the query engine to resolve custom table references at runtime. Without it, the query will not find your tables.


SDK Reference

Use the SDK methods below to interact with custom tables programmatically from workspaces, automations, or any JavaScript context inside Skills Workflow.

Namespace: SW.Document.CustomTable

View SDK Methods

get

Description

Fetches all rows from a custom table and returns them as flat JavaScript objects (column names as keys). Optionally sorts the result by a column on the client side.

Method(s)

declare function get(
customTableName: string,
orderByColumnName?: string
): Promise<object[]>
ParameterTypeRequiredDefaultsDescription
customTableNamestringtrueName of the custom table
orderByColumnNamestringfalsenullColumn name to sort the results by (client-side)

Basic Usage

// Get all rows from the "ProductCatalog" table
const rows = await SW.Document.CustomTable.get("ProductCatalog");

// Get rows sorted by "Name"
const sorted = await SW.Document.CustomTable.get("ProductCatalog", "Name");

create

Description

Creates a new custom table definition, or adds columns to an existing table. Defines the key column and the schema (column names and data types).

Method(s)

declare function create(
customTableName: string,
model: CustomTablePostModel
): Promise<any>
ParameterTypeRequiredDefaultsDescription
customTableNamestringtrueName of the custom table to create
modelCustomTablePostModeltrueTable definition including key column and columns

CustomTablePostModel

PropertyTypeRequiredDescription
KeyColumnNamestringtrueName of the primary key column (e.g. "Oid")
KeyDataTypeIdnumberfalseData type of the key column (see Data Types table below)
ColumnsCustomTableColumnPostModel[]trueArray of column definitions

Basic Usage

await SW.Document.CustomTable.create("ProductCatalog", {
KeyColumnName: "Oid",
KeyDataTypeId: 9, // UniqueIdentifier
Columns: [
{ ColumnName: "Name", ColumnDataTypeId: 6 }, // Varchar100
{ ColumnName: "Price", ColumnDataTypeId: 4 }, // Money
{ ColumnName: "IsActive", ColumnDataTypeId: 0 }, // Boolean
]
});

insert

Description

Inserts or updates one or more rows in a custom table. Accepts a single row or an array of rows. Each row defines its key and column values.

Method(s)

declare function insert(
customTableName: string,
rows: CustomTableRowPostModel | CustomTableRowPostModel[]
): Promise<any[]>
ParameterTypeRequiredDefaultsDescription
customTableNamestringtrueName of the custom table
rowsCustomTableRowPostModel | CustomTableRowPostModel[]trueOne row or an array of rows to insert/update

CustomTableRowPostModel

PropertyTypeRequiredDescription
KeyValueanyfalseValue of the key column for this row (e.g. a GUID)
KeyColumnNamestringfalseName of the key column (e.g. "Oid")
ColumnsCustomTableRowColumnPostModel[]trueArray of column name/value pairs for this row

CustomTableRowColumnPostModel

PropertyTypeRequiredDescription
ColumnNamestringtrueColumn name
ColumnDataTypeIdnumberfalseData type ID (see Data Types table)
ValueanytrueThe value to store

Basic Usage

// Insert a single row
await SW.Document.CustomTable.insert("ProductCatalog", {
KeyValue: SW.Utils.Guid.getNew(),
KeyColumnName: "Oid",
Columns: [
{ ColumnName: "Name", ColumnDataTypeId: 6, Value: "Widget A" },
{ ColumnName: "Price", ColumnDataTypeId: 4, Value: 29.99 },
{ ColumnName: "IsActive", ColumnDataTypeId: 0, Value: true },
]
});

// Insert multiple rows at once
await SW.Document.CustomTable.insert("ProductCatalog", [
{
KeyValue: SW.Utils.Guid.getNew(),
KeyColumnName: "Oid",
Columns: [
{ ColumnName: "Name", Value: "Widget A" },
{ ColumnName: "Price", Value: 29.99 },
]
},
{
KeyValue: SW.Utils.Guid.getNew(),
KeyColumnName: "Oid",
Columns: [
{ ColumnName: "Name", Value: "Widget B" },
{ ColumnName: "Price", Value: 49.99 },
]
}
]);

Data Types Reference

Each column has a ColumnDataTypeId that defines the SQL data type used for storage.

IDTypeDescription
0BooleanTrue / False
1DateDate value
2FloatDecimal number
3IntegerWhole number
4MoneyCurrency value
5Varchar50Text (max 50 chars)
6Varchar100Text (max 100 chars)
7VarcharMaxText (unlimited)
8TextLarge text
9UniqueIdentifierGUID / UUID
10Varchar200Text (max 200 chars)

API Reference

For external integrations or direct HTTP calls, use the REST API endpoints below.

View API Endpoints

All endpoints require authentication via the X-AccessToken header.

Base path: api/v3

Endpoints

MethodRouteDescription
GET/custom-tablesList all custom tables
GET/custom-tables/{tableName}Get table schema and columns
GET/custom-tables/{tableName}/rows/valuesGet all rows with column values
GET/custom-tables/{tableName}/rowGet a single row by key
GET/custom-tables/{tableName}/rows/columnValueGet a specific column value from a row
POST/custom-tables/{tableName}Create table / add columns
PUT/custom-tables/{tableName}/rowsInsert or update rows
PUT/custom-table-definitions/{id}Update table permissions (Read/Save roles)
DELETE/custom-tables/{tableName}/rowsDelete rows
DELETE/custom-tables/{tableName}Drop the entire table
GET/custom-tables/{tableName}/exportExport table to JSON file
PUT/custom-tables/{tableName}/importImport table from JSON file

Insert / Update Rows

PUT /api/v3/custom-tables/{tableName}/rows

The request body uses OperationType to control the behavior:

OperationTypeValueDescription
Update0Update a single row
UpdateMany1Insert or update multiple rows (batch)
UpsertMany2Insert if not exists, update if exists (batch)

Single row (Update)

{
"OperationType": "Update",
"UpdateModel": {
"KeyColumnName": "Oid",
"KeyValue": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"KeyDataTypeId": 9,
"Columns": [
{ "ColumnName": "Name", "Value": "Updated Product" },
{ "ColumnName": "Price", "Value": 39.99 }
]
}
}

Multiple rows (UpdateMany)

{
"OperationType": "UpdateMany",
"UpdateManyModel": [
{
"KeyColumnName": "Oid",
"KeyValue": "a1b2c3d4-0000-0000-0000-000000000001",
"KeyDataTypeId": 9,
"Columns": [
{ "ColumnName": "Name", "Value": "Product A" },
{ "ColumnName": "Category", "Value": "Electronics" }
]
},
{
"KeyColumnName": "Oid",
"KeyValue": "a1b2c3d4-0000-0000-0000-000000000002",
"KeyDataTypeId": 9,
"Columns": [
{ "ColumnName": "Name", "Value": "Product B" },
{ "ColumnName": "Category", "Value": "Furniture" }
]
}
]
}

Delete Rows

DELETE /api/v3/custom-tables/{tableName}/rows

OperationTypeValueDescription
Delete0Delete a single row by key
DeleteAll1Delete all rows in the table
DeleteMany2Delete multiple rows by key values

Single row (Delete)

{
"OperationType": "Delete",
"DeleteModel": {
"KeyColumnName": "Oid",
"KeyValue": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}

Multiple rows (DeleteMany)

{
"OperationType": "DeleteMany",
"DeleteManyModel": {
"KeyColumnName": "Oid",
"KeyValues": [
"a1b2c3d4-0000-0000-0000-000000000001",
"a1b2c3d4-0000-0000-0000-000000000002"
]
}
}

All rows (DeleteAll)

{
"OperationType": "DeleteAll"
}

Create Table

POST /api/v3/custom-tables/{tableName}

Creates a new custom table with the specified schema. If the table already exists, adds the new columns.

{
"KeyColumnName": "Oid",
"KeyDataTypeId": 9,
"Columns": [
{ "ColumnName": "Name", "ColumnDataTypeId": 6 },
{ "ColumnName": "Price", "ColumnDataTypeId": 4 },
{ "ColumnName": "IsActive", "ColumnDataTypeId": 0 }
]
}

Get Row Values

GET /api/v3/custom-tables/{tableName}/rows/values

Returns all rows in the table. Each row includes the KeyColumnName, KeyValue, and a Columns array:

[
{
"TableName": "ProductCatalog",
"KeyValue": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"KeyColumnName": "Oid",
"KeyDataTypeId": 9,
"Columns": [
{ "ColumnName": "Name", "ColumnDataTypeId": 6, "Value": "Product A" },
{ "ColumnName": "Price", "ColumnDataTypeId": 4, "Value": 29.99 }
]
}
]

Reading Data via Queries

You can also read custom table data using Queries (created in Maintenance → Queries). When writing SQL queries that reference custom tables, use CustomTable as the namespace (schema context).

The actual database schema is [customtables], so the table is accessible as [customtables].[YourTableName] in SQL.

Example query:

SELECT Oid, Name, Price, IsActive
FROM [customtables].[ProductCatalog]
WHERE IsActive = 1
ORDER BY Name
note

Queries must be created with the namespace set to CustomTable in the query configuration to resolve the correct schema context at runtime.