> Deprecated:
> The creation of new marketing activity app extensions is deprecated. Only existing extensions can still be managed. If you have an existing marketing activity app extension and would like to continue to manage it, please migrate it to CLI following the [migration guide](/docs/apps/build/marketing-analytics/marketing-activities/migrate-extensions).

Before your app can receive communication from Shopify through a marketing activity app extension, you need to host a series of standardized API endpoints on your app's primary domain. These endpoints are called when your app extension is rendered and when there's a related action requested from your app.

## Endpoint requirements

The requirements for the marketing activity app endpoints are as follows:

<table>
<tr>
<th>rule/concern</th>
<th>type/requirement</th>
</tr>
<tr>
<td>API format</td>
<td>REST</td>
</tr>
<Tr>
<td>Content type</td>
<td>JSON</td>
</tr>
<tr>
<td>Security mechanism</td>
<td><a href="/docs/apps/build/webhooks">HMAC/Signed requests (same as webhooks)</a></td>
</tr>
<tr>
<td>Protocol</td>
<td>HTTPS (app domain requires valid SSL certificate)</td>
</tr>
</table>

> Note:
> All endpoints must respond within three seconds, otherwise Shopify will timeout the call and return an error to the user.

## Base endpoint

Your app must host a base URL that Shopify will use to make requests for all marketing activity endpoints. You can specify a custom API subpath for marketing activities using the extension configuration. If your app has multiple extensions, then you can also choose to share a single api subpath for all.

The following example shows a typical endpoint:

```
https://app-url.com/api/marketing_activities
```

The URL includes:

1. An HTTPS protocol (the app must have a valid SSL certificate)
2. The base application URL (configured for your app)
3. A fixed API path (configured in the marketing activity extension)

The base endpoint for marketing activity requests is:

```
https://#{base_app_url}/#{api_path}
```

## Preload a marketing activity form

When a user interacts with a marketing activity extension, the first thing that Shopify does is retrieve the form configuration from the app extensions framework. The form configuration is a schema that lists all form fields and other UI components that should be rendered in the UI.

### HTTP request

```
POST "#{base_endpoint}/preload_form_data"
```

Expected HTTP status response:

* 200 - OK
* 412 - Precondition Failed (if the app can't create the activity for some reason, such as the user hasn't finished setting up the app)

