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

# Connect Customer.io to Default by webhook

> Customer.io connects to Default by webhook, not natively, so Customer.io webhooks start workflows through the Incoming Webhook trigger and the Send to Webhook node updates Customer.io from Default.

Customer.io connects to Default by webhook. Default has no native Customer.io integration: Customer.io
has no card on the **Integrations** page. Customer.io starts Default workflows by sending webhooks to a
workflow's **Incoming Webhook** trigger, and Default updates Customer.io with the **Send to Webhook**
node.

## How Customer.io data flows to and from Default

| Direction | How it works | Default side |
| - | - | - |
| Customer.io to Default | A Customer.io webhook sends a JSON `POST` to a Default webhook URL, for example when a person reaches a step in a campaign. | [**Incoming Webhook** trigger](/workflows/triggers#incoming-webhook), authenticated with the [webhook secret](/settings/webhook-secret) |
| Default to Customer.io | A workflow calls Customer.io's API, for example to update a person's attributes after a meeting is booked. | [**Send to Webhook** node](/workflows/steps-actions#send-to-webhook) |

## Start a Default workflow from Customer.io

<Steps>
  <Step title="Add the Incoming Webhook trigger">
    In **Workflows**, create a workflow and add the **Incoming Webhook** trigger. Under
    **Connected Webhook**, select **Create new webhook**, or choose an existing webhook.
  </Step>

  <Step title="Copy the URL and the secret">
    Copy the **Ingestion URL**. Reveal and copy the **Bearer secret**. It is your workspace's
    [webhook secret](/settings/webhook-secret), shared by every webhook in the workspace.
  </Step>

  <Step title="Set up the webhook in Customer.io">
    In Customer.io, set up a webhook that sends a `POST` with a JSON body to the **Ingestion URL**, with
    the header `Authorization: Bearer <secret>`. Include the person's email in the body.
  </Step>

  <Step title="Capture a sample">
    Select **Listen for test event**, then send 1 test webhook from Customer.io. For the next 5 minutes,
    Default saves the first request it receives as the **Captured payload** and does not start the
    workflow with it. You can also select **Paste a sample**, paste an example body, and select
    **Save sample**.
  </Step>

  <Step title="Map the person">
    Under **Identity mapping**, set **Person email** to the field that holds the email.
  </Step>

  <Step title="Build, test, and publish">
    Add the nodes that act on the person, for example **Match Record** and a routing node. Type `{{` to
    insert values from the captured payload. Select **Test**, then **Run Test**, to try it. Select
    **Publish**, then check that the status next to the
    [deployment switch](/workflows#the-deployment-switch) reads **Live**. A new workflow goes live when you first
    publish it. If the status reads **Paused**, turn the switch on. Customer.io webhooks now start
    the workflow.
  </Step>
</Steps>

A body like this works as a sample:

```json theme={null}
{
  "email": "jane@acme.com",
  "campaign": "Trial nurture",
  "action": "Clicked book a demo"
}
```

A person can trigger the same Customer.io webhook more than once. Before the workflow routes or creates
records, check for an existing CRM record with **Match Record**, and route only on the **No Match**
branch. See [CRM nodes](/workflows/steps-crm#match-record).

## Webhook request rules for Customer.io

* Method: `POST`, with a JSON body up to 1 MB. A larger body gets a `413` response.
* Validation: malformed JSON gets a `400`. So does a request whose mapped **Person email** field holds
  text that is not a valid email address. An empty or non-text value is not checked, and the run
  starts with no person.
* Authentication: `Authorization: Bearer <webhook secret>`. A missing or wrong secret gets a `401`.
* Runs: each request starts 1 run of every published, enabled workflow that uses the webhook.
* Paused webhook: turning off the webhook's **Active** switch in the trigger makes Default reject
  requests with a `410`.
* Response: an accepted request gets status `200` with `"accepted": true`. Default also answers `200`
  when no published, enabled workflow uses the webhook, so a `200` alone does not mean a run started.

## Update Customer.io from Default

Use **Send to Webhook** to call Customer.io's API, for example to set a `meeting_booked` attribute on
the person so your Customer.io campaigns can react.

<Steps>
  <Step title="Choose the trigger">
    Start the workflow with the trigger that matches the moment, for example **Meeting Status** with
    **Meeting statuses** set to **Booked**. See [Triggers](/workflows/triggers#meeting-status).
  </Step>

  <Step title="Point Send to Webhook at Customer.io">
    Add **Send to Webhook**. Set **Request Type** and **Request URL** to the Customer.io API endpoint
    you want to call, from Customer.io's API documentation.
  </Step>

  <Step title="Set the authorization">
    Under **Authorization**, choose what that endpoint expects: **API Key**, **Token**, or **Basic**.
  </Step>

  <Step title="Build the body and publish">
    Build the **Body** under **Fields** or **JSON**. Type `{{` to insert values, such as the lead's
    email. Publish the workflow and check that its status reads **Live**. If it reads **Paused**,
    turn on the [deployment switch](/workflows#the-deployment-switch). Each booked meeting now sends the
    request to Customer.io.
  </Step>
</Steps>

Testing is not available yet for workflows that start from a **Meeting Status** trigger. Default stops
a request after 30 seconds and does not follow redirects. See
[Send to Webhook](/workflows/steps-actions#send-to-webhook).

## What Default does not support with Customer.io

* A native Customer.io integration, or a Customer.io card on the **Integrations** page.
* Reading Customer.io segments, campaigns, or people on its own. Customer.io has to send the data.
* Webhooks without an `Authorization: Bearer` header. Default rejects them with a `401`.

Related: [Default integrations](https://www.default.com/integrations)


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