Skip to content

Functions

Overview

Functions (compute-functions) are the code layer in Centrali. A function contains your business logic, integrations, and data operations. It does not decide how requests enter the system or whether work happens in one step or many — triggers and automations handle that.

Use this page when you need to understand what function code can do once execution has already started.

Functions in the Execution Model

Think about the execution model in layers:

  • HTTP trigger = async inbound webhook entry
  • Endpoint trigger = synchronous request/response API entry
  • Function = the code that runs after a trigger or automation step starts execution
  • Automation = a multi-step workflow that chains functions together

Functions are where you:

  • Process data: Transform, validate, normalize, or enrich records
  • Implement business logic: Calculations, validations, approvals, and side effects
  • Integrate systems: Call external APIs and services
  • React to execution context: Handle event-driven, scheduled, on-demand, HTTP, or endpoint-triggered runs

Note

If you are still deciding how execution should start, read Triggers first. If you are receiving inbound third-party webhooks, start with Webhook Ingestion. If you need branching or delays, move up to Automations.

Key Features

Secure Sandbox

  • Functions run in isolated environments
  • No access to file system or network (except approved APIs)
  • CPU and memory limits enforced
  • Automatic timeout after 5 minutes

Built-in APIs

Each function has access to: - Data API: Query and modify records in your workspace - Storage API: Upload and download files - HTTP Client: Make external API calls - Crypto API: SHA256 hashing, HMAC-SHA256 signing, RSA signing, and JWT creation - Base64 API: Encode and decode Base64 strings (useful for Basic Auth headers) - Logging: api.log() for general logging, api.logError() for error logging with context

How Functions Get Called

A function can run through: - Record events: Created, updated, deleted, restored, reverted - Schedule: Interval-based, cron expression, or one-time execution - Manual: On-demand invocation via API - HTTP Triggers: External HTTP requests (fire-and-forget async ingestion) - Endpoints: HTTP requests that return the function's output inline (synchronous API execution) - Automations: Compute steps inside multi-step workflows

See Also: Event Payloads Reference for detailed documentation on event payload structures.

Creating a Function

Step 1: Create the Function

A function is created in a single step with inline code:

curl -X POST https://api.centrali.io/data/workspace/my-workspace/api/v1/compute-functions \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "process-order",
    "description": "Process new orders and send notifications",
    "code": "async function run() {\n  const recordId = executionParams.recordId;\n  \n  // Query the order record\n  const order = await api.fetchRecord(recordId);\n  \n  // Call external API\n  await api.httpPost(\"https://api.example.com/notify\", {\n    orderId: order.id,\n    total: order.data.total\n  }, {\n    headers: { \"Authorization\": \"Bearer \" + triggerParams.apiKey }\n  });\n  \n  return { success: true };\n}"
  }'

Response:

{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "name": "process-order",
  "description": "Process new orders and send notifications",
  "code": "async function run() { ... }",
  "workspaceSlug": "my-workspace",
  "createdBy": "user-uuid",
  "createdAt": "2025-01-15T10:30:00.000Z",
  "updatedAt": "2025-01-15T10:30:00.000Z"
}

Step 2: Test the Function

Test function code before attaching triggers:

curl -X POST https://api.centrali.io/data/workspace/my-workspace/api/v1/compute-functions/test \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "async function run() {\n  const recordId = executionParams.recordId;\n  const order = await api.fetchRecord(recordId);\n  return { success: true, orderId: order.id };\n}",
    "params": {
      "recordId": "550e8400-e29b-41d4-a716-446655440000"
    }
  }'

Step 3: Publish from Draft (Optional)

If you use the draft workflow, publish a draft to create the function:

curl -X POST https://api.centrali.io/data/workspace/my-workspace/api/v1/compute-functions/DRAFT_ID/publish \
  -H "Authorization: Bearer YOUR_TOKEN"

Function Code Structure

Basic Structure

All functions must define a run() function:

