# Triggers and schedules

> An agent fires on a repeating schedule, when a CRM record is created or a field changes, or on demand against records you select in a table. Each option has its own conditions and reprocessing rules.

- Source: https://spiich.ai/help/background-agents/agent-triggers
- Section: Background agents
- Who can do this: Everyone
- Time: 6 minutes
- Last updated: 2026-08-24

## Before you start

- You can set up background agents.
- A CRM is connected if you want to use CRM event triggers.

Step 1 of the agent form asks "What type of agent is this?". The answer decides what you configure next, what the agent runs against, and who pays for the run.

## The trigger types

| Type | What it does | Runs against |
| --- | --- | --- |
| **Event-based** | Runs when a CRM event happens | The one record that changed |
| **Scheduled** | Runs on a schedule (hourly, daily, weekly, or monthly) | Your book of records, or nothing but the prompt |
| **Webhook** | Runs when an external service sends data | The record identified in the payload, if you set one up |
| **On-demand** | Run manually from a table on selected records | The records you selected |

Switching between the schedule type and the others clears the record type, because it means something different in each.

## Scheduled runs

Choose **Repeats**, then fill in what that repeat needs.

- **hourly**: pick the interval from **Every hour** up to **Every 12 hours**.
- **daily**: pick **Every day**, **Every other day**, or up to every 7 days.
- **weekly**: tick the weekdays under **On these days**.
- **monthly**: pick the date under **On day**. Days 1 to 28 are available, so a schedule never silently skips a short month.

Then set the time under **At**, in five-minute steps.

