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:
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.
What to Read Next¶
- Need to choose between HTTP triggers, endpoints, schedules, and event-driven execution? Read Triggers.
- Need the webhook-specific async ingest flow? Read Webhook Ingestion.
- Need the code API in more depth? Read Writing Functions.
- Need exact event and execution payload shapes? Read Event Payloads Reference and Trigger Parameters & Payload Shapes.
- Need multi-step workflows instead of one function run? Read Automations.
- Need exact REST endpoints? Read the Functions API and Triggers API.
- Need to retry previous executions? Read Function Re-run.