# Create a sync trigger

> Add a trigger to a sync: when a record of the chosen table is created, updated or deleted in a source app and passes the filters, the action runs with the record (`<<data>>`) and its changes (`<<changes>>`). Send `validate_only: true` to run every check without storing.

Source: https://docs.stacksync.com/api-reference/syncs/triggers/create_sync_trigger

`POST https://api.stacksync.com/v1/workspaces/{workspace_id}/bases/{base_id}/triggers`

- Operation: `create_sync_trigger`
- Resource: Sync triggers
- Access: writes data

## Authentication

- `Authorization: Bearer <key>`: A workspace API key (workspace_…, created by a workspace owner under Workspace settings > Stacksync API) acts with editor rights on that workspace only; a user API key (user_…, created under Profile > Stacksync API) acts as that user in every workspace they belong to. POST, PUT and PATCH requests must send Content-Type: application/json. Every authentication failure answers 403.
- `Content-Type: application/json` on every request with a body.

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `workspace_id` | integer | Yes | The workspace the resources belong to |
| `base_id` | string (uuid) | Yes | The sync (a sync is called a base in these paths) |

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `region` | string (besg \| usnv) | Yes | Data region of the sync |

## Request body

`application/json`. The trigger to add. The example's host hooks.example.com is a placeholder: replace it with your own HTTPS endpoint; it must resolve publicly.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | The name of the trigger |
| `trigger_type` | string (webhook \| db_query \| queue) | Yes | `webhook` calls a URL, `db_query` runs SQL on a database connection, `queue` adds a message to a queue |
| `table` | string | Yes | The table whose changes fire the trigger, by its name in the `column_names_from_app` app (its id is accepted) |
| `column_names_from_app` | string | Yes | The app whose column names the trigger uses: its app type as shown in Stacksync, or its `app_id` when both apps have the same type |
| `operations` | array of string | Yes | The changes that fire the trigger, each once: `created`, `updated`, `deleted` |
| `source` | array of string, at least 1 item, at most 2 items | Yes | The app or apps whose changes fire the trigger, by app type (or `app_id` when both apps have the same type); the sync must read changes from that app's table |
| `columns_to_ignore` | array of string | Yes | Columns of the table left out of the record data the action receives (case sensitive, must exist in the table) |
| `filters` | object (TriggerFilterGroup) | Yes | Conditions combined with `and` or `or`; a group may hold other groups. An empty `and` group matches every change |
| `filters.type` | string (group) | Yes | `group` |
| `filters.operator` | string (and \| or) | Yes | How the conditions combine |
| `filters.conditions` | array of object (TriggerFilterCondition) \| object (TriggerFilterGroup) | Yes | A list (never a single object): each entry is a condition (TriggerFilterCondition) or a nested group (TriggerFilterGroup) |
| `action` | string \| object (TriggerDbQueryAction) \| object (TriggerQueueAction) | Yes | What runs: a cURL command (`webhook`), a query (`db_query`) or a queue message (`queue`) |
| `is_paused` | boolean, default false | No | True stores the trigger paused; false (the default) runs it |
| `validate_only` | boolean, default false | No | Run every check of the write and answer without writing: a refused write answers the error it would answer |

## Returns

### 200 The trigger created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | The new trigger |
| `msg` | string | Yes | `Trigger created successfully` |

### 204 Every check passed and nothing was written (`validate_only: true`)

No body.

## Example request

```bash
curl -X POST "https://api.stacksync.com/v1/workspaces/{workspace_id}/bases/{base_id}/triggers?region=besg" \
  -H "Authorization: Bearer $STACKSYNC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Notify on new customer accounts",
  "trigger_type": "webhook",
  "table": "Account",
  "column_names_from_app": "salesforce",
  "operations": [
    "created",
    "updated"
  ],
  "source": [
    "salesforce"
  ],
  "columns_to_ignore": [
    "Website"
  ],
  "filters": {
    "type": "group",
    "operator": "and",
    "conditions": [
      {
        "type": "condition",
        "column": "Type",
        "operator": "eq",
        "value": "Customer"
      },
      {
        "type": "group",
        "operator": "or",
        "conditions": [
          {
            "type": "condition",
            "column": "Rating",
            "operator": "eq",
            "value": "Hot"
          },
          {
            "type": "condition",
            "column": "Website",
            "operator": "has_ch",
            "value": ""
          }
        ]
      }
    ]
  },
  "action": "curl -X POST https://hooks.example.com/accounts -H '\''Content-Type: application/json'\'' -d '\''{\"record\": <<data>>, \"changes\": <<changes>>}'\''"
}'
```

`hooks.example.com` is a placeholder: replace it with your own host, which the API checks before saving (the example as written is refused).

## Example response (200)

```json
{
  "id": "0d1e2f3a-4b5c-4d6e-9f70-1a2b3c4d5e6f",
  "msg": "Trigger created successfully"
}
```

## Errors

| Status | Meaning | Body |
| --- | --- | --- |
| 400 | The `region` is missing or not one of besg, usnv; the body is not valid JSON; `base_id` is not a UUID; a field is missing or of the wrong type (`Invalid Request Body`, the message names the field); `trigger_type` is not webhook, db_query or queue; a webhook `action` is not one cURL command with one http(s) URL on a public host, or a word of it would not be sent; a `db_query` query is blank; `column_names_from_app`, `table`, a column of `columns_to_ignore` or of a condition is not in the sync; `source` names an app the sync does not read changes from on this table; both apps have the same type and an app type instead of an `app_id` was sent; a filter has a wrong structure, an unknown operator, a regular expression that does not compile or a non-number on a numeric column (the message is the error); the trigger could not be stored (`Error creating trigger`) | `{ "error": string }` |
| 403 | Forbidden: invalid API key, API key of another workspace, insufficient scope, workspace unavailable, or a non-GET request without `Content-Type: application/json`; a `db_query` `connection_id` is not a connection of the workspace in the sync's region (`Invalid connection_id`), or a `queue` `queue_id` is not a queue of the workspace (`Invalid queue_id`) | `{ "error": string }` |

## Related

- [API Reference overview](https://docs.stacksync.com/api-reference): base URLs, regions, pagination, idempotency and errors
- [Authentication](https://docs.stacksync.com/api-reference/authentication): API keys and the 403 answers
- OpenAPI document: https://docs.stacksync.com/openapi.json
- [List sync triggers](https://docs.stacksync.com/api-reference/syncs/triggers/list_sync_triggers)
- [Get a sync trigger](https://docs.stacksync.com/api-reference/syncs/triggers/get_sync_trigger)
- [Update a sync trigger](https://docs.stacksync.com/api-reference/syncs/triggers/update_sync_trigger)
- [Pause or resume a sync trigger](https://docs.stacksync.com/api-reference/syncs/triggers/update_sync_trigger_status)
- [Delete a sync trigger](https://docs.stacksync.com/api-reference/syncs/triggers/delete_sync_trigger)