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:

bash
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 }
    ]
  }'
POST/custom-tables

Create 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)

json
{
  "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)

json
{
  "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

json
{
  "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)

json
{
  "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:

GET/custom-tables/:tableName

View all data in a custom table.

POST/custom-tables/:tableName/insert

Insert a single record.

POST/custom-tables/:tableName/bulk-insert

Insert multiple records at once.

PUT/custom-tables/:tableName/update

Update 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.

bash
curl -X GET http://localhost:3009/custom-tables/reconciliation_log/audit \
  -H "X-Org-Id: acme-corp"
GET/custom-tables/:tableName/audit

View 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