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

# Adding Webhook-Powered Content to Campaigns

> Pull in live external data—product catalogs, showtimes, personalized offers—and render it directly in your email campaigns using webhook-powered content.

Sometimes the content you need in an email lives outside Maestra Platform—a showtime catalog, live inventory, or personalized offers from your own service. And it's not a single field: it's arrays of data you need to loop through and render into the email layout. Webhook-powered content lets you do that directly from the campaign template, no custom integration required.

This guide walks you through the setup.

***

## Step 1. Create an integration

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-14.09.57.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=de3df9958716b2eab540061fed6f51f1" alt="Screenshot 2026 05 29 At 14 09 57" width="2936" height="756" data-path="images/Screenshot-2026-05-29-at-14.09.57.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-14.12.07.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=4fa596f9c77e13db33b59dc55daaca43" alt="Screenshot 2026 05 29 At 14 12 07" width="2916" height="1462" data-path="images/Screenshot-2026-05-29-at-14.12.07.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-14.22.37.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=958188356c0d63bc792ad85341aba55d" alt="Screenshot 2026 05 29 At 14 22 37" width="2912" height="340" data-path="images/Screenshot-2026-05-29-at-14.22.37.png" />
</Frame>

Go to **Integrations → Add integration**, pick the **Webhook Integration** preset, and fill in:

* **URL** — the base URL of your service. You can specify just the root and add path-specific parts in each webhook separately.
* **Headers** — `Authorization`, `Content-Type`, and anything else your API requires.
* **Request rate limit per second** — set to **Not specified** so Maestra doesn't rate-limit outbound sends.

4. Click **Create**

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=7731e5397c6bc00fb982e778ef9df89f" alt="Screenshot 2026" width="2912" height="340" data-path="images/Screenshot-2026.png" />
</Frame>

***

## Step 2. Create a webhook with "Use full response as campaign content"

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-14.36.50.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=d49fd2831b04fc47edb44221006c2c0b" alt="Screenshot 2026 05 29 At 14 36 50" width="2930" height="838" data-path="images/Screenshot-2026-05-29-at-14.36.50.png" />
</Frame>

Inside the integration, click **Create** to add a webhook. Fill in the name, system name, method, and path.

In the **Response settings** block, select **"Use full response as campaign content"**.

<Accordion title="How this differs from the standard webhook mode">
  Webhooks support two modes:

  * **Map specific fields** — the existing behavior. Used for integrations and response checks inside flow scenarios: individual values are pulled from the response by path and saved in a flow session for use in Condition nodes or campaigns as individual data points.
  * **Use full response as campaign content** — the new mode. The entire JSON response becomes available inside the campaign template, where you can iterate it with `for…end for`, branch with `if`, and render content directly in your email block using Dynamic parameters.
</Accordion>

Save the webhook.

<Warning>
  Do **not** use dashes in the webhook system name. Use `camelCase` or `snake_case` instead.
</Warning>

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-15.18.55.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=b8a78fbf3a58707f15d15dfba17857a1" alt="Screenshot 2026 05 29 At 15 18 55" width="2920" height="1352" data-path="images/Screenshot-2026-05-29-at-15.18.55.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-15.22.14.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=c383c767723a2775beee7785934b7cde" alt="Screenshot 2026 05 29 At 15 22 14" width="2106" height="510" data-path="images/Screenshot-2026-05-29-at-15.22.14.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-15.28.13.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=9fbd9d4dbd04af4bb108ddfa3011c30a" alt="Screenshot 2026 05 29 At 15 28 13" width="2918" height="340" data-path="images/Screenshot-2026-05-29-at-15.28.13.png" />
</Frame>

***

## Step 3. Reference the webhook in your campaign

Open a campaign and reference the webhook response using this parameter syntax:

```text theme={null}
ExternalData.YourWebhookSystemName.SpecificJSONNodes
```

```text theme={null}
ExternalData.YourWebhookSystemName
```

After the webhook name, use dot notation to navigate to specific JSON nodes.

