# Update a mail trigger

PATCH

/v1/mail-triggers/{triggerId}

```sh
curl --request PATCH \
  --url https://example.com/v1/mail-triggers/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{ "flowId": "example", "flowVersion": "example", "agentId": "example", "agentVersion": "example", "config": { "mailbox": { "app": "google", "as": "company" }, "folder": "example", "pollSeconds": 1, "runsPerHour": 1 }, "label": "example", "toolsAllowedUnattended": [ "example" ] }'
```

Changes what it runs (which needs `execute` on the new target, and must be the project’s to reach), its mailbox (replaced whole), folder, pace or label (`null` clears it). To watch the inbox again, name it as the folder: `INBOX` on Gmail, `inbox` on Outlook. No edit moves the owner: a personal trigger’s change is its owner’s (who needs `write` on the project) or a project admin’s, a shared one’s is a project admin’s, and the company’s mailbox, before or after, takes a project admin. Only a personal trigger’s owner chooses what it reads from a person’s mailbox, another of their mailboxes or another folder: anyone else, a project admin included, gets a `403`, and may take the trigger over to watch their own. A project admin’s other changes to a person’s trigger, such as what it runs, its pace or a move to the company’s mailbox, keep its owner, so its runs go on acting as that person, and they’re audited as `trigger-changed-for-owner`, naming the trigger’s version after each. Since no edit moves the owner, with an authorization store a new target (another flow or agent) must be one the owner can run, a person or a service account, else `409 trigger-owner-cannot-run-target`; that’s not checked when the caller is the owner, nor for an owner that was unregistered or removed. `toolsAllowedUnattended` replaces the list (`[]` clears it; absent keeps it, a new version too), and a new target or mailbox while it lists any must name it again. Naming a list takes `admin` on the project; a personal trigger’s owner may name `[]` with their own new target or mailbox.

## Authorizations

- **[bearerAuth](https://docs.kindgi.com/v0.4.0/reference/api.md#bearerauth)**

## Parameters

### Path Parameters

**triggerId**

required

string format: uuid

TriggerId — the trigger id (a UUID).

### Header Parameters

**Idempotency-Key**

string

\>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per `docs/API-ROUTE-CONVENTIONS.md` §3.1). A retry sent while the first request still runs is answered `409 idempotency-key-in-flight` with `Retry-After`, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets `409 idempotency-key-replay-withheld`, with the first request’s status and when it succeeded (from 0.1.5). A request whose key store can’t be read before it runs is answered `503 idempotency-store-unavailable` with `Retry-After`: nothing ran, so retry with the same key (from 0.3.0).

## Request Bodyrequired

application/json

Change what it runs (the target fields, as at registration, which also needs `execute` on the new target), its mailbox (replaced whole), folder, pace or label. A personal trigger’s change is its owner’s or a project admin’s; a shared one’s, a project admin’s; and the company’s mailbox, before or after, takes a project admin. The owner stays.

object

**flowId**

Run a flow (with `flowVersion`).

string

\>= 1 characters

**flowVersion**

string

\>= 1 characters

**agentId**

Run an agent (instead of a flow): at `agentVersion`, else its pinned version.

string

\>= 1 characters

**agentVersion**

string

\>= 1 characters

**config**

A mail trigger’s mailbox, folder or pace, to change. An absent field keeps its value.

object

**mailbox**

The mailbox a mail trigger reads: its app (`google`: Gmail; `microsoft`: Outlook) and whose it is (`company`: the company’s mailbox, through the company’s connection of that app; `person`: the trigger owner’s own, through their connection).

object

**app**

required

string

Allowed values: google microsoft

**as**

required

string

Allowed values: company person

**folder**

The Gmail label id, or the Outlook folder id or well-known name, it watches from now. Absent: it keeps its folder, unless `mailbox` changes; then it watches the new mailbox’s inbox. To watch the inbox again, name it: `INBOX` in Gmail, `inbox` in Outlook.

string

\>= 1 characters <= 512 characters

**pollSeconds**

How often it looks for new mail, in seconds (default 60).

integer

\>= 30 <= 3600

**runsPerHour**

The most runs its mail starts in an hour (default 60). Past it, a mail’s fire is `refused` (`detail` starts `over-limit:`), and that mail doesn’t run later.

integer

\>= 1 <= 600

**label**

string | null

**toolsAllowedUnattended**

Replaces the list (`[]` clears it; absent keeps it). Naming it takes `admin` on the trigger’s project. A new target (not just a version) or another mailbox while it lists any must name it again, as it is or `[]`. Each tool by its id, with no wildcard or pattern, and only tools this trigger’s flow or agent calls. It lifts only that wait: the tenant’s approval rules, the agent’s own rules, the permission check (as the trigger’s owner) and the tool’s own limits all still apply.

Array\<string>

<= 100 items unique items

## Responses

### 200

Updated mail trigger.

application/json

A mail trigger: each new mail in its mailbox’s folder starts a run of its agent or flow, with the mail as the run’s input, as its owner. In such a run, every call that changes something, or uses the run’s own mailbox, waits for a person’s yes unless the trigger lists it (`toolsAllowedUnattended`).

object

**triggerId**

required

string

**flowId**

Run a flow (with `flowVersion`).

string

\>= 1 characters

**flowVersion**

string

\>= 1 characters

**agentId**

Run an agent (instead of a flow): at `agentVersion`, else its pinned version.

string

\>= 1 characters

**agentVersion**

string

\>= 1 characters

**projectId**

required

The trigger’s project: its runs are this project’s.

string format: uuid

**owner**

required

