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

# Validate Campaign (V5)

> Runs full publish-time validation (`DRAFT_PUBLISH`) on a saved draft without mutating it. Returns `valid: true` if the campaign would pass, or a list of blocking errors if it would not.

All campaign data is read from the saved draft identified by `campaign_id` in the path. There is no channel-specific payload.


<Info>
  You do not need an idempotency key for this endpoint. The validate endpoint is read-only and safe to retry freely.
</Info>

### Validation Modes

The V5 API applies validation in two modes:

| Mode | Triggered by | Strictness |
| :- | :- | :- |
| Lenient | Draft create (`POST /v5/campaigns`) and component patch (`PATCH /v5/campaigns/{id}`) | Partial — individual components are validated in isolation as they are written |
| Full (`DRAFT_PUBLISH`) | `POST /v5/campaigns/{id}/validate` and publish | Strict — all components are validated together as a complete, publish-ready campaign |

Use this endpoint to catch `DRAFT_PUBLISH` failures before triggering a publish.

### Validation Failures

All validation failures are blocking. There is no warning or non-blocking tier. A campaign that fails validation returns `valid: false` with a list of field-level errors. Each error identifies the `field` path and the `issue`.

### Channel-Specific Rules

The following rules are enforced at `DRAFT_PUBLISH` for each channel:

**Push**

* `campaign_content` must be present and include content for all platforms listed in `basic_details.platforms`.
* `template_type` must be valid for the target platform (Android, iOS, Web).
* Platform-specific required fields (for example, `title` and `message` for Android basic templates) must be non-empty.

**Email**

* `connector.connector_type` and `connector.connector_name` must be present and match a connector configured in your workspace.
* `basic_details.from_address` must be set and match a verified sender in the configured connector.
* `basic_details.subscription_category` must be present for `PROMOTIONAL` content type.
* `campaign_content` must include at least one variation with a non-empty `subject` and `html_content`.

### Delivery-Type-Specific Rules

The following rules are enforced at `DRAFT_PUBLISH` based on `campaign_delivery_type`:

| Delivery Type | Additional Requirements |
| :- | :- |
| `ONE_TIME`, `PERIODIC` | `scheduling_details` must be present. |
| `AT_FIXED_TIME` scheduling | `scheduling_details.timezone` must be present. |
| `PERIODIC` | `scheduling_details.periodic_details` must be present with a valid `sending_frequency`. |
| `EVENT_TRIGGERED` | `trigger_condition` must be present with at least one `included_filters` entry. |
| `DEVICE_TRIGGERED` | `trigger_condition` must be present. Trigger delay fields (`trigger_delay_type`, `trigger_delay_value`, `trigger_delay_granularity`) must **not** be set — they are only valid for `EVENT_TRIGGERED`. |
| `BUSINESS_EVENT_TRIGGERED` | `basic_details.business_event` must be present. |
| `LOCATION_TRIGGERED` | `basic_details.geofences` must contain at least one valid geofence entry. |

#### Rate Limits

| Rate Limit Name | Rate Limit |
| :- | :- |
| Validate campaign per second | The total number of validate campaign requests per second per client allowed is 10. |
| Validate campaign per minute | The total number of validate campaign requests per minute per client allowed is 100. |
| Validate campaign per hour | The total number of validate campaign requests per hour per client allowed is 6000. |


## OpenAPI

