Custom Table
Custom tables provide multi-tenant data storage within Hyphen. Create tables with typed fields, then read, write, update, and upsert records from workflows. Every mutation is audit-logged.
Creating a Table
Tables are created via API before use in workflows:
curl -X POST http://localhost:3009/custom-tables \
-H "X-Org-Id: acme-corp" \
-H "Content-Type: application/json" \
-d '{
"name": "reconciliation_log",
"fields": [
{ "name": "run_id", "type": "text", "required": true },
{ "name": "invoice_id", "type": "text", "required": true },
{ "name": "amount", "type": "numeric", "required": false },
{ "name": "status", "type": "text", "required": true },
{ "name": "matched", "type": "boolean", "required": false },
{ "name": "processed_at", "type": "timestamptz", "required": false }
]
}'
/custom-tablesCreate a new custom table with typed field definitions.
Field Types
| Type | Description | Example Values |
|---|---|---|
text |
String value, optional maxLength |
"INV-001", "pending" |
integer |
Whole numbers | 42, 0, -5 |
numeric |
Decimal numbers | 1500.50, 0.02 |
boolean |
True/false | true, false |
timestamptz |
Timestamp with timezone | "2025-01-15T10:30:00Z" |
Usage in Workflows
Use type: "custom-table" as a workflow step with the desired operation.
Write (Insert)
{
"type": "custom-table",
"properties": {
"table": "reconciliation_log",
"operation": "write",
"keys": ["run_id", "invoice_id"],
"values": ["@__run_id", "@input.invoice_id"],
"fields": {
"amount": "@input.amount",
"status": "processed",
"matched": true,
"processed_at": "@now"
}
}
}
Read (Query)
{
"type": "custom-table",
"properties": {
"table": "reconciliation_log",
"operation": "read",
"keys": ["invoice_id"],
"values": ["@input.invoice_id"]
},
"outputKey": "previous_runs"
}
Results are stored in context under the outputKey.
Update
{
"type": "custom-table",
"properties": {
"table": "reconciliation_log",
"operation": "update",
"keys": ["run_id"],
"values": ["@__run_id"],
"fields": {
"status": "approved",
"matched": true
}
}
}
Updates records matching the keys/values criteria with the new fields.
Upsert (Insert or Update)
{
"type": "custom-table",
"properties": {
"table": "vendor_preferences",
"operation": "upsert",
"keys": ["vendor_id"],
"values": ["@input.vendor_id"],
"fields": {
"preferred_payment": "@input.payment_method",
"last_updated": "@now"
}
}
}
If a record with the matching keys exists, it's updated. Otherwise, a new record is created.
Properties Reference
| Property | Type | Required | Description |
|---|---|---|---|
table |
string | Yes | Table name |
operation |
string | Yes | "read", "write", "update", or "upsert" |
keys |
string[] | Yes | Field names used to identify records |
values |
array | Yes | Values corresponding to keys (supports @path) |
fields |
object | No | Additional fields to write/update (supports @path values) |
Direct API Access
Tables can also be accessed directly via REST API, outside of workflows:
/custom-tables/:tableNameView all data in a custom table.
/custom-tables/:tableName/insertInsert a single record.
/custom-tables/:tableName/bulk-insertInsert multiple records at once.
/custom-tables/:tableName/updateUpdate records matching criteria.
Audit Log
Every mutation (write, update, upsert) is logged in the table's audit trail. The audit log records who made the change, when, what the previous value was, and what the new value is.
curl -X GET http://localhost:3009/custom-tables/reconciliation_log/audit \
-H "X-Org-Id: acme-corp"
/custom-tables/:tableName/auditView the audit log for a custom table.
Multi-Tenant Isolation
Custom tables are fully scoped per organization. A table named reconciliation_log in org acme-corp is completely separate from a table with the same name in org globex-inc. There is no cross-org data access.
Common Patterns
Workflow audit log: Write a record after every workflow run with key metrics ā matched count, exception count, approval status, timestamp.
Operational memory: Store intermediate results across workflow runs. An agent can read from a custom table to check whether an invoice was previously processed before investigating it again.
State tracking: Track the status of long-running multi-step processes. Each workflow run updates the record as it progresses through stages.
ā Next: Actions ā registering reusable operations