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

# Status-Change Triggers

> Start a Duvo agent automatically when a record in a CRM or project management tool reaches a particular state — a deal closes, a page moves to review, a ticket is resolved.

Status-change triggers let your agents start a Run automatically when a record in a connected tool — a CRM deal, a project task, a support ticket — reaches a particular state. Use them to chain Duvo workflows to the milestones that matter in your business: a deal closes, a project moves to review, a ticket is resolved.

## Key Capabilities

* **CRM stage monitoring** — React when a HubSpot deal or Salesforce opportunity moves to a target pipeline stage
* **Project status monitoring** — Start a Run when a Notion page status or Jira issue status changes to a configured value
* **Flexible polling cadence** — Run checks every few minutes for near-real-time response, or hourly for batch workflows
* **State memory** — Agent Memory stores the last-seen status of each record so the agent only fires once per genuine change, not on every poll
* **Multi-record support** — Process all records that changed state since the last check in a single Run, or trigger one Run per record

***

## How Status-Change Triggers Work

Duvo does not receive native push webhooks from CRM or project management tools (with the exception of Linear, which is already covered in [Event-Driven Triggers](/user-guide/assignment-features/event-driven-triggers)). Status-change monitoring is implemented by **scheduling an agent to run on a regular interval** and having the AOP:

1. Query the connected tool for records that have recently moved to the target state.
2. Compare results against the last-seen state stored in Agent Memory.
3. Process only the records that genuinely changed since the last Run.
4. Update Agent Memory with the new state before finishing.

```mermaid theme={"dark"}
flowchart TD
    A[Scheduled Run fires on interval] --> B[Query the connected tool for records in the target state]
    B --> C[Compare against last-seen state in Agent Memory]
    C --> D{Record genuinely changed since last Run?}
    D -->|No| E[Skip — already processed]
    D -->|Yes| F[Process the record's downstream action]
    F --> G[Update Agent Memory with the new state]
```

| Service                 | Mechanism             | Typical latency                                                                              |
| ----------------------- | --------------------- | -------------------------------------------------------------------------------------------- |
| HubSpot                 | Polling               | Equal to schedule interval                                                                   |
| Salesforce              | Polling               | Equal to schedule interval                                                                   |
| Notion                  | Polling               | Equal to schedule interval                                                                   |
| Jira (via Computer Use) | Polling               | Equal to schedule interval                                                                   |
| Linear                  | Native webhook (push) | Seconds — see [Event-Driven Triggers](/user-guide/assignment-features/event-driven-triggers) |

***

## When to Use Status-Change Triggers

* **Sales onboarding** — When a HubSpot or Salesforce deal moves to "Closed Won", start an onboarding agent that creates workspace accounts, sends a welcome email, and schedules a kickoff call
* **Contract review routing** — When a Notion page moves to "Ready for Legal Review", route the document to the legal team and post a Slack notification
* **Support escalation** — When a Zendesk ticket moves to "Escalated", create a Linear issue and assign it to the on-call engineer
* **Content publishing** — When a Notion page status changes to "Approved", export the content to your CMS and notify the author
* **Procurement follow-up** — When a Salesforce opportunity enters "Procurement Review", send a follow-up email and attach the latest price list

***

## How to Set It Up