async function run() {
  // Your code here

  return {
    success: true,
    data: { /* your results */ }
  };
}

Important: The function must be named run, not handler or anything else.

Available Globals

Functions have access to these global objects:

Global Purpose
api Data operations, HTTP, utilities
triggerParams Static config from trigger setup (API keys, endpoints)
executionParams Runtime data passed when invoking the function
Date, Math Standard JavaScript globals
setTimeout, setInterval Timer functions

The api Object

// Record Operations
api.queryRecords(recordSlug, options)
api.fetchRecord(recordId)
api.fetchRecordByUniqueField(recordSlug, field, value)
api.createRecord(recordSlug, data)
api.updateRecord(recordId, data)
api.deleteRecord(recordId, hardDelete)
api.incrementField(recordId, field, amount)
api.decrementField(recordId, field, amount)
api.aggregateRecords(recordSlug, options)

// HTTP Client (domain allowlist required)
// Returns { status, statusText, headers, data }
api.httpGet(url, options)
api.httpPost(url, data, options)
api.httpPut(url, data, options)
api.httpDelete(url, options)

// Utilities
api.log(message)           // Logging (string or object)
api.uuid()                 // Generate UUID
api.formatDate(date, format)
api.renderTemplate(template, data, options)  // Handlebars templates

// Crypto
api.crypto.sha256(data)                        // SHA256 hash (base64)
api.crypto.hmacSha256(key, data, options)       // HMAC-SHA256 (base64)
api.crypto.rsaSign(privateKeyPem, data, algo)   // RSA signature (base64url)
api.crypto.signJwt(privateKeyPem, payload, options)  // Build + sign a JWT

// Base64
api.base64.encode(data)    // Encode string to Base64
api.base64.decode(encoded)  // Decode Base64 string

// Libraries
api.lodash                 // Subset of lodash functions
api.math                   // Math.js for calculations

Parameters

triggerParams - Static configuration set when creating the trigger:

// Configured in trigger setup
const apiKey = triggerParams.apiKey;
const endpoint = triggerParams.endpoint;

executionParams - Runtime data passed when invoking:

// For on-demand triggers: the payload from SDK/API call
// For event-driven triggers: the event payload (recordId, data, etc.)
const orderId = executionParams.orderId;
const action = executionParams.action;

Event-Driven Trigger Payload

For event-driven triggers, executionParams contains:

{
  event: "record_created",  // or record_updated, record_deleted, etc.
  workspaceSlug: "my-workspace",
  recordSlug: "orders",
  recordId: "uuid-here",
  data: { /* record data or { before, after } for updates */ },
  timestamp: "2025-01-15T10:00:00Z"
}

Function Examples

Example 1: Send Welcome Email

async function run() {
  // For event-driven triggers, executionParams contains the event
  const { recordId, data } = executionParams;

  // Send welcome email via external service
  await api.httpPost('https://api.sendgrid.com/v3/mail/send', {
    to: data.email,
    subject: 'Welcome!',
    text: `Hello ${data.name}, welcome to our platform!`
  }, {
    headers: {
      'Authorization': `Bearer ${triggerParams.SENDGRID_API_KEY}`
    }
  });

  api.log({ message: 'Welcome email sent', userId: recordId });

  return { success: true };
}

Example 2: Calculate Order Total

async function run() {
  const orderId = executionParams.recordId;

  // Get order record
  const order = await api.fetchRecord(orderId);

  // Query line items
  const lineItems = await api.queryRecords('order-items', {
    filter: { 'data.orderId': orderId }
  });

  // Calculate total
  let total = 0;
  for (const item of lineItems.data) {
    total += item.data.price * item.data.quantity;
  }

  // Update order with calculated total
  await api.updateRecord(orderId, { total });

  return { success: true, total };
}

Example 3: Scheduled Cleanup

