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

# Upsert Agent Trigger

> Create or update the authenticated user's trigger for an integration on an agent. The integration must already be connected to the agent (its OAuth connection set up in the Duvo dashboard). Set `enabled: false` to pause a trigger without deleting it. An agent holds one trigger per integration for a user, so a save with a different `trigger_type` replaces the existing one — except when that trigger is an @mention trigger, which is managed from the agent's mention setting and answers 409 (`mention_trigger_protected`) here. @mention triggers are best managed from that setting throughout: this route leaves an existing one's `filter_config` untouched, and refuses to create a `teams_mention` trigger without a `filter_config.tenantId` (400, `mention_trigger_workspace_required`) — a Slack mention trigger has no equivalent field to supply.



## OpenAPI

````yaml https://api.duvo.ai/v2/documentation/mintlify.json put /v2/triggers/{agentId}
openapi: 3.0.3
info:
  title: Duvo Public API
  description: >-
    Public API for programmatic access to Duvo. Authenticate with API keys
    created in the Duvo dashboard.


    ## Rate limits


    Requests are counted per API key. Every response advertises the quota with
    the IETF RateLimit fields, so a client can self-throttle without waiting for
    a rejection:


    - `RateLimit-Policy: "default";q=<quota>;w=<window seconds>` — the policy in
    force: `q` requests per `w` seconds.

    - `RateLimit: "default";r=<remaining>;t=<seconds>` — the live state: `r`
    requests left, quota resetting in `t` seconds.

    - Read the quota from the headers rather than hard-coding it; it differs per
    environment.

    - The same numbers are also sent as `ratelimit-limit`, `ratelimit-remaining`
    and `ratelimit-reset`.


    Once the quota is exhausted the API answers `429 Too Many Requests` with
    `Retry-After` set to the seconds to wait; honor it instead of retrying
    immediately.
  version: 1.0.0
servers:
  - url: https://api.duvo.ai
    description: Production server
security: []
tags:
  - name: Runs
    description: Start, monitor, and manage agent runs (Runs in the Duvo UI)
  - name: Sandboxes
    description: Create sandboxes and upload files for agent runs
  - name: Queues
    description: Manage queues and their agent bindings
  - name: Cases
    description: Create, list, and manage cases and their labels within queues
  - name: Case Approvals
    description: Submit decisions on pending case approval requests issued by an agent run
  - name: Case Attachments
    description: Upload, list, download, and remove the files attached to a case
  - name: Automations
    description: >-
      List and manage automations — the workspace container that groups the
      agents and queues making up one end-to-end process
  - name: Agents
    description: Create and manage agents for automation workloads
  - name: Revisions
    description: Create and manage agent revisions — the underlying Setup for an Agent
  - name: Agent Folders
    description: Organize agents into folders
  - name: Agent Memory
    description: Read an agent's memory files (the Memory feature in the Duvo UI)
  - name: Suggestions
    description: >-
      List, apply, and dismiss an Agent's improvement suggestions (the
      suggestions inbox in the Duvo UI)
  - name: Notifications
    description: >-
      List, read, dismiss, and clear the authenticated user's team notifications
      (the Notification Center in the Duvo UI)
  - name: Schedules
    description: List schedules configured for an agent
  - name: Duvo Pulse
    description: >-
      Create, list, iterate on, and delete Duvo Pulse dashboards — live,
      agent-generated visualizations of your Duvo data
  - name: Case Triggers
    description: >-
      Configure case triggers that automatically dispatch agent runs (Runs in
      the Duvo UI) for cases added to a queue
  - name: Triggers
    description: >-
      Configure event triggers that start a Run automatically when an external
      event fires (e.g. an email arrives, a Linear issue is created, or a file
      changes in Google Drive)
  - name: Skills
    description: Manage team and system skills (reusable knowledge packs).
  - name: Files
    description: Manage team files.
  - name: Plugins
    description: Discover plugins that can be referenced from a revision.
  - name: Organizations
    description: Inspect organizations you belong to and the teams within them
  - name: Team
    description: Inspect the team and members associated with the API key
  - name: Invites
    description: >-
      Invite people to a team — one at a time or in bulk, scoped to a Clarity
      process or the whole team — and manage the team's shareable invite link
  - name: Integrations
    description: Browse the team's catalog of available integration types
  - name: Connections
    description: Manage your connected integrations
  - name: Credentials
    description: >-
      Manage logins (domain + username + password + TOTP) used by agents to sign
      in to websites and desktop applications, and attach them to assignment
      revisions
  - name: Secrets
    description: >-
      Manage env-var secrets injected into runs, and attach them to assignment
      revisions. Only metadata is exposed; values are never returned
  - name: Revision Integrations
    description: >-
      Attach integrations to assignment revisions, pin specific connections, and
      link queues
  - name: ClarityV2
    description: >-
      Manage Clarity v2 process snapshots, automation proposals, and the
      extra-capture-request follow-up loop
