> ## Documentation Index
> Fetch the complete documentation index at: https://docs.member.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Start an automation from Zapier or Make

> Give Zapier, Make or your own code a URL that finds or creates a contact by email and starts an automation for them.

Alice runs a hub, and her leads arrive in Typeform. She wants every new response to land in Mio as a contact and start her "New lead onboarding" [automation](https://docs.member.dev/guides/automations.md). An **inbound webhook** is the URL that makes this work: Zapier or Make posts the response to it with a secret in an `Authorization` header, Mio finds or creates the contact by email, and every live automation bound to that URL starts for them.

```text theme={null}
Typeform ──▶ Zapier / Make ──POST──▶ https://api.member.dev/api/hooks/in/<webhook id>
                                       Authorization: Bearer whk_<secret>
                                          │
                                          ▼
                              find or create the contact by email
                              write mapped custom fields
                                          │  202 Accepted
                                          ▼
                   automations bound to this URL start (within about a minute)
```

## Set it up

1. **Create the webhook.** In the API, `POST /api/v1/teams/{team_id}/hubs/{hub_id}/inbound-webhooks` with a name. The response carries `attributes.url`, and once, `attributes.secret` and `attributes.header`. The secret is shown only this one time, so copy it now. The URL holds no secret and can be shown again. Your assistant can do the same with the `create_inbound_webhook` tool.
2. **Bind an automation to it.** Create an automation whose trigger has `event_type` `automation.inbound_webhook.received` and `inbound_webhook_id` set to the webhook's `id`. The webhook must belong to the same hub.
3. **Publish and activate the automation before you test.** A request that arrives while no live automation is bound is still answered `202`, because `202` only means received. Nobody is enrolled, and that request is not replayed later.
4. **Point Zapier or Make at the URL.** Use a **Webhooks** action with method `POST`, payload type **JSON**, the URL from step 1, and one header: `Authorization` with the value `Bearer whk_<secret>` (the response's `attributes.header` gives the exact line). In Zapier that is *Webhooks by Zapier → POST → Payload Type: json*, with `Authorization` under *Headers*; in Make it is the *HTTP → Make a request* module with body type *Raw*, content type *JSON*, and `Authorization` added under *Headers*.
5. **Map the fields** (below), send a test, and check the automation's enrollments.

## What to send

One flat JSON object, up to 64 KiB. `email` is required; every other key is optional.

```json theme={null}
{
  "email": "bob@example.com",
  "first_name": "Bob",
  "plan": "pro",
  "utm_source": "typeform"
}
```

| Key | What Mio does with it |
| - | - |
| `email` | Finds the contact, or **creates** one if the address is new. A missing or invalid email answers `422` and stores nothing. |
| `first_name`, `last_name` | Fills the name only when the contact has none. A known contact is never renamed from a request. |
| A key equal to a custom field **slug** | Writes the value onto the contact and **overwrites** what was there. A value of the wrong type, or a field the hub marks read-only, answers `422` with `source.pointer` set to `/<key>` and stores nothing. |
| Any other key | Not stored on the contact. It travels with the event as the payload, and the response lists it under `unmatched_fields`. |

Mapping happens in Zapier or Make: name the keys after your custom field slugs. A text field takes a string, a number field a number, a yes/no field `true` or `false`, a date field `YYYY-MM-DD`, and a single or multiple choice field the option id (an array of ids for multiple). Because the values are on the contact, a later `branch` step, an entry filter or a segment can use them.

## Avoid enrolling someone twice

Zapier and Make retry on errors. Send an `Idempotency-Key` header with the id of the source record, for example the Typeform response id. Mio uses it per webhook: a repeat of the same key answers `202` with the original id and writes nothing, even if the body changed.

## What the answers mean

| Status | Meaning |
| - | - |
| `202` | Received (also for a repeated `Idempotency-Key`: same `id`, nothing written). The body is an `inbound_webhook_receipts` resource whose `id` is the event id. This does **not** mean the contact was enrolled. A contact who is banned from the hub, or whose team link was removed, also gets `202` and starts nothing, so a leaked secret cannot be used to look people up. |
| `404` | The `Authorization` header is missing or wrong, the secret belongs to another webhook, or the webhook is unknown, switched off or deleted. One answer for all of them. A secret placed in the URL instead of the header also answers `404`. |
| `413` | The body is over 64 KiB. |
| `422` | The body is not a JSON object, the email is missing or invalid, or a mapped field value is wrong. |
| `429` | Too many requests (60 per minute per secret, 300 per minute per IP address, and a per-email limit). Retry later. |

## If the secret leaks

The secret is the credential: anyone who holds it, together with the webhook's URL, can create contacts in that hub and start its automations. The URL alone does nothing. If the secret appears somewhere it should not:

* **Rotate it.** `POST .../inbound-webhooks/{id}/rotate` (or `rotate_inbound_webhook`) returns a new secret once, and the old one stops working at once. The URL stays the same. Update the `Authorization` header in Zapier or Make.
* **Or switch it off.** `PATCH` the webhook with `enabled: false`. A switched-off webhook answers `404`.
* `token_prefix` is the first 12 characters of the secret. It is safe to show and lets you tell your webhooks apart.

## Admin API

```text theme={null}
GET    /api/v1/teams/{team_id}/hubs/{hub_id}/inbound-webhooks              list
POST   /api/v1/teams/{team_id}/hubs/{hub_id}/inbound-webhooks              create (secret shown once)
PATCH  /api/v1/teams/{team_id}/hubs/{hub_id}/inbound-webhooks/{id}         rename, enable or disable
POST   /api/v1/teams/{team_id}/hubs/{hub_id}/inbound-webhooks/{id}/rotate  new secret (shown once)
DELETE /api/v1/teams/{team_id}/hubs/{hub_id}/inbound-webhooks/{id}         delete
```

A hub can have 20 live webhooks. The resource type is `inbound_webhooks`.

> [!NOTE]
>
> A sequence (drip campaign) cannot start on this event. Use an automation with an inbound webhook trigger and an `enroll_in_sequence` step.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.