````yaml /api/campaigns/campaign-draft.yaml post /v5/campaigns/{campaign_id}/validate
openapi: 3.0.3
info:
  title: MoEngage Campaigns API
  version: '2025-11-20'
  description: >
    The Campaigns V5 API manages the draft campaign lifecycle — draft creation,
    incremental updates, validation, test sends, and post-publish management.


    **Note:** Campaign publishing is not yet supported in V5. To publish
    campaigns, use the V1 API (`PATCH
    /core-services/v1/campaigns/{campaign_id}`) in the interim.


    **Supported channels:**

    - Push (Android, iOS, Web)

    - Email


    **Supported delivery types:**

    - ONE_TIME

    - PERIODIC

    - EVENT_TRIGGERED

    - BUSINESS_EVENT_TRIGGERED

    - DEVICE_TRIGGERED (Push only)

    - LOCATION_TRIGGERED (Push only)

    - BROADCAST_LIVE_ACTIVITY (Push iOS only)


    **Campaign lifecycle:**


    1. **Create** - Start a draft with only the required fields (`channel`,
    `campaign_delivery_type`, `created_by`). Add content, audience, and
    scheduling incrementally across subsequent update calls.

    2. **Update** - Patch individual components as you refine the setup. Each
    submitted component is validated in full before the draft is updated.

    3. **Validate** - Check whether a draft would pass publish-time validation
    without committing any changes.

    4. **Test** - Send a test message to specific users from either a saved
    draft or inline content before going live.

    5. **Manage** - Pause, resume, or stop a live campaign. Search your
    workspace and retrieve lightweight metadata across all campaigns.


    **Campaign versioning** is optional per workspace:

    - When enabled, publishing an update to a live campaign creates a new
    document with an incremented `version_number`.

    - `campaign_id` is the stable identifier across all versions; each version
    has its own raw `id` (ObjectId).


    **Authentication header:** The `MOE-APPKEY` request header is optional.
    Basic Auth already carries your Workspace ID as the username, so requests
    authenticate correctly without it.
  contact:
    name: MoEngage Developer Team
    email: support@moengage.com
    url: https://developers.moengage.com