async function run() {
  // Delete records older than 30 days
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const oldRecords = await api.queryRecords('logs', {
    dateWindow: {
      field: 'createdAt',
      to: thirtyDaysAgo.toISOString()
    },
    pageSize: 100
  });

  let deleted = 0;
  for (const record of oldRecords.data) {
    await api.deleteRecord(record.id, true);
    deleted++;
  }

  api.log({ message: 'Cleanup complete', deleted });

  return { success: true, deleted };
}

Function Parameters

Static parameters are configured through trigger metadata (triggerMetadata.params) when creating or updating a trigger. They are available in your function code via the triggerParams global.

Configuring Parameters

Parameters are set in the trigger's triggerMetadata.params field:

curl -X POST https://api.centrali.io/data/workspace/my-workspace/api/v1/function-triggers \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "order-processor",
    "functionId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "executionType": "on-demand",
    "triggerMetadata": {
      "params": {
        "WEBHOOK_URL": "https://api.example.com/webhook",
        "API_KEY": {
          "value": "sk_live_abc123",
          "encrypt": true
        }
      }
    }
  }'

Sensitive values can be encrypted at rest by using { "value": "...", "encrypt": true }. Encrypted parameters are automatically decrypted before function execution.

Accessing Parameters

Parameters are available in the triggerParams global:

async function run() {
  const apiKey = triggerParams.API_KEY;
  const webhookUrl = triggerParams.WEBHOOK_URL;

  // Use parameters in your code
  await api.httpPost(webhookUrl, { data: 'example' }, {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });

  return { success: true };
}

See the Function Triggers API for full documentation on parameter encryption.

Triggers

Triggers define when your function executes. Centrali supports five trigger types:

  • event-driven for record changes
  • scheduled for cron, interval, or one-time runs
  • on-demand for manual API or SDK invocation
  • http-trigger for async inbound webhook traffic
  • endpoint for synchronous custom APIs

If a single function is not enough, use Automations to coordinate multiple function steps with branching and delays.

For a complete guide on choosing and configuring triggers, see Triggers.

For the raw API endpoints, see the Triggers API Reference.

Monitoring & Debugging

View All Function Runs

curl -X GET https://api.centrali.io/data/workspace/my-workspace/api/v1/function-runs \
  -H "Authorization: Bearer YOUR_TOKEN"

View Runs for a Specific Function

curl -X GET https://api.centrali.io/data/workspace/my-workspace/api/v1/function-runs/function/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
  -H "Authorization: Bearer YOUR_TOKEN"

View a Specific Run

curl -X GET https://api.centrali.io/data/workspace/my-workspace/api/v1/function-runs/RUN_ID \
  -H "Authorization: Bearer YOUR_TOKEN"

Re-run Functions

You can re-run any previous function execution to retry or debug. Re-run is supported for all trigger types (on-demand, event-driven, scheduled, and HTTP).

See Function Re-run documentation.

Best Practices

Code Organization

  • Keep functions focused on a single task
  • Extract reusable logic to helper functions
  • Use clear variable and function names
  • Add comments for complex logic

Error Handling

async function run() {
  try {
    // Your code here
    return { success: true };
  } catch (error) {
    // Log the error with context
    api.log({
      level: 'error',
      message: error.message,
      stack: error.stack
    });

    // Return error response (don't throw - return success: false)
    return { success: false, error: error.message };
  }
}

Performance

  • Minimize external API calls
  • Cache frequently accessed data
  • Use bulk operations for multiple records
  • Set appropriate timeout limits

Security

  • Store secrets as encrypted parameters
  • Validate input data
  • Use HTTPS for external calls
  • Follow principle of least privilege

Limits & Quotas

Default limits:

Limit Value
Execution timeout Up to 5 minutes (configurable, default 30 seconds)
Memory per function 512 MB
Concurrent executions 100 per workspace
Function code size 5 MB (compressed)
Triggers per function 50
Functions per workspace 1,000

For the full list of platform limits including API rate limits, storage quotas, and query constraints, see Limits & Quotas.