Smart Columns

Smart columns process data per row. AI columns run prompts, HTTP columns call APIs, formula columns compute values, integration columns push data, lookup columns join across tables. The table IS the workflow.

Template Variables

Use {{column_name}} in prompts, URLs, request bodies, and run conditions to reference other columns in the same row. When the smart column runs, each {{...}} placeholder is replaced with the actual value from that row.

SyntaxDescriptionExample
{{column_name}}Value of a column in the current row{{country}} -> "France"
{{column.nested_field}}Nested field from a JSON column{{company_data.industry}} -> "SaaS"
{{column.arr[0]}}Array index from a JSON column{{metadata.tags[0]}} -> "enterprise"
In a prompt
What is the capital of {{country}}?
Reply with ONLY the city name.
In a request body
{
  "contents": [{
    "parts": [{
      "text": "Classify {{company}} ({{website}}) by industry. One word."
    }]
  }]
}
i
Where templates are used
Template variables work in: AI prompts, HTTP URLs, HTTP request bodies, HTTP headers, integration body templates, and run condition expressions.

Column Kinds

Every smart column has a kind that determines what it does when processing a row. There are 5 kinds:

KindWhat It DoesConfig KeysRate Limited
aiRuns an AI prompt per row using built-in modelsprompt, model, max_tokens, temperatureYes
httpMakes an HTTP request per row, extracts response dataurl, method, headers, body, extractYes
formulaComputes a value from other columns in the same rowexpressionNo
integrationPushes row data to an external service (webhook, Slack, etc.)target, url, method, headers, bodyYes
lookupCross-table VLOOKUP -- joins data from another tablesource_table, match_column, return_columnNo
*
Rate limiting applies to external calls
Only kinds that make external requests (ai, http, integration) are rate limited. Formula and lookup columns run locally and have no rate limiting.

hypertab_add_smart_column

POST/api/tables/:tableId/smart-columnshypertab_add_smart_column

Add a smart column that processes data per row. AI columns run prompts, HTTP columns call APIs, formula columns compute values, integration columns push data, lookup columns join across tables.

ParameterTypeDescription
tablerequiredstringTable name or ID
namerequiredstringColumn name (lowercase, underscores, must start with a letter). Max 64 chars.
typerequiredstringOutput data type: text, number, json, boolean, email, url, phone, datetime, select, multi_select, currency, image_url
kindrequiredstringSmart column kind: ai, http, formula, integration, or lookup
configrequiredobjectKind-specific configuration. See each kind section below for required fields.
rate_limitstring | objectPreset name ("aggressive", "moderate", "conservative", "gentle") or custom object with requests_per_second, max_concurrent, retry_strategy, max_retries, retry_delay_ms, cool_down_on_429.
auto_runbooleandefault: falseAutomatically process new rows when inserted.
Rate limit presets:
PresetReq/sConcurrent
aggressive5006
moderate506
conservative105
gentle21
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "leads",
    "name": "industry",
    "type": "text",
    "kind": "ai",
    "config": {
      "prompt": "Classify {{company}} by industry. One word."
    },
    "rate_limit": "moderate",
    "auto_run": true
  }
}

HTTP Column -- Gemini API Example

Call the Gemini API per row to find the capital of each country. The prompt uses {{country}} to inject the row value.

Config breakdown:
  • url -- Gemini API endpoint with your API key as a query parameter
  • method -- POST for Gemini's generateContent endpoint
  • headers -- Content-Type must be application/json
  • body -- The request payload with {{country}} template variable injected into the prompt text
  • extract -- JSONPath-like expression to pull the generated text from Gemini's nested response structure
  • run_condition -- Only process rows where the country column is not empty, skipping incomplete data
*
Extract paths
The extract field uses dot notation with array indices to navigate the API response. For Gemini: candidates[0].content.parts[0].text
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "countries",
    "name": "capital",
    "type": "text",
    "kind": "http",
    "config": {
      "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=YOUR_KEY",
      "method": "POST",
      "headers": {
        "Content-Type": "application/json"
      },
      "body": {
        "contents": [{
          "parts": [{
            "text": "What is the capital of {{country}}? Reply with ONLY the city name."
          }]
        }],
        "generationConfig": {
          "temperature": 0
        }
      },
      "extract": "candidates[0].content.parts[0].text",
      "run_condition": "{{country}} IS NOT EMPTY"
    },
    "rate_limit": "conservative"
  }
}

