---
title: "Act on an event"
method: POST
path: "/v1/hooks/n8n"
tags: ["Webhooks"]
---

# Act on an event

`POST /v1/hooks/n8n`

## Request

- Base URL: `https://api.automatedclientacquisition.com`
- URL: `https://api.automatedclientacquisition.com/v1/hooks/n8n`
- Auth: one of:
  - HTTP bearer
  - API key in header `x-webhook-secret`

Post back into ACA to act on an event.

Authenticate with your normal `Authorization: Bearer aca_…` token, in
which case the organization comes from the token and `organization_id`
in the body is optional (and must match the token if you send it).

A webhook secret from [Settings → Webhooks](/settings?tab=webhooks) sent
as `x-webhook-secret`, together with an explicit `organization_id`, also
works. One of the two is required — an organization with no secret
configured is not an organization that accepts unauthenticated writes.

Target the contact by `contact_id`, `conversation_id`, `contact_email` or
`contact_phone` — at least one is required. `contact_email` and
`contact_phone` are resolved against your organization only.

### The `data` payload per action

`data` is action-specific. Pick your action from the examples dropdown to see
the exact shape.

| Action | `data` fields |
| --- | --- |
| `send_message` | `content` (required), `channel` |
| `add_tag` | `tag_name` **or** `tag_id` |
| `remove_tag` | `tag_name` **or** `tag_id` |
| `change_stage` | `stage_name` **or** `stage_id` |
| `update_score` | `score_delta` (relative) **or** `score` (absolute) |
| `add_note` | `content` |
| `enroll_in_sequence` | `sequence_id`; optional `delay_hours`, `allow_concurrent` |
| `remove_from_sequence` | `sequence_id` **or** `enrollment_id`; optional `status` (`completed`, `paused`, `unsubscribed` — default `completed`) |
| `set_ai_handling` | `ai_handling` (boolean) |
| `assign_to_user` | `user_id`, or `null` to unassign |

Every failed action — an unknown name, a missing field, a contact that
could not be resolved, an enrollment that matched nothing — returns
**400** with `{ "success": false, "message": "…" }`. Only a completed
action returns 200. Every call is logged either way.

## Request body

- object
  - `organization_id` string, uuid: Required when authenticating with `x-webhook-secret`. Optional with an API token — it comes from the token, and a value that disagrees with the token is rejected.
  - `action` 'send_message' | 'add_tag' | 'remove_tag' | 'change_stage' | 'update_score' | 'add_note' | 'enroll_in_sequence' | 'remove_from_sequence' | 'set_ai_handling' | 'assign_to_user', required: Which action to run. Determines the shape of `data`.
  - `contact_id` string, uuid: Target directly by contact.
  - `conversation_id` string, uuid: Target by conversation — the contact is resolved from it.
  - `contact_email` string: Target by email, resolved within your organization.
  - `contact_phone` string: Target by phone, resolved within your organization.
  - `data` object, required: Action-specific payload — see the table above.
  - `source_event_id` string: Your own reference to the event that triggered this. Logged for tracing.

## Response `200`

Action executed.

- object
  - `success` boolean
  - `message` string

## Other responses

- `401`: Invalid webhook secret.

---

[API](https://skmtc.dev/automatedclientacquisition/apis/aca-api.md) · [All operations](https://skmtc.dev/automatedclientacquisition/apis/aca-api/llms.txt) · [OpenAPI document](https://skmtc.dev/automatedclientacquisition/apis/aca-api/revisions/8f3e3b141311?raw)
