---
title: "Create a webhook"
method: POST
path: "/v2/webhooks"
tags: ["Webhooks"]
---

# Create a webhook

`POST /v2/webhooks`

## Request

- Base URL: `https://api.village.ai`
- URL: `https://api.village.ai/v2/webhooks`
- Auth: HTTP bearer

Register a callback URL that Village will POST the user's own Village activity to, as it happens — new connections, job changes among their contacts, new search results, list changes, and sequence-email events. Use this to push activity into a CRM, an automation, or the user's own backend instead of polling. Because this sends the user's relationship data to a third-party endpoint, only register a URL the user has explicitly given you, and read it back to them before creating it. Provide `url` (publicly reachable http(s), HTTPS recommended; localhost and private IPs are rejected) and optionally `event_filter` to narrow which events are sent — omit it, or pass null, to receive EVERY event type including ones added later. Deliveries are HMAC-signed; pass your own `secret` (32+ characters), or omit it and Village generates one. This create response is the ONE place the secret is returned — save it if you intend to verify signatures, because reads only report `has_secret`, never the value. Returns the webhook with its encrypted id.

## Request body

- CreateWebhookRequest: Request body for registering a webhook endpoint
  - `url` string, uri, required: HTTP(S) endpoint that receives the event payloads (HTTPS recommended). Must be publicly reachable and controlled by the user — localhost and private IP ranges are rejected.
  - `description` string: Human-readable label, so you can tell your webhooks apart later
  - `secret` string: Your own HMAC signing secret (min 32 characters), used to sign every delivery so your endpoint can verify it really came from Village. Leave this out and Village generates one for you; either way the secret is readable via this API.
  - `is_active` boolean: Whether the webhook starts out receiving deliveries
  - `event_filter` string[], nullable: Event types this webhook receives. Pass null (or omit on create) to receive EVERY event type, including ones added in future. Pass an explicit array to narrow it.

## Response `200`

Webhook created successfully

- object
  - `data` CreateWebhookResponse, required: The newly registered webhook, including its signing secret (shown once).
    - `id` string, required: Encrypted webhook identifier
    - `url` string, required: Endpoint that receives event payloads
    - `description` string, nullable, required: Human-readable label, or null if none was set
    - `is_active` boolean, required: True when the webhook is receiving deliveries; false when paused
    - `event_filter` string[], nullable, required: Event types delivered to this webhook. NULL means every event type is delivered.
    - `has_secret` boolean, required: Whether an HMAC signing secret is configured. The secret value is write-only — it is returned once by create_webhook and never again, so reads report only this flag.
    - `created_at` string, required: ISO 8601 creation timestamp
    - `updated_at` string, required: ISO 8601 last update timestamp
    - `secret` string, nullable, required: The HMAC signing secret, returned ONLY here (once). Deliveries carry an X-Village-Signature header computed with it; store it now — reads never expose it again.
  - `metadata` object, required
    - `request_id` string, required

## Other responses

- `400`: Bad request - invalid parameters
- `401`: Unauthorized - missing or invalid authentication

---

[API](https://skmtc.dev/village/apis/village-v2-api.md) - [All operations](https://skmtc.dev/village/apis/village-v2-api/llms.txt) - [OpenAPI document](https://skmtc.dev/village/apis/village-v2-api/revisions/aebe21a1a544?raw)