### JSON input

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en"
}
```

<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The shop domain requesting to preload the form. Apps hold the shop domain in their database as a unique record, and use it to fetch specific data for each user or shop.</td>
</tr>
<Tr>
<td><code>shop_id</code></td>
<td>The shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the user who is currently logged in to the Shopify admin. You can use the ID to link the authenticated user with an ad account instead of a broad ad account shared with many different users for a given shop.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current session locale (string), which is the language being used in the current session by the app user.</code>
</tr>
<Tr>
<td><code>marketing_activity_id</code> (optional)</td>
<td>The existing marketing activity GID. This is used only when editing a marketing activity. To learn more, refer to <a href="#edit-a-marketing-activity"><em>Edit a marketing activity</em></a>).</td>
</tr>
</table>

### JSON output

You can include a field in the response if you want to change a property of the marketing activity. If nothing is returned, then whatever is configured statically for that field (inside the app extension) is what will be rendered to the user.

Here's an example of an empty response:

```json
{
  "form_data": {}
}
```

In this example, an app adds more attributes to `average_daily_budget` field:

```json
{
  "form_data": {
    "average_daily_budget": {
      "currency": "CAD",
      "help_text": "Your shop will perform best with a $20 daily budget.",
      "min_amount": "13.00"
    }
  }
}
```

Since these properties will be merged into the current state of `average_daily_budget`, if there was a predefined `help_text`, then the app would overwrite with `Your shop will perform best with a $20 daily budget.`. This would be true also for other fields present in that response. The state of the `amount` field is preserved since the app didn't mention it in the response.

If an app wants to clear the `amount` field, then it needs to provide an empty value in the response:

```json
{
  "form_data": {
    "average_daily_budget": {
      "amount": "",
      "currency": "CAD",
      "help_text": "Your shop will perform best with a $20 daily budget.",
      "min_amount": "13.00"
    }
  }
}
```

### FAQ

**Which properties are available for each field? What is the contract for each component?**

To learn more about how to configure the components, refer to the [Marketing activities components reference](/docs/api/marketing-activities/components).

**Is it possible for an app to add a new field in the UI dynamically?**

No. Apps must always respect the predefined fields from the static definition of the form (as it was created from the Partners Dashboard). However, an app can show, hide, or disable UI fields using the pattern above.

### Adding marketing activity form banners

In the preload call, you can return a list of banners to display on top of the form in addition to returning the preloaded form configuration and values. These app banners are useful for providing users with educational information separate from the error messages in the marketing activity form.

There are a few different types of app banners available. Refer to the entry for `type` in the **App banner properties** table below. To see how each one looks, refer to the [Banner](https://polaris.shopify.com/components/feedback-indicators/banner) documentation in Shopify's Polaris design system.

> Note:
> A maximum of 2 banners can be returned per preload call.

#### Preload call with app banners response JSON

```json
 "form_data": {
   "average_daily_budget": {
     "value": 35,
     "description": "in CAD",
     "minimum": 13
   }
 },
 "app_banners":[
   {
     "type": "info",
     "title": "Your Dynamic Product Ad might not be effective. Please refer to this [help](https://www.teststore.myshopify.com/extension/create)",
     "description": "Please create a carousel ad instead.",
     "primary_cta": {
       "label": "Create a carousel Ad",
       "url": "https://www.teststore.myshopify.com/extension/create"
     },
     "secondary_cta": {
       "label": "Find out more",
       "url": "https://www.teststore.myshopify.com/facebook_ads/find_out_more"
     }
   }
 ]
 ```

#### App banner properties

<table>
<tr>
<td><code>type</code> (required)</td>
<td>The type of the banner. Valid values: <code>default</code>, <code>info</code>, <code>warning</code>, <code>critical</code>.</td>
</tr>
<Tr>
<td><code>title</code> (required)</td>
<td>The title of the banner.</td>
</tr>
<tr>
<td><code>description</code> (required)</td>
<td>The description that appears in the banner.</td>
</tr>
<tr>
<td><code>primary_cta</code> (optional)</td>
<td>The primary call to action button in the banner. Includes the following properties:
  <ul>
    <li><code>label</code> - The label of the call to action button.</li>
    <li><code>url</code> - The link of the call to action button.</li>
  </ul>
</td>
</tr>
<Tr>
<td><code>secondary_cta</code> (optional)</td>
<td>The secondary call to action button in the banner. Requires that <code>primary_cta</code> is provided. Accepts the same properties as <code>primary_cta</code>.</td>
</tr>
</table>


#### App banner FAQ

**What if I don't need to display any app banners in the form?**

In the preload response, you can return `nil` or an empty array instead of returning the hash with the `app_banners` key.

**Is markdown supported in the app banner?**

Only markdown formatting for links is currently supported. The link urls can be either absolute or relative.

**Are dismissible app banners supported?**

No, they aren't currently supported.

## Preview a marketing activity

Most marketing activities let the user preview them before they are actually created. For example, when a user creates a Facebook campaign, they can preview it after choosing different options, content, types, some descriptions, and how much they want to spend.

To preview a marketing activity, the app receives the marketing activity from the form and then returns a preview URL. This preview URL is embedded in Shopify in an iframe and displayed to the user.

Previewing a marketing activity is a good way to perform validations and give early feedback to the user. It's a good idea to perform validations before generating the preview. If there are validation errors, then return them in the response.

### HTTP request

```
POST "#{base_endpoint}/preview"
```

Expected HTTP status responses:

* 200 - OK (if the preview was generated and no validation errors were found)
* 422 - Unprocessable Entity (if there are validation errors)

### JSON input

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/4",
  "preview_types": ["desktop", "mobile"],
  "properties": {
    "average_daily_budget": "13.00",
    "quantity": 2
  }
}
```
<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<Tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<Tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<Tr>
<td><code>marketing_activity_id</code> (optional)</td>
<td>The ID of the marketing activity. This is passed only if the user is previewing a marketing activity that already exists.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>preview_types</code></td>
<td>An array of preview types to request. Default: <code>["desktop", "mobile"]</code>.</td>
</tr>
<Tr>
<td><code>properties</code></td>
<td>All input field values collected from the user.
</td>
</tr>
</table>

