> ## 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.

# Scheduled Functions

> Create scheduled JavaScript jobs, select the lead cohort they receive, run them safely, and inspect their execution history.

Scheduled Functions run isolated JavaScript on a cron schedule. Each scheduled tick receives a fresh, organization-scoped cohort and can call external APIs or queue controlled changes in Nexor.

Use a Scheduled Function for logic that must run on a clock and is clearer in code, such as re-scoring older leads, synchronizing a nightly cohort, or distributing unassigned leads. Use a [Cloud Function](/docs/en/guides/advanced/cloud-functions) when an event in Nexor should trigger the code instead.

<Warning>
  **Run** and **Run now** are live executions, not dry runs. HTTP requests are sent and buffered effects are applied after the function finishes successfully. Use test endpoints, narrow the cohort, and inspect the preview before executing.
</Warning>

## Create a function

In the dashboard, organization Owners, Admins, and Partners can create, edit, run, pause, clear history, or delete Scheduled Functions.

<Steps>
  <Step title="Choose a starting point">
    Open **Developers → Scheduled Functions** and select **New job**. Start blank or choose **Re-score stale leads**, **Tag inactive**, or **Round-robin unassigned**.
  </Step>

  <Step title="Set the schedule">
    Enter a name, choose a frequency, confirm the timezone, and continue. You can edit the cron expression and timezone later.
  </Step>

  <Step title="Define the lookup scope">
    Select the leads, AI agents, and hosts that the code needs. Narrow the lead query and set the maximum number of leads loaded per run.
  </Step>

  <Step title="Write and save the code">
    Implement `onSchedule(ctx)`, add environment variables for secrets, and save to deploy the current code and schedule.
  </Step>

  <Step title="Preview, run, and monitor">
    Preview the cohort, run with a controlled input, and inspect the output. Leave the function active only after the result, logs, requests, and effects match your intent.
  </Step>
</Steps>

The starter templates are editable examples, not background modes. Review their query, IDs, limits, and code before saving.

| Template                   | Starting behavior                                                              |
| -------------------------- | ------------------------------------------------------------------------------ |
| **Blank**                  | Loads leads and runs an empty `onSchedule(ctx)` body.                          |
| **Re-score stale leads**   | Selects leads not contacted recently and lowers a score stored in metadata.    |
| **Tag inactive**           | Selects leads without recent contact and adds an `inactive` tag.               |
| **Round-robin unassigned** | Selects unassigned leads and distributes them across the user IDs you provide. |

## Configure the schedule

The editor provides presets for every 5 minutes, every 15 minutes, hourly, every 4 hours, and daily execution. Select **Custom** to enter a five-field cron expression.

The timezone controls when calendar-based expressions run. For example, `0 9 * * *` means 09:00 in the function's selected timezone, not necessarily the browser's timezone. The schedule preview asks the server to calculate the next occurrences so you can verify both values together.

<Tip>
  Pause a function while changing an external integration or investigating failures. Pausing prevents future scheduled ticks, but an execution already in progress may still finish.
</Tip>

## Select the lookup scope

Nexor resolves the lookup scope immediately before each tick. The function receives data from the same organization only.

The lead lookup can filter by:

* active, historic, or all leads;
* Agent and stage;
* campaign;
* assigned user or unassigned leads;
* name, email, or phone search;
* a moving created-at window in hours or days; and
* sort order and a per-run lead limit.

The lead batch defaults to 50 and can be set from 1 to 500. A query can reduce the batch further. **Preview cohort** shows the total matches and a sample, while the configured cap controls how many rows reach `ctx.leads` during a run.

AI agents and human hosts are optional lookup groups. Include them only when the code reads `ctx.agents` or `ctx.hosts`; otherwise those arrays are empty.

## Read the run context

Every scheduled tick receives a `ctx` object with this structure:

| Field               | Contents                                              |
| ------------------- | ----------------------------------------------------- |
| `ctx.event`         | The fixed event name `schedule.tick`.                 |
| `ctx.client_id`     | The organization that owns the function.              |
| `ctx.scheduled_for` | The scheduled occurrence represented by this run.     |
| `ctx.timezone`      | The function's IANA timezone.                         |
| `ctx.cron`          | The saved cron expression.                            |
| `ctx.leads`         | The capped lead cohort resolved from the lookup.      |
| `ctx.agents`        | Active AI agents when that lookup group is enabled.   |
| `ctx.hosts`         | Active human hosts when that lookup group is enabled. |
| `ctx.effects`       | Buffered, tenant-scoped Nexor actions.                |

