Dolfin Custom Functions & Developer API #

The Dolfin Custom Functions Engine enables developers to write, compile, and execute isolated TypeScript functions directly inside the Dolfin platform. Functions can be triggered by user interactions (lead row actions), automated stage transitions (on entering or exiting a pipeline stage), or scheduled background jobs.

ℹ️ Note

All custom functions are authored in TypeScript and automatically transpiled to secure ES2020 JavaScript upon saving in the Custom Functions IDE (Ctrl+S).


Execution Model & Architecture #

Each custom function invocation executes inside a dedicated, memory-capped V8 Isolate. This architecture provides strict process isolation, preventing rogue scripts from blocking the main API thread or leaking tenant data.

typescript
┌─────────────────────────────────────────────────────────────┐
│                       Trigger Event                         │
│   • Lead Table Row Action                                   │
│   • Pipeline Stage Transition (On Enter / On Exit)          │
│   • Background Automation Dispatcher                        │
└──────────────────────────────┬──────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                    Isolated V8 Sandbox                      │
│                                                             │
│   async function run(context: Context, dolfin: DolfinApi)   │
│                                                             │
│   ├── Context: Injected Lead, Contact & User metadata      │
│   ├── dolfin.crm.module(id): Scoped CRM database bridge     │
│   └── dolfin.http: Outbound HTTP with SSRF filter           │
└──────────────────────────────┬──────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────┐
│             Execution Logs & Database Persistence           │
│   • Status (Success / Failed / Timeout)                     │
│   • Captured Console Output (stdout / stderr)               │
│   • Execution Duration (ms) & Context Payload Audit         │
└─────────────────────────────────────────────────────────────┘

Global Runtime Signature #

Every custom function exports a top-level asynchronous run entry point accepting two ambient arguments:

typescript
async function run(context: Context, dolfin: DolfinApi): Promise<void> {
  // 1. Destructure entity data from runtime context
  const { lead } = context;

  console.log(`Executing function for lead "${lead.name}" (ID: ${lead.id})`);

  // 2. Obtain module-scoped CRM API bridge
  const crm = await dolfin.crm.module(lead.moduleId);

  // 3. Perform CRM operations or outbound HTTP integrations
  await crm.leads.notes.add(
    lead.id,
    "Custom function executed successfully."
  );
}

Ambient Parameters #

ParameterTypeDescription
contextContextContains immutable runtime data for the triggering entity (e.g. lead.id, lead.name, lead.meta).
dolfinDolfinApiPrimary SDK client providing dolfin.crm and dolfin.http APIs.
consoleConsoleProvides console.log, console.warn, and console.error. All logged output is streamed into the Execution Logs drawer.

API Namespaces #

Dolfin exposes two primary API groups:

1. dolfinApi.crm #

Access module-scoped CRM entities, update custom metadata attributes (lead.meta), transition stages, reassign leads, add internal timeline notes, and query activity logs.

typescript
const crm = await dolfin.crm.module(lead.moduleId);
await crm.leads.update(lead.id, { meta: { status: "verified" } });

Explore dolfinApi.crm Documentation →

2. dolfinApi.http #

Make authenticated outbound HTTP requests (GET, POST, PUT, DELETE) to external services (Slack, Discord, Zapier, Webhooks, ERPs) with built-in SSRF protections and automatic JSON serialization.

typescript
const res = await dolfin.http.post("https://api.external.com/v1/sync", { leadId: lead.id });

Explore dolfinApi.http Documentation →

3. Custom Listing Pages & Actions #

Build reactive, code-first data listing views with cascading filters, system-managed pagination, primary key bindings, and typed single-row and bulk actions powered by filters.ts, fetcher.ts, and actions/*.ts.

typescript
// Fetcher (fetcher.ts)
export async function run(context: CustomListContext, dolfin: DolfinSdk): Promise<CustomListResponse> {
  const crm = await dolfin.crm.module(context.moduleId);
  const result = await crm.leads.list({ page: context.pagination.page, limit: context.pagination.limit });
  return { items: result.data || [], total: result.total || 0 };
}

// Single-Row Action (actions/qualify.ts)
export async function run(context: CustomListRowActionContext, dolfin: DolfinSdk): Promise<CustomListActionResponse> {
  const crm = await dolfin.crm.module(context.moduleId);
  await crm.leads.update(Number(context.row.id), { meta: { status: "qualified" } });
  return { success: true, message: "Lead qualified!", refresh: true };
}

Explore Custom Listing Pages Documentation → | Custom Actions & Row Operations →


Engine Constraints & Safety Budgets #

To ensure high performance and prevent infinite loops, the engine enforces strict limits:

MetricLimitFailure Behavior
Execution Timeout10,000 ms (10 seconds)Process terminated; recorded with status timeout.
Isolate Memory Cap64 MBScript terminates if memory threshold is exceeded.
CRM Call Budget50 operations per invocationThrows Exceeded maximum CRM calls per execution (50).
HTTP Call Budget5 requests per invocationThrows Exceeded maximum HTTP calls per execution (5).
HTTP Request Timeout8,000 ms per requestAborts request via AbortController signal.
Max HTTP Response Size1 MB (1,048,576 bytes)Throws Response size exceeds maximum limit.
SSRF GuardrailProhibits private CIDRs & localhostThrows SSRF Blocked: URL resolves to forbidden range.
⚠️ Warning

The CRM Call Budget is shared across all module instances created within a single script invocation. Avoid executing unbounded database reads or writes in loops.


Viewing Execution History & Logs #

Every execution generates a persistent audit log accessible from the Custom Functions management screen:

  • Duration: Exact runtime execution time in milliseconds.
  • Status: Success, Failed, or Timeout.
  • Console Output: Real-time captures of all console.log statements.
  • Error Trace: Full stack trace and error message if an uncaught exception occurred.
  • Context Snapshot: Sanitized JSON payload representing the entity state at time of invocation.