HTTP Column -- OpenAI API Example

Call the OpenAI API per row to summarize a company. Uses {{company}} and {{website}} template variables.

Config breakdown:
  • url -- OpenAI Chat Completions endpoint
  • method -- POST
  • headers -- Authorization with Bearer token and Content-Type
  • body -- Standard OpenAI chat format with model, messages array, and max_tokens. The user message content uses template variables.
  • extract -- Path to the generated text in OpenAI's response: choices[0].message.content
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "leads",
    "name": "summary",
    "type": "text",
    "kind": "http",
    "config": {
      "url": "https://api.openai.com/v1/chat/completions",
      "method": "POST",
      "headers": {
        "Content-Type": "application/json",
        "Authorization": "Bearer sk-YOUR_OPENAI_KEY"
      },
      "body": {
        "model": "gpt-4o-mini",
        "messages": [
          {
            "role": "user",
            "content": "Summarize {{company}} ({{website}}) in one sentence."
          }
        ],
        "max_tokens": 100
      },
      "extract": "choices[0].message.content"
    },
    "rate_limit": "moderate"
  }
}

AI Column (Built-in)

AI columns use hypertab's built-in AI processing. No external API key needed -- just write a prompt with template variables and choose a model. The result is written back to the cell.

Config KeyTypeRequiredDescription
promptstringYesThe AI prompt. Use {{column}} to inject row values.
modelstringNoModel identifier (e.g. "claude-haiku-4-20250414"). Defaults to platform default.
max_tokensnumberNoMaximum tokens in the response. Default: 256.
temperaturenumberNoSampling temperature (0-1). Lower = more deterministic. Default: 0.

The prompt supports all template variable syntax. The AI processes each row independently, replacing variables with the row's actual values before sending to the model.

AI
Agent tip
AI columns are ideal for classification, extraction, summarization, and sentiment analysis. Set temperature to 0 for consistent outputs.
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "support_tickets",
    "name": "sentiment",
    "type": "text",
    "kind": "ai",
    "config": {
      "prompt": "Classify the sentiment of this support ticket:\n\n{{message}}\n\nReply with exactly one word: positive, negative, or neutral",
      "model": "claude-haiku-4-20250414",
      "max_tokens": 10,
      "temperature": 0
    },
    "rate_limit": "moderate",
    "auto_run": true
  }
}

Formula Column

Formula columns compute a value from other columns in the same row. No external API calls, no rate limiting. The expression is evaluated locally for each row.

Function / OperatorDescriptionExample
+, -, *, /Arithmetic operatorsprice * quantity
CONCAT(a, b, ...)Concatenate stringsCONCAT(first_name, " ", last_name)
UPPER(text)Convert to uppercaseUPPER(country)
LOWER(text)Convert to lowercaseLOWER(email)
TRIM(text)Remove leading/trailing whitespaceTRIM(name)
LEFT(text, n)First n charactersLEFT(phone, 3)
RIGHT(text, n)Last n charactersRIGHT(zip_code, 4)
LEN(text)Character countLEN(description)
IF(cond, then, else)Conditional expressionIF(score > 80, "hot", "cold")
ROUND(num, decimals)Round to n decimal placesROUND(price * 1.1, 2)
NOW()Current ISO 8601 timestampNOW()

Expressions reference column names directly (no {{...}} syntax needed). Column names are resolved against the table schema at evaluation time.

i
Formula columns have no rate limiting and no config beyond the expression. They re-evaluate whenever the referenced columns change.
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "orders",
    "name": "total",
    "type": "number",
    "kind": "formula",
    "config": {
      "expression": "price * quantity"
    }
  }
}

Integration Column

Integration columns push row data to external services. Each row triggers an outbound request to the configured target. Useful for syncing data to Slack, webhooks, CRMs, or any HTTP endpoint.

Config KeyTypeRequiredDescription
targetstringYesIntegration target: "webhook", "slack"
urlstringYesDestination URL to POST data to
methodstringNoHTTP method. Default: "POST"
headersobjectNoCustom headers (e.g. Authorization)
bodyobject | stringNoBody template with {{column}} variables. If omitted, sends full row as JSON.

Integration columns write the response status back to the cell (e.g. "200 OK" or "error: timeout"). The body template supports all template variable syntax.