<Steps>
  <Step title="Create the agent" icon="plus">
    1. Click **+ Create Agent** from your dashboard.
    2. Select **Use Agent Builder**.
  </Step>

  <Step title="Write your AOP" icon="pen-line">
    The AOP pattern for status-change triggers has three phases: **query**, **compare**, **act**.

    Here is a template adapted for a HubSpot deal stage change:

    ```
    Check HubSpot for deals that have moved to the stage "[Target Stage Name]" in the last
    [polling interval, e.g. 30 minutes].

    Compare the list of deal IDs to the "processed_deal_ids" list stored in memory.
    Only process deals whose IDs are NOT already in that list.

    For each new deal in the target stage:
    1. Retrieve the full deal record: company name, contact name, email, deal value, owner.
    2. [Describe your downstream action — examples below]
    3. Add the deal ID to "processed_deal_ids" in memory.

    At the end, save the updated "processed_deal_ids" list to memory.
    ```

    Replace `[Target Stage Name]` with your pipeline stage (for example, "Closed Won", "Contract Sent", or "Procurement Review"). Replace the downstream action with your specific workflow.
  </Step>

  <Step title="Add connections" icon="plug">
    Under **Connections**, enable the connection for the tool you are monitoring:

    * **HubSpot** — for deal or contact status changes
    * **Salesforce** — for opportunity or case status changes
    * **Notion** — for page or database entry status changes
    * **Human-in-the-Loop** — if the workflow includes an approval step

    Add any connections required for the downstream action (email, Slack, Google Sheets, etc.).
  </Step>

  <Step title="Enable Agent Memory" icon="brain">
    Go to **Setup** and enable **Agent Memory**. The AOP will use it to store the IDs of records already processed.
  </Step>

  <Step title="Set a schedule" icon="clock">
    1. Click **Schedule** in the agent header.
    2. Choose an interval: every 15 minutes for near-real-time response, or every hour for batch workflows.
    3. Click **Add schedule** to save.
  </Step>
</Steps>

***

## Worked Example — "Closed Won" Deal Triggers Onboarding

**Outcome**: When a HubSpot deal moves to "Closed Won", Duvo starts an onboarding Run that creates accounts for the new customer, sends a welcome email, and notifies the customer success team in Slack.

**Connections used**:

* HubSpot — query deals by stage
* Gmail — send the welcome email
* Slack — notify the customer success channel
* Human-in-the-Loop — optional approval step before sending the email

### AOP

```
Check HubSpot for deals that moved to the stage "Closed Won" in the last 30 minutes.

Compare the deal IDs to the "onboarded_deal_ids" list in memory. Skip any deal already in the list.

For each new "Closed Won" deal:
1. Retrieve the deal record: company name, primary contact name and email, deal value, account owner.

2. Request human approval before sending any external communications:
   Title: "Onboarding ready — [Company Name] — [Deal Value]"
   Body: "Deal closed. About to send welcome email to [Contact Name] at [Contact Email].
          Account owner: [Owner]. Approve to proceed or reject to pause."

3. After approval, send a welcome email to the primary contact:
   Subject: "Welcome to [Your Company] — let's get you started"
   Body: Personalized welcome including their name, company, and a link to the onboarding calendar.

4. Post a message to the #customer-success Slack channel:
   "New customer: [Company Name] ([Deal Value]) — welcome email sent to [Contact Name].
    Owner: [Owner]. Kickoff link: [link]."

5. Add the deal ID to "onboarded_deal_ids" in memory.

Save the updated "onboarded_deal_ids" list to memory.
```

### Connections to enable