### JSON output

In this example, the app was able to generate a preview (status code 200):

```json
{
   "desktop": {
     "preview_url": "https://app-url.com/previews/98564321",
     "content_type": "text/html",
     "width": 1000,
     "height": 800
   },
   "mobile": {
     "preview_url": "https://app-url.com/previews/98564322",
     "content_type": "text/html",
     "width": 360,
     "height": 800
   }
}
```

<table>
<tr>
<td><code>preview_type</code></td>
<td>The corresponding <code>preview_type</code> key corresponding to what was passed in the JSON request.
</tr>
<Tr>
<td><code>preview_url</code> (required when 200)</td>
<td>The URL with the preview HTML or image. Shopify embeds this preview inside an iframe.</td>
</tr>
<tr>
<td><code>content_type</code> (required when 200)</td>
<td>The mime type for the preview. Available options:
<ul>
<li>text/html</li>
<li>image/jpeg</li>
<li>image/png</li>
</td>
</tr>
<td><code>width</code> (required when 200)</td>
<td>The width of the preview (Integer). Shopify uses this to adjust the size of the iframe.
</td>
</tr>
<tr>
<td><code>height</code> (required when 200)</td>
<td>The height of the preview (Integer). Shopify uses this to adjust the size of the iframe.</td>
</tr>
</table>

If the app was unable to generate a preview due to validation errors (status code 422), it can respond with an error message that's displayed to the user within the preview frame. The JSON structure of the errors is the same as that for updating the status of the marketing activity to [`FAILED`](/docs/api/marketing-activities/statuses#failed-status).

### FAQ

**Does the preview URL support HTML?**

Yes.

**Are asynchronous previews supported?**

No. Apps should provide synchronous preview endpoints only.

If your app requires more than 10 seconds to generate a preview, then as a workaround you can provide the preview endpoint quickly as HTML and generate the preview when the URL gets hit.

**I have all the information I need to generate the preview from the `properties` in the request. Do I need to use `marketing_activity_id`?**

The `marketing_activity_id` is provided in the request when previewing an existing marketing activity. You can use it to generate the preview, but it isn't required.

## Create a marketing activity

This endpoint is called when a user tries to create a marketing activity in the marketing section. The marketing activity create REST end point must schedule an asynchronous job to create a marketing activity in the marketing platform. This endpoint must validate the form and schedule an update to the marketing activity object created by Shopify. In the job, the first update to the marketing activity object must include the UTM parameters, and if it is a paid activity, also the budget fields.

There must be a 1-to-1 relationship between a Shopify marketing activity and the activity that your app creates on the marketing platform. When your app creates a marketing activity on the platform, verify the uniqueness of the Shopify marketing activity ID. For example, if a network issue causes the same marketing activity ID to be provided to the create endpoint twice, then your app should create only one marketing activity.

> Note:
All endpoints must respond within three seconds. For a more responsive user experience, update the marketing activity’s information asynchronously in a job outside of this call.

The workflow for creating a marketing activity includes the following steps:

1. The user fills out the marketing activity form, and clicks on the **Publish** button.

2. Shopify creates the marketing activity in advance and hits the app's create marketing activity REST endpoint.