!
Rate limiting required
Integration columns make external HTTP requests and must have a rate_limit configured. Default: conservative (10 req/s).
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "alerts",
    "name": "slack_notify",
    "type": "text",
    "kind": "integration",
    "config": {
      "target": "slack",
      "url": "https://hooks.slack.com/services/T00/B00/xxx",
      "method": "POST",
      "body": {
        "text": "New alert: {{title}} (severity: {{severity}})"
      }
    },
    "rate_limit": "conservative",
    "auto_run": true
  }
}

Lookup Column

Lookup columns perform a cross-table VLOOKUP. For each row, they find a matching row in another table and return a value from it. No external API calls, no rate limiting.

Config KeyTypeRequiredDescription
source_tablestringYesThe table to look up data from
match_columnstringYesColumn in the source table to match against the current row value
return_columnstringYesColumn in the source table whose value to return

The lookup matches the current row's column value (same name as match_column) against the source table. If a match is found, the value from return_column is written to the cell. If no match is found, the cell is left empty.

i
Cross-table join
This is equivalent to a SQL LEFT JOIN. Example: your orders table has a customer_id column and you want to pull company_name from the customers table.
{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "orders",
    "name": "customer_company",
    "type": "text",
    "kind": "lookup",
    "config": {
      "source_table": "customers",
      "match_column": "customer_id",
      "return_column": "company_name"
    }
  }
}

Run Conditions

Run conditions let you skip rows that don't have the required data. Add a run_condition to any smart column's config. Rows that don't match the condition are marked as "skipped" instead of "error".

OperatorSyntaxDescription
IS EMPTY{{col}} IS EMPTYTrue if the column value is null or empty string
IS NOT EMPTY{{col}} IS NOT EMPTYTrue if the column has a value
EQUALS{{col}} EQUALS "value"True if the column equals the given string
NOT EQUALS{{col}} NOT EQUALS "value"True if the column does not equal the string
CONTAINS{{col}} CONTAINS "text"True if the column contains the substring
GREATER THAN{{col}} GREATER THAN 100True if the numeric value exceeds the threshold
LESS THAN{{col}} LESS THAN 50True if the numeric value is below the threshold
ANDexpr AND exprBoth conditions must be true
ORexpr OR exprAt least one condition must be true
Examples:
ConditionMeaning
{{website}} IS NOT EMPTYOnly process rows that have a website
{{size}} GREATER THAN 100Only companies with 100+ employees
{{status}} EQUALS "active"Only active rows
{{email}} IS NOT EMPTY AND {{company}} IS NOT EMPTYRows with both email and company
{{score}} GREATER THAN 50 OR {{priority}} EQUALS "high"High-scoring or high-priority rows
{{company_data.industry}} IS NOT EMPTY AND {{size}} GREATER THAN 50JSON field access with numeric comparison
*
Best practice
Always add a run_condition for HTTP and AI columns to avoid wasting API calls on rows with missing data. Skipped rows don't count toward your rate limit.

hypertab_update_column_config

PATCH/api/tables/:tableId/columns/:col/confighypertab_update_column_config

Update the configuration of a smart column after creation. Change the AI prompt, HTTP URL, formula expression, rate limit preset, or auto-run setting. Only provided fields are updated; omitted fields are left unchanged.

ParameterTypeDescription
tablerequiredstringTable name or ID
columnrequiredstringSmart column name or ID
configobjectUpdated kind-specific config (merged with existing config). Only include fields you want to change.
rate_limitstring | objectUpdated rate limit preset or custom config
auto_runbooleanUpdated auto-run setting

Config updates are merged with the existing config. For example, updating just the prompt on an AI column preserves the model and temperature settings.

!
Existing results not reprocessed
Updating a column's config does not automatically reprocess existing rows. Use hypertab_run_column to trigger reprocessing after a config change.
{
  "tool": "hypertab_update_column_config",
  "arguments": {
    "table": "leads",
    "column": "sentiment",
    "config": {
      "prompt": "Classify sentiment as: very_positive, positive, neutral, negative, very_negative\n\n{{message}}"
    }
  }
}

hypertab_run_column

POST/api/tables/:tableId/columns/:col/runhypertab_run_column

Trigger smart column processing for all rows or specific rows. Creates a column run and enqueues cells for batch processing. Rate limits are enforced per column config.