Who its runs act as, with their connections. A service account owns a shared trigger, on the company’s mailbox: one named with `runAsServiceAccountId`, or the project’s own (`runAsProject`, `isProjectAccount`). A person owns a personal one: every trigger on a person’s mailbox, and one on the company’s mailbox registered without either. No edit moves it; only a take-over (`POST …/owner`) does.

object

**kind**

required

string

Allowed values: user service

**id**

required

string

**displayName**

The owner’s name at the time of the response: the person’s display name, or the service account’s name. Absent when it can’t be read (no directory, a removed account) and from a runtime before Kindgi 0.1.6: show the id then.

string

**isProjectAccount**

Set when the owner is the trigger’s project’s own service account (`runAsProject`): the trigger is shared, and runs as the project. Show it as “This project”. Absent otherwise.

boolean

**mailbox**

required

The mailbox a mail trigger reads: its app (`google`: Gmail; `microsoft`: Outlook) and whose it is (`company`: the company’s mailbox, through the company’s connection of that app; `person`: the trigger owner’s own, through their connection).

object

**app**

required

string

Allowed values: google microsoft

**as**

required

string

Allowed values: company person

**folder**

The Gmail label id, or the Outlook folder id or well-known name, it watches. Absent: the inbox.

string

\>= 1 characters <= 512 characters

**pollSeconds**

required

How often it looks for new mail, in seconds (default 60).

integer

\>= 30 <= 3600

**runsPerHour**

required

The most runs its mail starts in an hour (default 60). Past it, a mail’s fire is `refused` (`detail` starts `over-limit:`), and that mail doesn’t run later.

integer

\>= 1 <= 600

**label**

required

string | null

**status**

required

Lifecycle status. Only `active` triggers fire. Tombstoned rows are excluded from every read path.

string

Allowed values: active paused

**statusReason**

Why it isn’t polling as it should: `connection-missing` (the mailbox’s connection is gone or lapsed; polls go on, and work again once it’s back), `owner-refused` (its owner was removed or may no longer run the target; polls go on and read nothing until that changes or an admin takes it over), or why the runtime paused it.

string

**version**

The trigger’s newest version (`GET …/versions`): one more for each change to what it runs, when, as whom or with what. Absent until its first version.

integer

\>= 1

**account**

The mailbox’s account at its last poll: the connection’s account id and its label (the address). Absent before its first poll.

object

**id**

required

string

**label**

required

string

**lastPolledAt**

When it last polled the mailbox and got an answer.

string format: date-time

**toolsAllowedUnattended**

The tools whose calls in this trigger’s runs don’t wait for a person’s yes, though a run a mail started asks for one for every call that changes something or uses its mailbox. Absent: none. Each tool by its id, with no wildcard or pattern, and only tools this trigger’s flow or agent calls. It lifts only that wait: the tenant’s approval rules, the agent’s own rules, the permission check (as the trigger’s owner) and the tool’s own limits all still apply.

Array\<string>

<= 100 items unique items

**lastFiredAt**

required

string | null format: date-time

**createdAt**

required

string format: date-time

**updatedAt**

required

string format: date-time

##### Example

```json
{
  "owner": {
    "kind": "user",
    "isProjectAccount": true
  },
  "mailbox": {
    "app": "google",
    "as": "company"
  },
  "status": "active"
}
```

### 400

A body that fails validation (`bad-input`): `runAsServiceAccountId` or `runAsProject` (the owner changes only by `POST …/owner`), a person’s mailbox for a shared trigger, or a new target or mailbox without the list it holds. Or `reference-out-of-scope`: the new target isn’t the project’s to reach. Nothing changes.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 401

Missing / malformed / expired / revoked bearer token.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 404

No mail trigger with that id.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 409

A new target the trigger’s owner can’t run (`trigger-owner-cannot-run-target`), with an authorization store. Or an Idempotency-Key reused with a different body.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 413

The request body is over the API’s limit (`request-too-large`; `details.maxBytes` says how much).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 500

Server error (unmapped domain code or framework crash).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 503

The `Idempotency-Key` store couldn’t be read before the request ran (`idempotency-store-unavailable`), so nothing was changed; `Retry-After` (whole seconds) says when to try again with the same key.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

## See also

- [`GET /v1/mail-triggers/{triggerId}`: Fetch a mail trigger](https://docs.kindgi.com/v0.4.0/reference/api/operations/mailtriggersget.md)
- [`POST /v1/mail-triggers/{triggerId}/pause`: Pause a mail trigger](https://docs.kindgi.com/v0.4.0/reference/api/operations/mailtriggerspause.md)
- [`POST /v1/mail-triggers/{triggerId}/resume`: Resume a mail trigger](https://docs.kindgi.com/v0.4.0/reference/api/operations/mailtriggersresume.md)
- [`POST /v1/mail-triggers/{triggerId}/unregister`: Soft-delete a mail trigger (tombstone)](https://docs.kindgi.com/v0.4.0/reference/api/operations/mailtriggersunregister.md)
- [Error code `bad-input`](https://docs.kindgi.com/v0.4.0/reference/errors.md#bad-input)
- [Error code `idempotency-store-unavailable`](https://docs.kindgi.com/v0.4.0/reference/errors.md#idempotency-store-unavailable)
- [Error code `reference-out-of-scope`](https://docs.kindgi.com/v0.4.0/reference/errors.md#reference-out-of-scope)
- [Error code `request-too-large`](https://docs.kindgi.com/v0.4.0/reference/errors.md#request-too-large)
- [Error code `trigger-owner-cannot-run-target`](https://docs.kindgi.com/v0.4.0/reference/errors.md#trigger-owner-cannot-run-target)
- [Every error code](https://docs.kindgi.com/v0.4.0/reference/errors.md)