3. The app should do the following:
    1. Validate the form. If it's valid, then respond with `200 OK` and empty JSON response. If it's invalid, then respond with the correct HTTP error code and the JSON error hash as described in [previewing](#preview-a-marketing-activity) section.
    2. Schedule an asynchronous job to set the UTM parameter and budget of the marketing activity using [MarketingActivityUpdate](/docs/api/admin-graphql/latest/mutations/marketingactivityupdate).
    3. Schedule an asynchronous job to publish the marketing activity to the platform (such as Facebook), then invoke [MarketingActivityUpdate](/docs/api/admin-graphql/latest/mutations/marketingactivityupdate) to update the status.

4. If the app responds with `200 OK`, then Shopify responds back to the app with the created marketing activity in a **Pending** state.

5. If the app responds with an HTTP error code in the 400s or 500s, then Shopify cleans up the marketing activity it created in advance.

6. After the app has published the marketing activity to the platform, it should do the following:
    1. If it's successful, then call [MarketingActivityUpdate](/docs/api/admin-graphql/latest/mutations/marketingactivityupdate) to mark the activity either as `ACTIVE` if it's ongoing, or as `INACTIVE` if it's completed.
    2. If it's unsuccessful, then call [MarketingActivityUpdate](/docs/api/admin-graphql/latest/mutations/marketingactivityupdate) to mark the activity as `FAILED`, and pass the cause of the error so that it can be displayed on the **Marketing** page in the Shopify admin.


### Sequence diagram of marketing activity creation flow

![Sequence diagram of marketing activity creation flow.](/assets/api/embedded-apps/app-extensions/marketing_activity_create_flow.png)

### HTTP request

```
POST "#{base_endpoint}"
```

Expected HTTP status responses:

* 200 - OK (if the activity was created and no validation errors were found)
* 412 - Precondition failed (if the user hasn't finished setting up the app)
* 422 - Unprocessable Entity (if there are validation errors)

### JSON input

The JSON input for creating a marketing activity is almost the same as the input for [previewing](#preview-a-marketing-activity) a marketing activity:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_title": "Apparel promotion",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34435",
  "context": "",
  "properties": {
    "average_daily_budget": "150.00",
    "quantity": 2
  }
}
```

<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<tr>
<td><code>marketing_activity_title</code></td>
<td>The title of the marketing activity (string).</td>
</tr>
<tr>
<td><code>marketing_activity_id</code></td>
<td>The GID of the marketing activity that was created by Shopify.</td>
</tr>
<tr>
<td><code>context</code>(deprecated)</td>
<td>An encoded string that Shopify uses to identify some marketing activity properties. Note: This context needs to be relayed to Shopify if you are using the deprecated GraphQL MarketingActivityCreate endpoint.</td>
</tr>
</tr>
<td><code>properties</code></td>
<td>All input field values collected from the user.</td>
</tr>
</table>

### JSON output

If the app was able to create the marketing activity (status code 200), we expect an empty JSON response.

```json
{}
```

<table>

<tr>
<td><code>errors</code> (required when 422)</td>
<td>The app can respond with validation errors to be displayed to users if creation has failed. The error response structure is  the same as that for updating the status of the marketing activity to <a href="/docs/api/marketing-activities/statuses#failed-status"><code>FAILED</code></a>.</td>  </tr>
</table>

### FAQ

**Why does Shopify create the marketing activity in advance?**

This simplifies the process of creating a marketing activity by preventing the app from having to make an extra call to Shopify. It also reduces the chance of timeouts for this REST endpoint.

**Why should we asynchronously update the marketing activity?**

The marketing activity creation flow will be more responsive. It will take less time to respond to the initial call to the App.

**What is the initial status of the marketing activity?**

The initial status is **PENDING**. In the App's asynchronous job to update the marketing activity object, it is free to update to other status such as **ACTIVE** or **FAILED** or continue keep the status as **PENDING**.

**Why do I need to update the marketing activity UTM parameters?**

Shopify needs UTM parameters in order to display the engagement and the report for the ad. This is **required** for all marketing tactics except the storefront app tactic. The UTM parameter must be specified the first time the marketing activity is updated.

**Do apps need to call both the marketing activity endpoints and the MarketingEvent API?**

No. Apps that create marketing activities through the new marketing section will use only the marketing activity endpoints.

**Will I lose old marketing events from my app?**

No. Shopify will backfill all existing marketing events into marketing activities. Each marketing event will have a corresponding marketing activity, and any changes to either API will be reflected in both entities.

## Edit a marketing activity

In some cases, the user is allowed to change some attributes of an existing marketing activity. For example, some social media apps let the user change the budget of an activity after it's been created. Some other apps have more flexibility, and let the user update additional fields.

This can be achieved by using the `preload_form_data` endpoint. For more information, refer to [preload a marketing activity form](#preload-a-marketing-activity-form)).

In this example, Shopify sends the `marketing_activity_id` in the payload:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34526"
}
```

The app must make sure that it has that marketing activity persisted in their database and respond accordingly, setting up the form fields as expected:

```json
{
  "form_data": {
    "average_daily_budget": {
      "amount": "1000.00",
      "currency": "CAD",
      "help_text": "Your shop will perform best with a $20 daily budget.",
      "min_amount": "13.00"
    },
    "quantity": {
      "disabled": true,
      "value": 2
    },
    "ad_title": {
      "disabled": true,
      "value": "Welcome to John's apparel store."
    }
  }
}
```

## Update a marketing activity

This is the continuation of the [previous use case](#edit-a-marketing-activity). After all changes were made, the user submits the form. This action is similar to inline marketing activity creation.

### HTTP request

```
PATCH "#{base_endpoint}"
```

Expected HTTP status responses:

* 200 - OK (if the activity was synchronously updated and no validation errors were found)
* 202 - Accepted (if the activity was scheduled to be asynchronously updated)
* 412 - Precondition Failed (if the user hasn't finished setting up the app)
* 422 - Unprocessable Entity (if there are validation errors)

After receiving a 200 response, Shopify updates the marketing activity's status to `ACTIVE`.

### JSON input

The input to update a marketing activity is the same as inline marketing activity creation with the marketing activity GID:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34435",
  "marketing_activity_title": "Apparel promotion",
  "properties": {
    "average_daily_budget": 150.00,
    "quantity": 2
  }
}
```
<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>marketing_activity_id</code></td>
<td>The GID of the marketing activity being updated.</td>
</tr>
<tr>
<td><code>marketing_activity_title</code></td>
<td>The title of the marketing activity (string).</td>
</tr>
<tr>
<td><code>properties</code></td>
<td>All input field values.</td>
</tr>
</table>

### JSON output

If your app is able to update the marketing activity synchronously (status code 200), then Shopify expects an empty body in the response.

If your app has started to update the marketing activity asynchronously, then Shopify expects the status code 202 accepted and an empty body in the response.

However, if your app detects validation errors, it can respond with the status code 422 and the related errors. The error response structure is the same as that for updating the status of the marketing activity to [`FAILED`](/docs/api/marketing-activities/statuses#failed-status).

## Pause a marketing activity

You can pause a marketing activity that is in an active state. You can use the `pause` endpoint to pause an active marketing activity either synchronously or asynchronously.

### HTTP request

```
PATCH "#{base_endpoint}/pause"
```

Expected HTTP status responses:

* 200 - OK (if the activity was synchronously paused)
* 202 - Accepted (if the activity has started asynchronous pause)
* 412 - Precondition Failed (if the user hasn't finished setting up the app)

After receiving a 200 response, Shopify updates the marketing activity's status to `PAUSED`.

### JSON input

The input to update a marketing activity is the same as inline marketing activity creation with the marketing activity GID:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34435",
}
```
<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>marketing_activity_id</code></td>
<td>The GID of the marketing activity being updated.</td>
</tr>
</table>

### JSON output

If your app is able to pause the marketing activity synchronously (status code 200), then Shopify expects an empty body in the response.

If your app has started to pause the marketing activity asynchronously, then Shopify expects the status code 202 accepted and an empty body in the response.

## Resume a marketing activity

You can resume marketing activities that are in a paused state. You can use the `resume` endpoint to resume a paused marketing activity either synchronously or asynchronously.

### HTTP request

```
PATCH "#{base_endpoint}/resume"
```

Expected HTTP status responses:

* 200 - OK (if the activity was synchronously resumed)
* 202 - Accepted (if the activity was asynchronously resumed)
* 412 - Precondition Failed (if the user hasn't finished setting up the app)

After receiving a 200 response, Shopify updates the marketing activity's status to `ACTIVE`.

### JSON input

The input to update a marketing activity is the same as inline marketing activity creation with the marketing activity GID:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34435",
}
```
<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>marketing_activity_id</code></td>
<td>The GID of the marketing activity being updated.</td>
</tr>
</table>

### JSON output

If your app is able to resume the marketing activity synchronously (status code 200), then Shopify expects an empty body in the response.

If your app has started to resume the marketing activity asynchronously, then Shopify expects the status code 202 accepted and an empty body in the response.

## Republish a marketing activity

If a marketing activity creation fails, then its state changes to failed. To re-publish it, the user might need to modify a few of the activity's properties. You can use the `republish` endpoint to achieve this. The related request and response bodies are the same as those used to [update a marketing activity](#update-a-marketing-activity).

### HTTP request

```
POST "#{base_endpoint}/republish"
```

Expected HTTP status responses:

* 200 - OK (if the activity was synchronously republished and no validation errors were found)
* 202 - Accepted (if the activity has started asynchronous republish)
* 412 - Precondition Failed (if the user hasn't finished setting up the app)
* 422 - Unprocessable Entity (if there are validation errors)

After receiving a 200 response, Shopify updates the marketing activity's status to `ACTIVE`.

### JSON input

The input to republish a marketing activity is the same as inline marketing activity creation with the marketing activity GID:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34435",
  "marketing_activity_title": "Apparel promotion",
  "properties": {
    "average_daily_budget": "150.00",
    "quantity": 2
  }
}
```
<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>marketing_activity_id</code></td>
<td>The GID of the marketing activity being updated.</td>
</tr>
<tr>
<td><code>marketing_activity_title</code></td>
<td>The title of the marketing activity (string).</td>
</tr>
<tr>
<td><code>properties</code></td>
<td>All input field values.</td>
</tr>
</table>

### JSON output

If your app is able to republish the marketing activity synchronously (status code 200), then Shopify expects an empty body in the response.

If your app has started to republish the marketing activity asynchronously, then Shopify expects the status code 202 accepted and an empty body in the response.

However, if your app detects validation errors, it can respond with the status code 422 and the related errors. The error response structure is the same as that for updating the status of the marketing activity to [`FAILED`](/docs/api/marketing-activities/statuses#failed-status).

## Delete a marketing activity

You can delete a marketing activity. You can use the `delete` endpoint to delete a marketing activity either synchronously or asynchronously.

### HTTP request

```
PATCH "#{base_endpoint}/delete"
```

Expected HTTP status responses:

* 200 - OK (if the activity was synchronously deleted)
* 202 - Accepted (if the activity was asynchronously deleted)
* 412 - Precondition Failed (if the user hasn't finished setting up the app)

After receiving a 200 response, Shopify updates the marketing activity's status to `DELETED`.

### JSON input

The input to delete a marketing activity is the same as inline marketing activity creation with the marketing activity GID:

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "marketing_activity_id": "gid://shopify/MarketingActivity/34435",
}
```

<table>
<tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>marketing_activity_id</code></td>
<td>The GID of the marketing activity being deleted.</td>
</tr>
</table>

### JSON output

If your app is able to delete the marketing activity synchronously (status code 200), then Shopify expects an empty body in the response.

If your app has started to delete the marketing activity asynchronously, then Shopify expects the status code 202 accepted and an empty body in the response.

## Dynamic standalone fields

Some UI fields, such as type-ahead fields, require more comprehensive integration with an app to provide dynamic data from the backend.

In this example, the app wants to let the user partially type some interests and then provide a list of the available matching interests:

![An example of the Audience section of the marketing activity form.](/assets/api/embedded-apps/app-extensions/audience-example.png)

With that approach, the app directs the user towards a valid selection instead of using an open text field where the user can enter input that risks causing validation errors.

### HTTP request

```
POST "#{base_endpoint}/load_field/#{field_name}"
```
Expected HTTP status responses:

* 200 - OK

### JSON input

```json
{
  "shopify_domain": "example.myshopify.com",
  "shop_id": "gid://shopify/Shop/1111111",
  "user_id": 1,
  "locale": "en",
  "field_name": "interests",
  "value": "sports"
}
```

<table>
<Tr>
<td><code>shopify_domain</code></td>
<td>The associated shop domain.</td>
</tr>
<Tr>
<td><code>shop_id</code></td>
<td>The associated shop GID.</td>
</tr>
<Tr>
<td><code>user_id</code></td>
<td>The ID of the authenticated user.</td>
</tr>
<Tr>
<td><code>locale</code></td>
<td>The current locale (string).</td>
</tr>
<tr>
<td><code>field_name</code></td>
<td>The name of the field, specified when you create the form.</td>
</tr>
<Tr>
<td><code>value</code></td>
<td>The current value for the given field.</td>
</tr>
</table>

### JSON output

Similar to other examples above, the app will customize the field properties but in this case it can manipulate only one field:

```json
{
  "field_data": {
    "options": [
      {"label": "Sports", "value": "sports"},
      {"label": "Movies", "value": "movies"},
      {"label": "Music", "value": "music"}
    ]
  }
}
```

### FAQ

**Why does the endpoint include the field name? Why not have a single endpoint and send the field name in the payload only?**

By having different endpoints for each field, you can help split the required code into smaller sections.

**Why is the field name in both the payload and the URI?**

Having more data in the payload can help create different HMACs for each call. This improves the security of our communications by having more random data to influence the HMAC.

Apps can use either the field name from the URI or the payload (both have the same effect).

## Error feedback

This endpoint is called to report back to the app if the JSON output for any of the previously described endpoints does not conform to the expected format. For example, if the app response to the preload endpoint contains an invalid data type, a missing key, or any unexpected value, then the error endpoint reports that back to the app.

Example invalid JSON output on preload:

```json
{
  "form_data": {
    "ad_title": {
      "random_prop": "random",
      "min_length": -3
    },
    "average_daily_budget": {
      "help_text": "Your shop will perform best with a $20 daily budget.",
      "min_amount": "13.00"
    }
  }
}
```

Corresponding error message which will be reported back:

```json
[
  {
    "ad_title": [
      { "#": "\"random_prop\" is not a permitted key." },
      { "#/min_length": "-3 must be greater than or equal to 0., -3 is not a null." }
    ],
    "average_daily_budget": [
      { "#": "\"currency\" wasn't supplied." }
    ]
  }
]
```

### HTTP request

```
POST "#{base_endpoint}/errors"
```
Expected HTTP status responses:

* 200 - OK

### JSON input

```json
{
  "request_id": "example-request-id",
  "message": "[{\"ad_title\":[{\"#\\/min_length\":\"-3 must be greater than or equal to 0., -3 is not a null.\"}]}]",
}
```

<table>
<Tr>
<td><code>request_id</code></td>
<td>The ID of the request whose response caused a validation failure.</td>
</tr>
<Tr>
<td><code>message</code></td>
<td>A JSON serialized string describing the errors with the app response.</td>
</tr>
</table>

### JSON output

A JSON body is not required in the response.