ParameterTypeDescription
tablerequiredstringTable name or ID
columnrequiredstringSmart column name or ID
row_idsstring[]Specific row IDs to process. Omit to process all rows.

When triggered, the engine creates a column run record, evaluates run conditions for each row, and enqueues matching cells for batch processing. Progress can be tracked using the returned run_id.

i
Rows that don't pass the run condition are marked "skipped" immediately. The run completes when all non-skipped cells are processed.
{
  "tool": "hypertab_run_column",
  "arguments": {
    "table": "countries",
    "column": "capital"
  }
}

hypertab_get_column_run_status

GET/api/column-runs/:runIdhypertab_get_column_run_status

Check the progress of a smart column run. Shows total rows, processed count, error count, and completion status. Use the run_id returned by hypertab_run_column.

ParameterTypeDescription
run_idrequiredstringColumn run ID returned by hypertab_run_column

Poll this endpoint to track progress. The run transitions through states:

  • running -- cells are being processed
  • complete -- all cells finished (some may have errors)
  • failed -- circuit breaker tripped, run halted
{
  "tool": "hypertab_get_column_run_status",
  "arguments": {
    "run_id": "run_abc123"
  }
}

hypertab_get_cell_states

GET/api/tables/:tableId/columns/:col/cellshypertab_get_cell_states

Get per-cell execution states for a smart column. Each cell in a smart column has its own execution state tracking. Filter by status to find failures or pending cells.

ParameterTypeDescription
tablerequiredstringTable name or ID
columnrequiredstringSmart column name or ID
statusstringFilter by cell status: idle, pending, running, complete, error, skipped
limitnumberdefault: 100Max cells to return.
offsetnumberdefault: 0Number of cells to skip for pagination.
Cell states:
StatusMeaning
idleNot yet queued for processing
pendingQueued and waiting to be processed
runningCurrently being processed
completeSuccessfully processed
errorProcessing failed (see error message)
skippedRun condition not met for this row
{
  "tool": "hypertab_get_cell_states",
  "arguments": {
    "table": "countries",
    "column": "capital",
    "status": "error"
  }
}

hypertab_retry_failed_cells

POST/api/tables/:tableId/columns/:col/retryhypertab_retry_failed_cells

Retry all failed cells in a smart column. Creates a new column run for just the cells with "error" status, re-enqueuing them for processing.

ParameterTypeDescription
tablerequiredstringTable name or ID
columnrequiredstringSmart column name or ID

Only cells in "error" state are retried. Cells that completed successfully or were skipped are not affected. The retry creates a new run_id that you can track with hypertab_get_column_run_status.

*
Check errors first
Before retrying, use hypertab_get_cell_states with status: "error" to understand why cells failed. If the issue is a bad config (wrong URL, invalid API key), fix it with hypertab_update_column_config before retrying.
{
  "tool": "hypertab_retry_failed_cells",
  "arguments": {
    "table": "countries",
    "column": "capital"
  }
}

Cell Details (Structured JSON Response)

Every AI and HTTP smart column stores a structured JSON response with metadata alongside the extracted value. Click any completed cell in the UI to open the Cell Details Panel showing all response fields with the ability to add any field as a new column.

GET/api/tables/:tableId/rows/:rowId/cells/:columnName

Get the full response metadata for a specific cell.

ParameterTypeDescription
tableIdrequiredstringTable name or ID
rowIdrequiredstringRow _ht_id
columnNamerequiredstringSmart column name
curl /api/tables/countries/rows/ROW_ID/cells/capital \
  -H "Authorization: Bearer ht_sk_..."
i
Response Metadata Fields
AI columns include: result or output (for structured JSON), model, provider, input_tokens, output_tokens, time_taken_seconds, cost_usd. HTTP columns include: result or output (for multi-extract), http_status, time_taken_seconds, attempts.

Structured JSON Output (Clay Model)

AI columns can return structured JSON instead of plain text. Define an output_schema in the column config, and the AI will return a JSON object matching that schema. The cell shows the first field value with aJSON badge. Click the cell to expand all fields.