### Example: Angel Studios

The Angel API returns a nested response like this:

```json theme={null}
{
  "venues": [
    {
      "name": "Classic Cinemas Fox Lake Theatre",
      "address_text": "115 Towne Centre Lane, Fox Lake, IL",
      "showtimes_by_day": [
        {
          "date": "2026-07-03",
          "showtimes": [
            {
              "local_start_time_friendly": "11:15 AM",
              "ticket_url": "https://www.angel.com/tickets/..."
            }
          ]
        }
      ]
    }
  ]
}
```

In the campaign's HTML block, use nested loops to render the full structure:

```html theme={null}
@{ for venue in ExternalData.AngelWebhookYoungWashingtonLaunchDate.venues }
  <h3>${ venue.name }</h3>
  <div>${ venue.address_text }</div>

  @{ for day in venue.showtimes_by_day }
    <strong>${ day.date }</strong>
    @{ for showtime in day.showtimes }
      <a href="${ showtime.ticket_url }">
        ${ showtime.local_start_time_friendly }
      </a>
    @{ end for }
  @{ end for }
@{ end for }
```

Three levels of nesting—`venues → showtimes_by_day → showtimes`—are iterated with three nested `for…end for` loops. Fields within each object are accessed with dot notation: `venue.name`, `day.date`, `showtime.ticket_url`.

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/Screenshot-2026-05-29-at-15.49.46.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=f5fbbc4bdce577e0299109688170ac05" alt="Screenshot 2026 05 29 At 15 49 46" width="2914" height="1564" data-path="images/Screenshot-2026-05-29-at-15.49.46.png" />
</Frame>

***

## Step 4. Send the campaign

At send time, Maestra Platform calls your endpoint for each recipient, waits for the response, and injects the data into the email before delivery.

<Frame>
  <img src="https://mintcdn.com/maestraio/0dDg46S6N-QQIeVN/images/image-18.png?fit=max&auto=format&n=0dDg46S6N-QQIeVN&q=85&s=0908150c44ad28c3212a7a44477e7b47" alt="Image 18" width="772" height="600" data-path="images/image-18.png" />
</Frame>

***

## What happens if the webhook doesn't respond

If the call to your endpoint fails, the email is **not sent** to that recipient. The rest of the campaign continues normally—only the affected recipients are skipped.

Before skipping, the system retries automatically:

1. **3 attempts** on `429` and `5xx` errors
2. **1-minute pause**
3. **Up to 2 more retry cycles**

A recipient is only skipped if all retry attempts fail.

***

## Debugging

Every webhook call is logged. Go to **Integrations → Webhooks → Webhook logs** to see the full request URL, headers, response body, and HTTP status.

<Frame>
  <img src="https://mintcdn.com/maestraio/ndpW5zVYhGAs-p28/images/Screenshot-2026-05-29-at-16.13.11.png?fit=max&auto=format&n=ndpW5zVYhGAs-p28&q=85&s=43462243955fa352c61e8b3e7a611d25" alt="Screenshot 2026 05 29 At 16 13 11" width="2906" height="620" data-path="images/Screenshot-2026-05-29-at-16.13.11.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/maestraio/ndpW5zVYhGAs-p28/images/Screenshot-2026-05-29-at-16.21.00.png?fit=max&auto=format&n=ndpW5zVYhGAs-p28&q=85&s=15e17506fd6759b2d251d242a16131d5" alt="Screenshot 2026 05 29 At 16 21 00" width="2922" height="702" data-path="images/Screenshot-2026-05-29-at-16.21.00.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/maestraio/ndpW5zVYhGAs-p28/images/Screenshot-2026-05-29-at-16.40.10.png?fit=max&auto=format&n=ndpW5zVYhGAs-p28&q=85&s=5b622c7911221b34b58b55a2cb7347fe" alt="Screenshot 2026 05 29 At 16 40 10" width="2452" height="1298" data-path="images/Screenshot-2026-05-29-at-16.40.10.png" />
</Frame>

If something looks off, that's your starting point.