servers:
  - url: https://api-{dc}.moengage.com/
    description: MoEngage Campaigns API Server
    variables:
      dc:
        default: '01'
        description: >-
          Data center (DC) segment in the hostname. Replace `OX` with your
          workspace DC (01–06 or 101). See [Data
          centers](/api/introduction#data-centers).
security:
  - BasicAuth: []
paths:
  /v5/campaigns/{campaign_id}/validate:
    post:
      tags:
        - Create Campaigns
      summary: Validate Campaign (V5)
      description: >
        Runs full publish-time validation (`DRAFT_PUBLISH`) on a saved draft
        without mutating it. Returns `valid: true` if the campaign would pass,
        or a list of blocking errors if it would not.


        All campaign data is read from the saved draft identified by
        `campaign_id` in the path. There is no channel-specific payload.
      operationId: validate_draft_campaign_v5
      parameters:
        - $ref: '#/components/parameters/MOE-APPKEY'
        - $ref: '#/components/parameters/X-MOE-Request-Id'
        - name: campaign_id
          in: path
          required: true
          description: >
            Raw 24-char ObjectId of the campaign to validate. Use the `id` value
            returned in the Create Campaign response.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                request_id:
                  type: string
                  description: >-
                    Optional string (UUID v4 recommended) used to identify this
                    validation call. Unlike other POST endpoints, this field is
                    not required and does not enforce deduplication - the
                    validate endpoint is read-only and safe to retry freely.
                  example: '{{request_id}}'
            examples:
              validate:
                summary: Validate a draft campaign
                value:
                  request_id: '{{request_id}}'
      responses:
        '200':
          description: >-
            Validation result - always returned regardless of whether the
            campaign passes or fails validation.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/V5SuccessEnvelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/V5ValidateResponse'
              examples:
                valid:
                  summary: Campaign passes validation
                  value:
                    response_id: abc-501
                    type: campaign
                    data:
                      valid: true
                invalid:
                  summary: Campaign fails validation
                  value:
                    response_id: abc-501
                    type: campaign
                    data:
                      valid: false
                      errors:
                        - field: >-
                            campaign_content.content.push.android.basic_details.title
                          issue: title is required
                        - field: scheduling_details
                          issue: scheduling_details is required for publish
        '400':
          $ref: '#/components/responses/V5ValidationError'
        '401':
          $ref: '#/components/responses/V5Unauthorized'
        '500':
          $ref: '#/components/responses/V5InternalError'
components:
  parameters:
    MOE-APPKEY:
      name: MOE-APPKEY
      in: header
      required: false
      description: >
        Your MoEngage Workspace ID (App ID). Optional — Basic Auth already
        carries the Workspace ID as the username, so this header is not
        required. Find it in the dashboard at **Settings** > **Account** > **API
        keys**.
      schema:
        type: string
      example: '{{workspace_id}}'
    X-MOE-Request-Id:
      name: X-MOE-Request-Id
      in: header
      required: false
      description: >
        Client-supplied trace ID for tracing. Correlates with `response_id`.
        Supply this header or `request_id` in the body; if both are set, they
        must match.
      schema:
        type: string
  schemas:
    V5SuccessEnvelope:
      type: object
      properties:
        response_id:
          type: string
        type:
          type: string
          example: campaign
        data:
          type: object
    V5ValidateResponse:
      type: object
      description: >
        - When `valid` is `true`, only `valid` is returned.

        - When `valid` is `false`, `errors` lists one or more field-level issues
        found during publish-time validation (`DRAFT_PUBLISH`).
      properties:
        valid:
          type: boolean
          description: >-
            `true` if the campaign passes all publish-time validation checks.
            `false` if one or more checks fail.
          example: false
        errors:
          type: array
          description: >
            Present only when `valid` is `false`. Each item describes a single
            validation failure. Multiple errors can be returned, and more than
            one error can reference the same field.
          items:
            type: object
            properties:
              field:
                type: string
                description: >
                  Dot-separated JSON path to the field that failed validation,
                  relative to the campaign document root (for example,
                  `campaign_content.content.push.android.basic_details.title` or
                  `scheduling_details`).
                example: campaign_content.content.push.android.basic_details.title
              issue:
                type: string
                description: >-
                  Human-readable description of the validation failure for this
                  field. The value is free-form and may vary by channel,
                  delivery type, and component.
                example: title is required
    V5ErrorEnvelope:
      type: object
      properties:
        response_id:
          type: string
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - VALIDATION_FAILED
                - UNPROCESSABLE_ENTITY
                - BAD_REQUEST
                - RATE_LIMITED
                - UNAUTHORIZED
                - INTERNAL_ERROR
                - FORBIDDEN
            message:
              type: string
            target:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  target:
                    type: string
                  message:
                    type: string
            request_id:
              type: string
              description: >
                The `request_id` from the originating request. Use this to
                correlate a failed response back to the specific call that
                triggered it, particularly useful in high-volume or retry
                scenarios.


                In V1, `request_id` appeared inside the `error` object. V5
                preserves this field in the same location.
  responses:
    V5ValidationError:
      description: Request failed schema or component validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/V5ErrorEnvelope'
          examples:
            validation_failed:
              summary: Generic field validation failure
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  request_id: req-push-001
                  details:
                    - target: campaign_delivery_type
                      message: campaign_delivery_type value is required.
            double_opt_in_not_enabled_for_account:
              summary: Double opt-in not enabled for account
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: Double opt-in is not enabled for this account
                  target: basic_details
                  details:
                    - target: basic_details.send_only_double_opt_in_users
                      message: Double opt-in is not enabled for this account
            double_opt_in_single_opt_in_method:
              summary: Account opt-in method is Single Opt-in
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    send_only_double_opt_in_users cannot be set to true when
                    account opt-in method is Single Opt-in
                  target: basic_details
                  details:
                    - target: basic_details.send_only_double_opt_in_users
                      message: >-
                        send_only_double_opt_in_users cannot be set to true when
                        account opt-in method is Single Opt-in
            double_opt_in_used_on_transactional_campaign:
              summary: Used on TRANSACTIONAL campaign
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    send_only_double_opt_in_users is not supported for
                    transactional campaigns
                  target: basic_details
                  details:
                    - target: basic_details.send_only_double_opt_in_users
                      message: >-
                        send_only_double_opt_in_users is not supported for
                        transactional campaigns
            double_opt_in_wrong_type:
              summary: Wrong type (non-boolean)
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    send_only_double_opt_in_users - Invalid value passed.
                    Expected type: boolean
                  target: basic_details
                  details:
                    - target: basic_details.send_only_double_opt_in_users
                      message: >-
                        send_only_double_opt_in_users - Invalid value passed.
                        Expected type: boolean
            deduplication_attribute_feature_not_enabled_for_account:
              summary: deduplication_attribute - feature not enabled for account
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: Brand dedup is not enabled for this account
                  target: basic_details
                  details:
                    - target: basic_details.deduplication_attribute
                      message: Brand dedup is not enabled for this account
            deduplication_attribute_invalid_attribute_name:
              summary: deduplication_attribute - invalid attribute name
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    deduplication_attribute '<value>' is not a valid user
                    attribute for this account
                  target: basic_details
                  details:
                    - target: basic_details.deduplication_attribute
                      message: >-
                        deduplication_attribute '<value>' is not a valid user
                        attribute for this account
            deduplication_attribute_wrong_type_non_string:
              summary: deduplication_attribute - wrong type (non-string)
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    deduplication_attribute - Invalid value passed. Expected
                    type: string, but got: int.
                  target: basic_details
                  details:
                    - target: basic_details.deduplication_attribute
                      message: >-
                        deduplication_attribute - Invalid value passed. Expected
                        type: string, but got: int.
            deduplication_attribute_not_supported_for_api_triggered:
              summary: >-
                deduplication_attribute not supported for API_TRIGGERED
                campaigns
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    deduplication_attribute is not supported for API_TRIGGERED
                    campaigns
                  target: basic_details
                  details:
                    - target: basic_details.deduplication_attribute
                      message: >-
                        deduplication_attribute is not supported for
                        API_TRIGGERED campaigns
            gmail_annotations_on_transactional:
              summary: gmail_annotations used on TRANSACTIONAL campaign
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: campaign_content.content.email.gmail_annotations
                      message: >-
                        gmail_annotations is not supported for TRANSACTIONAL
                        content type. It is only supported for PROMOTIONAL
                        campaigns.
            gmail_annotations_missing_sender_logo:
              summary: sender_logo missing when gmail_annotations is present
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.sender_logo
                      message: >-
                        sender_logo is required when gmail_annotations is
                        specified
            gmail_annotations_invalid_sender_logo:
              summary: sender_logo is not a valid HTTPS URL
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.sender_logo
                      message: sender_logo must be a valid https URL
            gmail_annotations_deal_card_missing_field:
              summary: Required deal_card field missing
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.deal_card.availability_starts
                      message: >-
                        availability_starts is required when deal_card is
                        specified
            gmail_annotations_deal_card_invalid_end_time:
              summary: availability_ends less than 1 hour after availability_starts
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.deal_card
                      message: >-
                        End date and time must be a minimum of one hour later
                        than the start date and time
            gmail_annotations_product_carousel_minimum_products:
              summary: Product carousel has fewer than 2 products
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel
                      message: Product carousel requires a minimum of 2 products
            gmail_annotations_product_set_product_count_exceeds_maximum:
              summary: product_count exceeds maximum of 9
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.product_set_data
                      message: product_count must be between 2 and 9
            gmail_annotations_product_carousel_invalid_original_price:
              summary: Manual product has invalid original_price
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.manual_data.products[0].original_price
                      message: original_price must be a valid number
            gmail_annotations_product_carousel_invalid_discount_value:
              summary: Manual product has invalid discount_value
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.manual_data.products[0].discount_value
                      message: discount_value must be a valid number
            gmail_annotations_product_carousel_invalid_promo_url:
              summary: Manual product has invalid promo_url
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.manual_data.products[0].promo_url
                      message: promo_url must be a valid https URL
            gmail_annotations_product_carousel_empty_product_image:
              summary: Manual product has empty product_image
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.manual_data.products[0].product_image
                      message: product_image (Image URL) cannot be empty
            gmail_annotations_product_carousel_invalid_product_image_url:
              summary: Manual product has invalid product_image URL
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.manual_data.products[0].product_image
                      message: product_image must be a valid https URL
            gmail_annotations_product_set_not_found:
              summary: Product set ID does not exist in the workspace
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel.product_set_data
                      message: product_set not found for the given workspace
            gmail_annotations_product_sets_feature_not_enabled:
              summary: Product Sets feature is not enabled for the workspace
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: >-
                        campaign_content.content.email.gmail_annotations.product_carousel
                      message: Product Sets is not enabled for this workspace
            link_branding_domain_no_domain_configured:
              summary: link_branding_domain - no link branding domains configured
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    link_branding_domain cannot be processed because no link
                    branding domains have been configured for this workspace.
                    Please set up a domain in your MoEngage dashboard settings
                    first.
                  target: campaign_content.content.email
                  details:
                    - target: campaign_content.content.email.link_branding_domain
                      message: >-
                        link_branding_domain cannot be processed because no link
                        branding domains have been configured for this
                        workspace.
            link_branding_domain_no_match:
              summary: link_branding_domain - does not match a configured domain
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    The provided link_branding_domain does not match any of the
                    configured domains for this workspace. Please verify the
                    domain name and try again.
                  target: campaign_content.content.email
                  details:
                    - target: campaign_content.content.email.link_branding_domain
                      message: >-
                        The provided link_branding_domain does not match any of
                        the configured domains for this workspace.
            deep_link_domain_no_domain_configured:
              summary: deep_link_domain - no deep linking domains configured
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    deep_link_domain cannot be processed because no deep linking
                    domains have been configured for this workspace. Please set
                    up a domain in your MoEngage dashboard settings first.
                  target: campaign_content.content.email
                  details:
                    - target: campaign_content.content.email.deep_link_domain
                      message: >-
                        deep_link_domain cannot be processed because no deep
                        linking domains have been configured for this workspace.
            deep_link_domain_no_match:
              summary: deep_link_domain - does not match a configured domain
              value:
                response_id: abc-101
                error:
                  code: BAD_REQUEST
                  message: >-
                    The provided deep_link_domain does not match any of the
                    configured domains for this workspace. Please verify the
                    domain name and try again.
                  target: campaign_content.content.email
                  details:
                    - target: campaign_content.content.email.deep_link_domain
                      message: >-
                        The provided deep_link_domain does not match any of the
                        configured domains for this workspace.
            from_address_personalization_not_enabled:
              summary: >-
                from_address - personalized value used without
                EMAIL_FROM_ADDRESS_PERS enabled
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: campaign_content.content.email.from_address
                      message: >-
                        Personalized from_address is not supported for this
                        workspace. Remove the personalization token, or ask
                        support to enable EMAIL_FROM_ADDRESS_PERS.
            from_address_invalid_email:
              summary: from_address - not a valid email address
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: campaign_content.content.email.from_address
                      message: from_address is not a valid email address
            reply_to_address_invalid_email:
              summary: reply_to_address - not a valid email address
              value:
                response_id: abc-101
                error:
                  code: VALIDATION_FAILED
                  message: One or more fields failed validation.
                  details:
                    - target: campaign_content.content.email.reply_to_address
                      message: reply_to_address is not a valid email address
    V5Unauthorized:
      description: Authentication failure.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/V5ErrorEnvelope'
          example:
            response_id: abc-101
            error:
              code: UNAUTHORIZED
              message: Invalid or missing credentials.
              details: []
    V5InternalError:
      description: Unhandled server-side failure.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/V5ErrorEnvelope'
          example:
            response_id: abc-101
            error:
              code: INTERNAL_ERROR
              message: Internal server error.
              details: []
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
      description: >
        Authentication is done via Basic Auth. This requires a base64-encoded
        string of your credentials in the format `username:password`.


        - **Username**: Use your MoEngage Workspace ID (also known as the App
        ID). Find it in the MoEngage dashboard at **Settings** > **Account** >
        **API keys**.

        - **Password**: Use an API key from **Settings** > **Account** > **API
        keys**.


        Refer to [API Key
        Dashboard](/user-guide/settings/account/api-and-api-keys/api-key-dashboard)
        for details on creating and managing API keys.

````

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