The runtime also provides `env`, `axios`, `fetch`, `console`, and `helpers`. `helpers.uuid()` creates a UUID, `helpers.now()` returns the current timestamp, and `helpers.daysAgo(n)` returns a timestamp relative to the run.

## Write controlled effects

Effects are buffered while the JavaScript runs. Nexor applies them after a successful execution and scopes every mutation to the organization that owns the function.

```javascript theme={null}
export default async function onSchedule(ctx) {
  for (const lead of ctx.leads) {
    if (!lead.tags.includes("reviewed")) {
      ctx.effects.tagLead(lead.id, ["reviewed"]);
    }
  }

  return { reviewed: ctx.leads.length };
}
```

Available effects are:

| Effect                                          | Action                                       |
| ----------------------------------------------- | -------------------------------------------- |
| `upsertLead(lead)`                              | Creates or matches a lead by email or phone. |
| `updateLead(leadId, patch)`                     | Merges supported fields into a lead.         |
| `updateMetadata(leadId, patch)`                 | Merges keys into the lead's metadata.        |
| `assignLead(leadId, userId)`                    | Assigns a lead to a human user.              |
| `assignToWorkflow(leadId, workflowId, reason?)` | Enrolls a lead in an Agent.                  |
| `tagLead(leadId, tags)`                         | Adds one or more tags.                       |
| `setLeadStatus(leadId, statusKey, workflowId?)` | Moves a lead to a status.                    |
| `deactivateWorkflowRun(leadId)`                 | Stops active Agent runs for the lead.        |
| `updateEnvironmentVariable(key, value)`         | Replaces an existing environment variable.   |

If the function throws or times out, its buffered effects are not applied. Calls already made with `axios` or `fetch` cannot be rolled back, so make external writes idempotent.

## Use environment variables

Cloud Functions and Scheduled Functions use the same organization-level environment variables. Read a value as `env.NAME`, and never place a token directly in the function source.

The dashboard masks stored values after save; the list shows the name, not the value. Creating, replacing, or deleting one redeploys all saved Cloud Functions and all active Scheduled Functions so their bindings stay current.

<Warning>
  `updateEnvironmentVariable(key, value)` rotates an existing secret as a live effect. Its value is redacted from the stored run details, but the change affects other functions that use the same variable.
</Warning>

## Run and inspect safely

Save and deploy pending edits before selecting **Run**. The run dialog offers two inputs:

* **Live cohort** resolves the saved lookup immediately before execution.
* **Custom ctx** sends the JSON you provide instead of resolving the saved cohort.

Both modes execute the deployed code, send real HTTP requests, and can apply real effects. A custom context changes the input; it does not turn the execution into a simulation.

The run history records the origin, status, duration, candidate count, applied and failed effects, console output, HTTP request previews, returned result, and errors. The health summary uses recent scheduled executions; manual runs remain visible but do not change the scheduled uptime calculation.

Clearing history deletes every stored run for that function permanently. Deleting a Scheduled Function also deletes its run history and cannot be undone.

## Use the public API

REST keys can use the Scheduled Functions endpoints. MCP keys need `workflows:read` for reads and previews, and `workflows:write` for creation, updates, execution, deletion, and clearing history.

<CardGroup cols={2}>
  <Card title="List Scheduled Functions" icon="list" href="/docs/en/api/scheduled-functions/list-scheduled-functions">
    Read the functions available to the organization.
  </Card>

  <Card title="Create a Scheduled Function" icon="plus" href="/docs/en/api/scheduled-functions/create-scheduled-function">
    Create code, schedule, timezone, and lookup configuration.
  </Card>

  <Card title="Preview a schedule" icon="calendar-clock" href="/docs/en/api/scheduled-functions/preview-schedule">
    Validate cron and timezone against the next occurrences.
  </Card>

  <Card title="Preview a cohort" icon="users" href="/docs/en/api/scheduled-functions/preview-cohort">
    Count and sample the leads selected by a lookup.
  </Card>

  <Card title="Run a Scheduled Function" icon="play" href="/docs/en/api/scheduled-functions/run-scheduled-function">
    Start a live execution whose effects may apply.
  </Card>

  <Card title="List runs" icon="scroll-text" href="/docs/en/api/scheduled-functions/list-runs">
    Inspect execution history programmatically.
  </Card>
</CardGroup>