{
  "tool": "hypertab_add_smart_column",
  "arguments": {
    "table": "my_leads",
    "name": "research",
    "type": "json",
    "kind": "ai",
    "config": {
      "provider_id": "prv_...",
      "model": "gemini-2.5-flash",
      "prompt": "Research {{company}} ({{website}}).",
      "output_schema": {
        "type": "object",
        "properties": {
          "industry": { "type": "string" },
          "employee_count": { "type": "number" },
          "hq_city": { "type": "string" },
          "revenue": { "type": "string" }
        },
        "required": ["industry", "employee_count", "hq_city", "revenue"]
      },
      "run_condition": "{{company}} IS NOT EMPTY"
    }
  }
}
*
Extract fields into columns
Click a completed JSON cell in the UI to open the Cell Details panel. Each field has an "Add to column" button that creates a new static column and populates it with that field's value from every row.

HTTP Column, Advanced Features

HTTP columns support Clay-level configuration: query parameters, retries, timeouts, multi-extract, saved API accounts, and more.

ParameterTypeDescription
query_paramsobjectKey-value pairs appended as ?k=v. Supports {{variables}}.
extractsobjectMultiple named extractions: {"email": "data.email", "name": "data.name"}. Creates structured JSON.
timeout_msnumberResponse timeout in ms (default 30000, max 120000).
retry_on_failurebooleanAuto-retry failed requests.
max_retriesnumberNumber of retry attempts (default 3).
retry_status_codesarrayWhich HTTP codes trigger retry (default: [429, 500, 502, 503, 504]).
retry_delay_msnumberDelay between retries in ms (default 1000). Linear backoff.
remove_empty_valuesbooleanStrip null/empty fields from request body.
return_metadatabooleanInclude response headers and redirect info in cell details.
follow_redirectsbooleanFollow HTTP redirects (default true).
account_idstringSaved API account ID, auto-injects auth headers. See hypertab_list_api_accounts.
{
  "config": {
    "url": "https://api.github.com/orgs/{{company}}",
    "method": "GET",
    "account_id": "acct_...",
    "extracts": {
      "repos": "public_repos",
      "followers": "followers",
      "blog": "blog",
      "location": "location"
    },
    "timeout_ms": 10000,
    "retry_on_failure": true,
    "max_retries": 2,
    "retry_status_codes": [429, 500, 502, 503]
  }
}

API Accounts (Saved Auth Headers)

Save named API accounts with auth headers. Use account_id in HTTP column config to auto-inject headers without pasting API keys every time.

{
  "tool": "hypertab_save_api_account",
  "arguments": {
    "name": "My GitHub API",
    "service": "github",
    "auth_type": "bearer",
    "token": "ghp_your_token_here",
    "base_url": "https://api.github.com",
    "description": "GitHub production API key"
  }
}
i
Auth Types
bearer, Authorization: Bearer <token>
api_key, X-API-Key: <token> (custom header name supported)
basic, Authorization: Basic base64(user:pass)
custom_headers, Any JSON headers object

Manage accounts: hypertab_list_api_accounts, hypertab_update_api_account, hypertab_delete_api_account. Or use Settings → API Accounts in the UI.

Pipeline Tabs (Connected Stages)

A table can contain multiple tabs (pipeline stages). Each tab has its own columns and rows. Linked tabs auto-sync data from a parent tab based on filter conditions. JSON fields from smart columns are expanded into real columns on the linked tab.

{
  "tool": "hypertab_create_tab",
  "arguments": {
    "table": "my_leads",
    "name": "qualified_leads",
    "source_column": "research",
    "filter": {
      "research.employee_count": { "gte": 500 }
    },
    "description": "Leads with 500+ employees"
  }
}

// Creates a new tab that:
// 1. Inherits parent columns (company, website)
// 2. Expands JSON fields from 'research' column (industry, employee_count, hq_city, revenue)
// 3. Only syncs rows where employee_count >= 500
*
Pipeline Flow
Raw Data → AI Enrichment → Filter → Linked Tab → More AI → Next Stage
Each tab is a stage. Data flows forward, gets richer at each stage. Like Clay's pipeline model.

Auto-Run on New Rows

Set auto_run: true in a smart column's config to automatically process new rows when they're inserted. The column run triggers immediately afterhypertab_insert_rows completes.

{
  "tool": "hypertab_update_column_config",
  "arguments": {
    "table": "my_leads",
    "column": "research",
    "config": { "auto_run": true }
  }
}

// Now when you insert rows:
// hypertab_insert_rows({ table: "my_leads", rows: [...] })
// → 'research' column automatically starts processing the new rows