> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getnexor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloud Functions

Cloud Functions run your JavaScript whenever a selected Nexor event occurs. Nexor passes the event object to your function as `ctx`, where you can inspect and transform it, update the lead, call any external HTTP API, and return a result for the run history.

Use a Cloud Function when an integration needs custom logic, not just a copy of an event. For example, you can reshape a qualified lead for your CRM, notify a team only for high-value conversions, or send meeting data to your own backend without hosting a separate event handler.

<Info>
  Cloud Functions are available under **Advanced → Cloud Functions**. Each function listens to one trigger, and the trigger determines the shape of `ctx`.
</Info>

## How it works

1. An event occurs in Nexor, such as a lead changing status.
2. Nexor invokes the active Cloud Functions mapped to that trigger.
3. The function receives the trigger-specific event object as `ctx` and runs in a sandboxed JavaScript environment.
4. Nexor stores its console output, HTTP requests, return value, lead changes, status, and duration in the run history.

A function listens for the selected event across your Nexor organization. To limit it to a particular agent, status, channel, or other condition, inspect the corresponding `ctx` fields and return early when they do not match. Nexor dispatches at most 25 matching active functions per event; if more are active, the excess functions are skipped.

Cloud Functions are intended for short event handlers. Each execution has an 8-second timeout.

## Create a function

<Note>
  Only organization admins can create, edit, manually run, pause, or delete Cloud Functions. Other users can view functions, run history, and environment-variable names.
</Note>

<Steps>
  <Step title="Name the function and choose a trigger">
    Go to **Advanced → Cloud Functions**, click **New function**, enter a descriptive name, and select the event that should run your code.
  </Step>

  <Step title="Inspect the payload">
    Open the **Payload** tab in the editor. It shows a sample `ctx` for the selected trigger, including example values. Click a field to insert it into your code, and handle fields that may be `null` or absent in a live event.
  </Step>

  <Step title="Write the integration logic">
    Use the event data, the built-in lead helpers, and `axios` or `fetch` to implement the action. Add API keys, tokens, and endpoint URLs as environment variables instead of placing secrets in the code.
  </Step>

  <Step title="Save and test">
    Save to deploy the function, then click **Run** to execute the deployed version with an editable sample `ctx`. Review the output, network calls, return value, and proposed lead changes.
  </Step>

  <Step title="Activate and monitor">
    Keep **Active** enabled to run the function automatically. Open **Logs** to inspect later executions, or pause the function without deleting its code.
  </Step>
</Steps>

<Note>
  The trigger cannot be changed after the function is created because it defines the event subscription and payload. Create a new function if you need to react to a different event.
</Note>

## Available triggers

Each function maps to one of the following 23 events.

### Leads

| Trigger               | Runs when                                |
| --------------------- | ---------------------------------------- |
| `lead.created`        | A new lead enters the funnel.            |
| `lead.updated`        | One or more lead fields are edited.      |
| `lead.status_changed` | A lead moves from one status to another. |
| `lead.assigned`       | A lead is assigned to a human agent.     |
| `lead.tag_added`      | A tag is applied to a lead.              |
| `lead.unsubscribed`   | A lead opts out through WhatsApp.        |

### Information

| Trigger                 | Runs when                                                        |
| ----------------------- | ---------------------------------------------------------------- |
| `information.collected` | The agent extracts a new fact or variable from the conversation. |
| `information.updated`   | A previously collected fact changes value.                       |

### Conversations

| Trigger             | Runs when                                      |
| ------------------- | ---------------------------------------------- |
| `message.received`  | An inbound message arrives on any channel.     |
| `message.sent`      | The agent sends an outbound message.           |
| `call.completed`    | A voice call ends and its transcript is ready. |
| `handoff.requested` | The agent escalates the lead to a human.       |

### Conversions

| Trigger               | Runs when                                  |
| --------------------- | ------------------------------------------ |
| `conversion.detected` | A conversion event is recorded for a lead. |

### Meetings

| Trigger               | Runs when                                         |
| --------------------- | ------------------------------------------------- |
| `meeting.created`     | A meeting is scheduled with a lead.               |
| `meeting.rescheduled` | A meeting moves to a new time.                    |
| `meeting.completed`   | A meeting finishes, optionally with a transcript. |
| `meeting.no_show`     | A lead misses a scheduled meeting.                |

### Tasks and agent runs

| Trigger                   | Runs when                                    |
| ------------------------- | -------------------------------------------- |
| `task.created`            | A scheduled follow-up task is created.       |
| `task.executed`           | A scheduled follow-up task runs.             |
| `workflow.run_started`    | A lead is enrolled into an agent.            |
| `workflow.status_entered` | A lead enters a specific status in an agent. |
| `workflow.status_left`    | A lead leaves a status in an agent.          |
| `workflow.run_completed`  | An agent run reaches a terminal status.      |

<Tip>
  Use `lead.status_changed` when you need both the previous and new status. Use `workflow.status_entered` or `workflow.status_left` when your logic is specifically about entering or leaving a stage.
</Tip>

## Work with the event object