* **HubSpot**
* **Gmail** (the account sending the welcome email)
* **Slack** (for the #customer-success channel notification)
* **Human-in-the-Loop** (for the approval step before external communications)

### Expected results

When the agent runs every 15 minutes:

* Deals that moved to "Closed Won" since the last Run are identified.
* A Human-in-the-Loop approval appears in Requests for each new deal.
* After approval, a personalized welcome email is sent and #customer-success is notified.
* The deal ID is added to Agent Memory so the next Run does not re-process it.

***

## Adapting for Other Services

<Tabs>
  <Tab title="Salesforce">
    **Opportunity stage change** — The pattern is the same. Replace the HubSpot query with a Salesforce SOQL query:

    ```
    Query Salesforce for opportunities where StageName = '[Target Stage]'
    and LastModifiedDate > [current time minus polling interval].

    For each opportunity not already in "processed_opportunity_ids" in memory:
    [your downstream action]
    Add the opportunity ID to "processed_opportunity_ids" in memory.
    ```

    **Example target stages**: Closed Won, Proposal/Price Quote, Negotiation/Review.
  </Tab>

  <Tab title="Notion">
    **Page status change** — Notion databases support a "Status" property. Query for pages where the Status equals your target value:

    ```
    Search the Notion database "[Database Name]" for pages where Status = "[Target Status]".

    For each page not already in "processed_notion_ids" in memory:
    [your downstream action — for example, export content, send notification, create ticket]
    Add the page ID to "processed_notion_ids" in memory.
    ```

    **Example target statuses**: Ready for Review, Approved, Published.
  </Tab>

  <Tab title="Jira">
    **Issue status change** — Jira does not have a native Duvo connection. To monitor Jira status changes, use [Computer Use](/user-guide/connections/computer-use-overview) to navigate the Jira web interface and read the issue list:

    ```
    Open [your Jira project URL] and filter for issues with status "[Target Status]"
    that were last updated in the past [polling interval].

    For each issue not already in "processed_jira_ids" in memory:
    [your downstream action]
    Add the issue key to "processed_jira_ids" in memory.
    ```

    For teams using Jira alongside Linear, note that Linear has a native webhook-based trigger that fires in real time — consider whether Linear can serve as the trigger source instead.
  </Tab>
</Tabs>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="The same record is processed more than once" icon="copy">
    * The Agent Memory key must be written at the end of each successful Run. If the Run fails partway through, the memory update may not have been saved. Check the session log to see where the failure occurred.
    * Make sure the AOP adds the ID to memory **before** the Run ends, even if the downstream action fails. Adjust the AOP: "Add the ID to memory regardless of whether the downstream action succeeds."
  </Accordion>

  <Accordion title="Records that changed state are not detected" icon="search">
    * **Time window too narrow**: The AOP queries for records changed "in the last X minutes". If the schedule interval is 15 minutes but the query window is 10 minutes, changes in the gap are missed. Set the query window to match or slightly exceed your polling interval.
    * **Timezone mismatch**: The query compares Duvo's time against the timestamp in the CRM. Confirm both are in the same timezone, or use UTC for the comparison.
    * **API pagination**: If many records changed state at once (for example, after a bulk import), the query may return only the first page. Add to your AOP: "Retrieve all pages of results, not just the first."
  </Accordion>

  <Accordion title="Memory grows very large over time" icon="database">
    Agent Memory is designed for moderate-size tracking lists. If your workflow processes hundreds of records per day, the `processed_ids` list can become large over time. Limit memory growth by expiring old entries:

    ```
    When adding a new ID to "processed_deal_ids", also remove any IDs older than 30 days from the list.
    ```
  </Accordion>
</AccordionGroup>

***

## Take It Further

**Chain to a second agent**

After completing the onboarding Run, schedule a follow-up check 7 days later:

```
At the end of the Run, schedule this assignment to run once in 7 days
with the deal ID as context, to check whether the onboarding tasks were completed.
```

See [Scheduling Agents](/user-guide/assignment-features/scheduling-assignments) for self-scheduling patterns.

**Notify via multiple channels**

Combine email and Slack in the same Run, or add a Human-in-the-Loop request for high-value deals:

```
If the deal value exceeds $100,000, request human approval before sending the welcome email.
```

**Multi-stage chaining**

Create separate agents for each key pipeline stage. When a deal enters "Contract Sent", fire one Run; when it enters "Closed Won", fire another. Each agent handles the actions appropriate to that stage.

***

## Related

<CardGroup cols={2}>
  <Card title="Event-Driven Triggers" icon="bolt" href="/user-guide/assignment-features/event-driven-triggers">
    Overview of all trigger types and the trigger matrix.
  </Card>

  <Card title="Scheduling Agents" icon="calendar" href="/user-guide/assignment-features/scheduling-assignments">
    Set the polling interval.
  </Card>

  <Card title="Agent Memory" icon="brain" href="/user-guide/assignment-features/assignment-memory">
    Track last-seen state to avoid duplicate processing.
  </Card>

  <Card title="Human-in-the-Loop" icon="user-check" href="/user-guide/assignment-features/human-in-the-loop">
    Add approval gates before irreversible actions.
  </Card>

  <Card title="HubSpot" icon="users" href="/user-guide/connections/available-connections/hubspot">
    Connect HubSpot.
  </Card>

  <Card title="Salesforce" icon="cloud" href="/user-guide/connections/available-connections/salesforce">
    Connect Salesforce.
  </Card>

  <Card title="Notion" icon="book" href="/user-guide/connections/available-connections/notion">
    Connect Notion.
  </Card>

  <Card title="Computer Use" icon="monitor" href="/user-guide/connections/computer-use-overview">
    Browser-based access for tools without a native connection.
  </Card>
</CardGroup>
