Skip to content

Pre-GA Design Partner and Early Access only. Request access

Helix Docs

ctx.callFunctionAsync()

Signature, parameters, and constraints for ctx.callFunctionAsync(), the fire-and-forget way to hand work off to another route.

For developers Updated Sep 18, 2026
View as Markdown

ctx.callFunctionAsync(path, input?) queues a call to another route in the same project, which runs as a new, independent execution. The call resolves once accepted, not once the target finishes.

Signature

callFunctionAsync(path: string, input?: unknown): Promise<void>
ParameterTypeDescription
pathstringThe target route’s path, for example 'leads/enrich'. Not validated against your project’s real routes at call time.
inputunknown (optional)Passed to the target as its ctx.input.

Returns a Promise<void> that resolves once the call is accepted. There is no return value, status, or execution ID from the target.

ctx.parentExecutionId

Available on the ctx a target route receives:

FieldTypeDescription
parentExecutionIdstring | nullThe execution ID of the caller that started this execution with callFunctionAsync, or null when this execution was not started by an async call (a direct request or a schedule).

Constraints

ConstraintBehavior
Dispatch methodAlways POST, regardless of the caller’s own method. The target must accept POST.
Chaining depthA chain is at most two hops deep: the execution that starts it may call callFunctionAsync, and the execution that call starts may call it again, but the execution after that may not.
DeliveryAt-least-once, with no idempotency key. A transient failure can cause the target to run again for the same call.
Unmatched pathNot validated at call time. With no matching route and no catch-all, the call is dropped silently. A catch-all route absorbs a mistyped path instead of surfacing an error.
ResultNone. The call is fire-and-forget: no return value, status, or execution ID is available to the caller.

Example

// functions/leads/webhook.post.ts, POST /leads/webhook
import { defineFunction } from '@trayai/helix-sdk';

export default defineFunction(async (ctx) => {
  await ctx.callFunctionAsync('leads/enrich', { leadId: ctx.input.leadId });
  return { received: true };
});
// functions/leads/enrich.post.ts, POST /leads/enrich
import { defineFunction } from '@trayai/helix-sdk';

export default defineFunction(async (ctx) => {
  ctx.log.info('Enriching lead', { leadId: ctx.input.leadId, calledBy: ctx.parentExecutionId });
});

Local development

helix dev fires the call directly at the target route on the same dev server and returns immediately: there’s no separate execution locally, so ctx.parentExecutionId is always null. This is a permanent property of local dev, not a gap that’s expected to close, so don’t gate local testing of a target on that field being set.

Idempotency concerns, the chaining limit, and the mistyped-path gotcha are covered in the async function calls guide.

Loading search…

Jump to a section

tab to move · esc to close