> **Careful:** Times run in the timezone of the member the agent runs as, not yours. The form says so: "Times are in the agent member's timezone." If that member has no timezone set, the schedule falls back to UTC. Set it in [`Settings > User Settings`](https://app.spiich.ai/settings/user).

The agent list resolves this and shows the real **Next run** on every row, so check that after saving rather than trusting the picker.

A scheduled agent can also be pointed at a set of records to scan rather than run as a plain prompt. Under **Which records should this agent process?** pick the record type, add the conditions that select them, and set a cap on how many records one run may process. Leave it alone and the agent simply runs your instructions on the schedule.

A scheduled agent can also be pinned to a fixed list of records rather than a filter. That is how Key Account Monitoring works when you upload an account list during setup. The row then reads "for {n} attached Organization records" instead of showing filters.

## Advanced: cron schedule

The schedule step carries a **basic** and **advanced** tab. Basic is the **Repeats**, **Every**, **On these days** and **At** pickers above. Advanced swaps them for a raw cron expression box, for the schedules the pickers cannot represent.

Type an expression such as `0 9 * * 1-5` and Spiich shows a plain-English preview underneath it, for example "At 09:00 AM, Monday through Friday", so you can check it reads the way you meant before you save. An expression that does not parse shows **Invalid cron expression**.

> **Careful:** Switching the tab back to **basic** is refused with "This expression can't be represented in basic mode" once the expression is too complex for the pickers to reproduce. Keep a copy of what you typed if you might want to simplify it later.

Cron schedules still run in the agent member's timezone, exactly like the basic pickers.

## CRM event triggers

Event-based agents react to your CRM instead of the clock. Step 2 asks "When should this agent activate?".

1. **Pick the record type**
   **Organization**, **Person**, **Deal** or **Task**. **Note** is available when the workspace is connected to HubSpot.

2. **Pick the event**
   **Created** or **Updated**. Note agents only support **Created**, and can be narrowed to a source integration under "From which integration?".

3. **Pick the field, for Updated**
   Under "Which field change should trigger this?", choose the exact field whose change starts the agent. Without this, every edit to the record fires it.

4. **Add the conditions**
   Under "What conditions must be met?", click **Add a rule** and build a field, operator and value test, then set **Match** to `all rules` or `any rule`.

The operators depend on the field type:

| Field type | Operators |
| --- | --- |
| Text | is exactly, is not, contains, does not contain, starts with, ends with, is empty, is not empty |
| Number or currency | equals, does not equal, is greater than, is less than, is at least, is at most |
| Select or label | is exactly, is not, is one of, is not one of |
| Date | in the last, not in the last, is before, is after, is between |
| Multi-value | includes, does not include |

You can nest a group of rules inside a group. Adding another rule is blocked until the current one is complete.

Two CRM-specific gotchas: on Attio, **Task** plus **Updated** is switched back to **Created** automatically, and the **Note** record type exists only on HubSpot. See [How CRM sync works](/help/your-data/crm-sync-rules).

## Webhook trigger

A Webhook agent starts when an outside service posts JSON to a private URL Spiich generates for it. Here is the setup end to end.

1. **Start a Custom Agent**
   Go to **Background Agents**, click **Create new**, then **Custom Agent**. In Step 1, "What type of agent is this?", click **Webhook**.

2. **Generate the URL**
   In Step 2, "Webhook configuration", click **Generate Webhook URL**. Spiich creates the endpoint and shows it under **Webhook URL**, with a copy button.

3. **Set the rate limit**
   Choose how many requests per second the endpoint accepts, from **1 request / second** up to **5 requests / second (max)**, the maximum allowed per customer.

4. **Point it at a record, if the payload identifies one**
   Fill in **Record ID field (optional)**, the JSON property in the incoming body that holds the record identifier, then choose a **Lookup mode**: **By CRM external ID** or **By attribute value** (pick the **Lookup attribute** for the latter). Set this and the matching record reaches the agent as context. Leave it blank and the agent runs with no record context.

5. **Add a description**
   **Description (optional)** notes which service calls this webhook, for whoever edits it next.

6. **Copy the secret**
   Under **Secret (save it now; it will not be shown again)**, copy the value and store it in the calling service. It is shown exactly once.

Sign every request with that secret so Spiich can trust it: compute an HMAC-SHA256 hex digest of the request body and send it in the `X-Webhook-Signature` header as `sha256=<hex>`.

Check what arrived under **View logs**, **Delivery History**, on the agent's webhook configuration. A fresh webhook reads "No deliveries yet."

> **Note:** A webhook agent cannot be fired from a table until **Allow running from Tables view** is switched on for it, same as an event-based agent.

Lost the secret, or think it leaked? Click **Regenerate secret**. The old one is invalidated immediately and any service still using it starts failing until you update it.

> **Careful:** Deleting a webhook stops the URL working immediately. The external service gets 404 errors from then on, and this cannot be undone.

## Running an agent on records you picked

Any agent set to **On-demand** can be fired from a table. An **Event-based** or **Webhook** agent joins them by switching on **Allow running from Tables view**, which adds manual runs on top of its automatic ones.

1. **Select the records**
   Open [Tables](/help/your-data/tables-and-views), open the table you want and select the records the agent should work on.

2. **Open the Run agent menu**
   In the bulk action bar, click **Run agent**. Under **Background agents** you see the agents available for that record type, each with its credit price. An agent with no record type set appears on every table.

3. **Confirm**
   The dialog gives the estimated credit cost and says "These runs are billed to you". Click **Run agent**.

A single record has the same menu on its header bar.

## Stopping an agent from repeating work

Two settings at the bottom of the form are the difference between a useful agent and an expensive one.

**Run once per record** controls when a record the agent already processed successfully becomes eligible again: **Once ever**, once per calendar day, week, month or year, or a **Custom interval** of 1 to 999 days, weeks, months or years. Calendar windows use the agent member's timezone and a week starts Monday.

**Daily run limit** caps successful runs per day, counted in UTC. Leave it blank for no limit. Once the cap is reached, further attempts are refused with "Daily limit reached" and logged in Usage History. The agent is deliberately not paused, because you set the cap on purpose.

The agent's **Records** section shows the result: an **Up next** tab listing what the next run will pick up, and an **Already run** tab with each record's next opportunity.

## Limits

- Monthly schedules can only use days 1 to 28, and hourly schedules repeat at most every hour.
- Daily run limits accept 1 to 10,000 successful runs per day.
- Event-based agents can only be run manually against organization, person and deal records.
- Attached record lists work on scheduled agents only.
- Webhook rate limit is 1 to 5 requests per second, the maximum allowed per customer.
- A webhook signing secret is shown once at creation. Regenerating it invalidates the old one immediately.
- A webhook agent needs **Allow running from Tables view** switched on before it can also be run manually.

## If something goes wrong

**The agent runs at the wrong time of day.** The schedule uses the timezone of the member the agent runs as. Set that timezone in `Settings > User Settings`, or change the schedule time, then check the resolved **Next run**.

**The agent keeps reprocessing the same records.** No **Run once per record** policy is set, so a record stays eligible after every successful run. Open **Configure**, switch it on and pick a cadence, then confirm in **Records > Already run**.

**Run agent now on an event-based agent asks for a record.** That is expected. Event-based, webhook and on-demand agents work on one record at a time. Pick it in the search dialog, or run the agent from Tables against a selection.

**The agent processed far fewer records than expected.** The per-run record cap applies, trimmed further by whatever is left of the daily run limit. Raise the cap in **Configure** and check the limit is not throttling the fan-out.

**I lost the webhook secret.** Open the agent, go to **Configure > Webhook configuration** and click **Regenerate secret**, then update the calling service. The old secret stops working immediately.

**The service calling my webhook gets 404 errors.** The webhook was deleted, which stops the URL working immediately. Generate a new one from **Configure > Webhook configuration** and update the URL and secret in the calling service.

## Frequently asked questions

### Can one agent have more than one trigger?

It has one trigger type, but an event-based agent can also be run by hand once **Allow running from Tables view** is on. That covers the common case of an agent that normally reacts to CRM changes but that you occasionally want to fire against a list you have just built.

### What happens if the agent fires while a previous run is still going?

The **Run once per record** policy is what stops the same record being picked up twice. If you are seeing overlap, tighten that policy or lower the schedule frequency.

### Why is Note missing from my record types?

The **Note** record type is only offered when the workspace is connected to HubSpot, and it only supports the **Created** event. On Attio and Pipedrive the option does not appear.

### Who pays for a run?

Whoever started it. Scheduled runs are billed to the member the agent runs as. On-demand runs, test runs and runs launched from a table are billed to the person who pressed the button, which the confirmation dialog states before you commit.

### How does Spiich know a webhook request is genuine?

It checks the signature you send. Compute an HMAC-SHA256 hex digest of the request body using the webhook’s secret, then send it as `sha256=<hex>` in the `X-Webhook-Signature` header. Store the secret in the calling service when you create the webhook, since it is only shown once.

## Related

- [Create a background agent](https://spiich.ai/help/background-agents/create-a-background-agent)
- [What an agent is allowed to do](https://spiich.ai/help/background-agents/agent-permissions)
- [Read and manage agent runs](https://spiich.ai/help/background-agents/monitor-agent-runs)
- [Tables and views](https://spiich.ai/help/your-data/tables-and-views)
- [Background Agents](https://spiich.ai/product/background-agents)
