# Incoming webhooks

An incoming webhook is a private URL that another system — a form builder, a landing page
tool, Zapier, your own code — can send contact details to. Each request creates a contact, or
updates the contact with that email address if there is one.

Open it from **Settings → Incoming webhooks**.

![The Incoming webhooks list, showing each webhook's name, URL and when it last received a request](/images/placeholder.svg)

## Create a webhook

1. Click **New webhook**.
2. **What it does** is **Create or update a contact**. You can't change it after the webhook is
   created.
3. Give it a **Name** that says where the data comes from, such as "Landing page form".
4. Leave **Accepting requests** on.
5. Under **What to do with them**, choose:
   - **Status for new contacts** — **Subscribed**, **Pending**, **Unsubscribed** or
     **Transactional**. Default **Subscribed**.
   - **Add tags** and **Add to lists** — applied to every contact this webhook sends.
   - **Company** — only when the Companies [add-on](/add-ons/) is on. Everyone from this
     webhook is linked to that company, unless a request names its own.
6. Click **Add**.

The URL and the field mapping appear once it's saved. Open the webhook again with **Edit**
to see them.

:::caution[Choose the status carefully]
Only choose **Subscribed** if the people the other system sends have actually agreed to
marketing email. If the sender only collects details for an order or an account, use
**Transactional**. If [double opt-in](/settings/opt-in/) is on and you want new people to
confirm, use **Pending**.
:::

## Send data to it

The sender posts a JSON object to the webhook's URL. The URL looks like this:

```text
https://example.com/wp-json/markercrm/v2/public/hooks/9f2c…
```

Under **Fields you can post**, the edit dialog lists every contact field and custom field
with the **Key to post** for it. Click a key to copy it. A key named exactly like one of
these is used as it is:

```json
{
  "email": "sam@example.com",
  "first_name": "Sam",
  "last_name": "Rivera"
}
```

Nested objects are fine. `{"contact": {"email": "…"}}` is read as the key `contact.email`.

### If the sender uses its own names

When the other system's keys don't match yours, map them:

1. Open the webhook with **Edit** and click **Listen for a test request**.
2. Send one test request from the other system within two minutes.
3. The keys it sent appear under **Last request**. For each contact field, pick which key
   holds it. Fields you don't map show **Not sent**.
4. Map at least the email field, then click **Save**.

Use **Listen again** to capture a new test request. If nothing arrives in two minutes, you
see **Nothing arrived. Post a test request and try again.**

## What the sender gets back

| Response | Meaning |
|---|---|
| `202` | The request was received. If it couldn't become a contact — no email field, for example — it is still answered `202`, but nothing is created. |
| `404` | The URL is wrong, or the webhook isn't accepting requests. |
| `422` | The body wasn't a JSON object. |
| `429` | More than 60 requests in a minute to this URL. Try again shortly. |

The **Last request** column shows when the webhook last received something.

## Keep the URL secret

Anyone with the URL can create contacts in your CRM. Treat it like a password.

- Don't put it in a web page or front-end code that visitors can read.
- If it leaks, use **Issue a new URL** from the row's menu. The old URL stops working at
  once, so update the sender with the new one straight away.
- To pause a webhook without deleting it, turn off **Accepting requests**. The list then
  shows it as **Not accepting requests**.

The row's menu also has **Edit**, **Copy URL** and **Delete**. Deleting a webhook doesn't
remove the contacts it already created.

## Who can manage webhooks

Only people with the **Settings** permission. See
[Users and permissions](/settings/permissions/).