paths:
  /v2/triggers/{agentId}:
    put:
      tags:
        - Triggers
      summary: Upsert Agent Trigger
      description: >-
        Create or update the authenticated user's trigger for an integration on
        an agent. The integration must already be connected to the agent (its
        OAuth connection set up in the Duvo dashboard). Set `enabled: false` to
        pause a trigger without deleting it. An agent holds one trigger per
        integration for a user, so a save with a different `trigger_type`
        replaces the existing one — except when that trigger is an @mention
        trigger, which is managed from the agent's mention setting and answers
        409 (`mention_trigger_protected`) here. @mention triggers are best
        managed from that setting throughout: this route leaves an existing
        one's `filter_config` untouched, and refuses to create a `teams_mention`
        trigger without a `filter_config.tenantId` (400,
        `mention_trigger_workspace_required`) — a Slack mention trigger has no
        equivalent field to supply.
      operationId: upsertAgentTrigger
      parameters:
        - schema:
            type: string
            format: uuid
          in: path
          name: agentId
          required: true
          description: The agent's unique identifier
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                integration_slug:
                  type: string
                  description: >-
                    Integration slug the trigger fires for (e.g. `gmail`,
                    `outlook`, `linear-native`, `google-drive`).
                trigger_type:
                  type: string
                  description: >-
                    Trigger type within the integration (e.g. `email_received`).
                    Discover valid values via the trigger types endpoint.
                    Integrations that enumerate their trigger types (Microsoft
                    Teams, Google Drive, Google Sheets) reject anything else
                    with 400 (`trigger_type_unsupported`), except a save that
                    pauses a trigger already carrying that type.
                filter_config:
                  description: >-
                    Integration-specific filter config (e.g. sender/subject
                    filters). Shape comes from the integration's filter schema.
                    Replaces the trigger's current config, so send the whole
                    object — except on an @mention trigger, whose config is
                    managed from the agent's mention setting and is left as it
                    is.
                  default: {}
                  type: object
                  additionalProperties: {}
                enabled:
                  default: true
                  description: Whether the trigger is active. Defaults to true.
                  type: boolean
              required:
                - integration_slug
                - trigger_type
      responses:
        '200':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  agent_id:
                    type: string
                  user_id:
                    type: string
                  integration_slug:
                    type: string
                  trigger_type:
                    type: string
                  filter_config:
                    type: object
                    additionalProperties: {}
                  integration_instance_id:
                    type: string
                  enabled:
                    type: boolean
                  auto_disabled_at:
                    type: string
                    nullable: true
                  auto_disabled_reason:
                    type: string
                    nullable: true
                  consecutive_missing_connection_failures:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  first_missing_connection_failure_at:
                    type: string
                    nullable: true
                  last_missing_connection_failure_at:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  webhook_status:
                    nullable: true
                    description: >-
                      Whether the upstream webhook this trigger needs is
                      registered. Null when the save needed no webhook work:
                      every trigger type but Jira today, and a Jira save with
                      `enabled: false`. Every enabled Jira save reconciles, so
                      saving again retries a failed registration. `registered`
                      means Duvo holds a current subscription covering this
                      trigger's projects. `connection_required` means the Jira
                      Connection this trigger is bound to names no Atlassian
                      site, so there is nothing to register against; reconnect
                      Jira and save again. `project_not_found` means Jira found
                      no project for one of `filter_config.project_keys` that
                      the Connection can open, so that key is left out of the
                      webhook; check the keys and save again. `failed` means
                      Atlassian refused or the call did not complete; see
                      `webhook_error` and retry. The trigger row is saved in
                      every case; anything but `registered` means it will not
                      fire yet.
                    type: string
                    enum:
                      - registered
                      - connection_required
                      - project_not_found
                      - failed
                  webhook_error:
                    nullable: true
                    description: >-
                      On `failed`, a stable reason code for the refusal (for
                      example `http_403`, `rejected_by_jira`).
                      `conflict_other_binding` means the Connection's Jira
                      account already sends events to another Duvo Connection,
                      in this team or another, and Jira allows one per account;
                      connect a different Jira account.
                      `issue_created_unconfirmed` means Jira has not yet
                      confirmed that the webhook sends new issues, so they may
                      not start Runs; Duvo tries again about every two hours,
                      and saving again tries at once. Null otherwise.
                    type: string
                required:
                  - id
                  - agent_id
                  - user_id
                  - integration_slug
                  - trigger_type
                  - filter_config
                  - integration_instance_id
                  - enabled
                  - auto_disabled_at
                  - auto_disabled_reason
                  - consecutive_missing_connection_failures
                  - first_missing_connection_failure_at
                  - last_missing_connection_failure_at
                  - created_at
                  - updated_at
                  - webhook_status
                  - webhook_error
                additionalProperties: false
        '400':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
                  code:
                    description: >-
                      Stable discriminator for errors a client must tell apart.
                      `connection_missing_scopes` means the bound connection's
                      OAuth grant lacks a scope this trigger needs and must be
                      reconnected. `trigger_type_unsupported` means the
                      integration enumerates its trigger types and
                      `trigger_type` is not one of them, so the trigger could
                      never fire; the message lists the types it does have, and
                      the trigger types endpoint is the general source. A
                      trigger that already carries such a type can still be
                      paused (`enabled: false`, same `trigger_type`) and
                      deleted. `jira_watched_fields_required` means a Jira save
                      that enables or creates the trigger carried no readable
                      watched field in `filter_config.fields` and was not a
                      new-issues trigger (`filter_config.issue_created: true`
                      with no `fields`), so the trigger could never start a Run;
                      send at least one readable field id, or turn on new issues
                      and send no fields. An existing Jira trigger can still be
                      paused without either. `jira_project_keys_required` means
                      such a save carried no project key in
                      `filter_config.project_keys`; send at least one.
                      `jira_project_keys_limit` means it carried more than 50,
                      which is one Jira lookup page. `mention_trigger_protected`
                      means the trigger this save would replace is an @mention
                      trigger, which only the agent's mention setting may
                      change; delete it to free the integration.
                      `mention_trigger_workspace_required` means this save would
                      create a `teams_mention` trigger with no
                      `filter_config.tenantId`, which would match no inbound
                      mention; turn @mentions on from the agent's mention
                      setting, which resolves the tenant from the team's Teams
                      workspace, or send `tenantId` explicitly. Only Teams
                      mention triggers pin a workspace this way — a Slack one
                      needs no such field. `trigger_save_timed_out` means the
                      save did not finish inside the bound this route holds
                      while writing the trigger; nothing is wrong with the
                      request, so retry it.
                    type: string
                  integration_instance_id:
                    description: >-
                      On `connection_missing_scopes`, the connection that was
                      rejected — the one to reconnect. Several connections can
                      be bound to one agent, so this names which.
                    type: string
                    format: uuid
                required:
                  - error
                additionalProperties: false
        '401':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
                required:
                  - error
                additionalProperties: false
        '403':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
                required:
                  - error
                additionalProperties: false
        '404':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
                required:
                  - error
                additionalProperties: false
        '409':
          description: >-
            `mention_trigger_protected`: the trigger this save would replace is
            an @mention trigger and the requested `trigger_type` differs. Delete
            that trigger (`DELETE /v1/triggers/{agentId}/{triggerId}`, id from
            `GET /v1/triggers/{agentId}`) to use the integration for a different
            trigger type. `trigger_save_timed_out`: the save did not finish
            inside the bound this route holds while writing the trigger — retry.
            Without either code, the integration already has a trigger on this
            agent and the save simply collided.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
                  code:
                    description: >-
                      Stable discriminator for errors a client must tell apart.
                      `connection_missing_scopes` means the bound connection's
                      OAuth grant lacks a scope this trigger needs and must be
                      reconnected. `trigger_type_unsupported` means the
                      integration enumerates its trigger types and
                      `trigger_type` is not one of them, so the trigger could
                      never fire; the message lists the types it does have, and
                      the trigger types endpoint is the general source. A
                      trigger that already carries such a type can still be
                      paused (`enabled: false`, same `trigger_type`) and
                      deleted. `jira_watched_fields_required` means a Jira save
                      that enables or creates the trigger carried no readable
                      watched field in `filter_config.fields` and was not a
                      new-issues trigger (`filter_config.issue_created: true`
                      with no `fields`), so the trigger could never start a Run;
                      send at least one readable field id, or turn on new issues
                      and send no fields. An existing Jira trigger can still be
                      paused without either. `jira_project_keys_required` means
                      such a save carried no project key in
                      `filter_config.project_keys`; send at least one.
                      `jira_project_keys_limit` means it carried more than 50,
                      which is one Jira lookup page. `mention_trigger_protected`
                      means the trigger this save would replace is an @mention
                      trigger, which only the agent's mention setting may
                      change; delete it to free the integration.
                      `mention_trigger_workspace_required` means this save would
                      create a `teams_mention` trigger with no
                      `filter_config.tenantId`, which would match no inbound
                      mention; turn @mentions on from the agent's mention
                      setting, which resolves the tenant from the team's Teams
                      workspace, or send `tenantId` explicitly. Only Teams
                      mention triggers pin a workspace this way — a Slack one
                      needs no such field. `trigger_save_timed_out` means the
                      save did not finish inside the bound this route holds
                      while writing the trigger; nothing is wrong with the
                      request, so retry it.
                    type: string
                  integration_instance_id:
                    description: >-
                      On `connection_missing_scopes`, the connection that was
                      rejected — the one to reconnect. Several connections can
                      be bound to one agent, so this names which.
                    type: string
                    format: uuid
                required:
                  - error
                additionalProperties: false
                description: >-
                  `mention_trigger_protected`: the trigger this save would
                  replace is an @mention trigger and the requested
                  `trigger_type` differs. Delete that trigger (`DELETE
                  /v1/triggers/{agentId}/{triggerId}`, id from `GET
                  /v1/triggers/{agentId}`) to use the integration for a
                  different trigger type. `trigger_save_timed_out`: the save did
                  not finish inside the bound this route holds while writing the
                  trigger — retry. Without either code, the integration already
                  has a trigger on this agent and the save simply collided.
        '500':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
                required:
                  - error
                additionalProperties: false
      security:
        - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key authentication. Get your API key from the Duvo dashboard.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.