The shape of `ctx` depends on the trigger. It can contain top-level identifiers and event fields as well as nested objects such as `lead`, statuses, changes, metadata, attendees, or a task payload. Common fields include `lead_id`, `client_id`, `workflow_id`, and timestamps, but fields can be `null` or absent depending on how the event occurred.

Use the **Payload** tab to explore the sample object, then inspect **Input · ctx** in the run output or logs to see the payload received by a specific execution. Guard optional fields in production code instead of assuming every sample field is present.

The function can use the following values, helpers, and language features. The runtime built-ins require no imports.

| Value or helper         | Purpose                                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| `ctx`                   | The complete trigger-specific event payload.                                                                 |
| `lead`                  | The lead object derived from `ctx.lead`, or an empty object when the event does not include a lead snapshot. |
| `updateLead(patch)`     | Queues a patch to the Nexor lead.                                                                            |
| `updateMetadata(patch)` | Queues keys to merge into `lead.metadata` without replacing its other keys.                                  |
| `env.NAME`              | Reads an organization-level environment variable at runtime.                                                 |
| `axios`                 | Makes HTTP requests with `get`, `post`, `put`, `patch`, `delete`, `head`, or `options`.                      |
| `fetch`                 | Makes lower-level HTTP requests.                                                                             |
| `console`               | Captures `log`, `info`, `warn`, `error`, and `debug` entries in the run output.                              |
| `helpers.uuid()`        | Generates a UUID.                                                                                            |
| `helpers.now()`         | Returns the current time.                                                                                    |
| `return`                | Stores a JSON-serializable returned value as the run result.                                                 |

`updateLead` and `updateMetadata` change the sandbox's `lead` copy and buffer the corresponding effects. Nexor applies them only after a successful automatic execution. They are not applied when the function throws, times out, or runs manually from the editor.

## Send an event out of Nexor

This example maps `lead.status_changed` to a CRM endpoint. It filters for the `qualified` status, creates the external payload from `ctx`, sends it with a secret token, and records the successful sync on the Nexor lead.

```javascript theme={null}
export default async function onLeadStatusChanged(ctx) {
  if (ctx.to_status?.key !== "qualified") {
    return { skipped: true };
  }

  const payload = {
    type: "lead.status_changed",
    occurred_at: ctx.changed_at,
    lead_id: ctx.lead_id,
    workflow_run_id: ctx.workflow_run_id,
    status: {
      from: ctx.from_status?.key ?? null,
      to: ctx.to_status?.key ?? null,
    },
    reason: ctx.reason ?? null,
  };

  const response = await axios.post(env.CRM_EVENTS_URL, payload, {
    headers: {
      Authorization: `Bearer ${env.CRM_API_TOKEN}`,
    },
  });

  updateMetadata({
    last_crm_sync_at: helpers.now(),
  });

  console.log("CRM response:", response.status);
  return { synced: true, status: response.status };
}
```

You can use the same pattern with any HTTP service: a CRM, data warehouse, internal API, notification endpoint, automation platform, or another system that accepts requests.

## Environment variables

Admins manage organization-level variables from the **Environment variables** section on the Cloud Functions page. Other users can see variable names but not their values. Read a variable in code as `env.NAME`, for example `env.CRM_API_TOKEN`.

Environment-variable values are write-only in the dashboard: a function can read them at runtime, but the UI cannot reveal them after they are saved. Creating, replacing, or deleting a variable redeploys every saved Cloud Function in the organization.

An organization can store up to 128 variables. Names must start with an uppercase letter and contain only uppercase letters, numbers, or underscores, with a maximum of 64 characters. Each non-empty value can contain up to 5 KiB.

<Warning>
  Clicking **Run** executes the deployed function. Nexor keeps `updateLead` and `updateMetadata` as proposed effects during this manual test, but `axios` and `fetch` calls to external systems are real. Use a test endpoint or test credentials while validating the function.
</Warning>

## Review executions

The editor output and **Logs** page help you follow each execution. A run includes:

* its origin and trigger;
* success, error, or timeout status;
* duration and timestamp;
* the input `ctx`;
* console output and uncaught errors;
* redacted HTTP request and response previews, with body previews capped at 16 KiB;
* the returned result; and
* lead and metadata effects produced by the function.

Only the last saved and deployed code runs. Save again before testing unsaved changes.

Automatic executions are asynchronous and best-effort; they do not block the Nexor event that invoked them. Make external actions idempotent and use the logs to monitor their outcome.

## Cloud Functions or webhooks?

Use a Cloud Function when the event needs code: filtering, transformation, branching, calls to multiple systems, or a write back to the Nexor lead. Use a [webhook](/docs/en/api/webhooks/overview) when you only need Nexor to deliver a signed event to an endpoint you already operate.

Cloud Functions and webhooks use different event names and payload contracts. For example, the Cloud Function trigger is `lead.status_changed`, while the related webhook event is `workflow_run.status_changed`. Do not parse `ctx` as a webhook envelope.

<Warning>
  Make lead updates idempotent, especially in functions triggered by `lead.updated` or status changes. Guard against processing the same state twice or retriggering logic after your own update.
</Warning>
