> ## 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.

# Test Content API

> Loads the saved content API identified by `id` and executes it against the upstream endpoint, returning the response. The full definition — URL, method, parameters, headers, body, and authentication — comes from the saved configuration.

The optional request body supplies sample values for the personalization tokens (`{{UserAttribute['city']}}`) in that configuration, which are resolved before the call. Omit the body if the configuration has no tokens.

Send `Content-Type: application/json` only when you include a request body. When the saved configuration has no tokens and you send no body, omit the header as well.

The upstream response is passed through in `data.api_response_body` — parsed JSON when the upstream returns JSON, and the raw body as a string otherwise. See the response examples for both cases.

The URL is validated against server-side request forgery (SSRF): internal and private ranges are rejected with `400`.

A well-formed `id` that matches no saved configuration returns `404`. An `id` that is not a valid ObjectId returns `400` with `VALIDATION_FAILED`.


#### Rate Limits

The rate limits are at the workspace level. A maximum of 10 requests per minute and 100 requests per hour are allowed per workspace.


## OpenAPI

````yaml /api/content-apis/content-apis.yaml post /v5/content-apis/{id}/test
openapi: 3.0.3
info:
  title: MoEngage Content APIs
  version: '5.0'
  description: >
    A content API is an external endpoint that MoEngage calls to pull dynamic
    data into a campaign at send time — for example, the current weather in a
    user's city or the live price of an item in their cart.


    Use these endpoints to list the content APIs configured in your workspace
    and to test a saved configuration against its upstream endpoint. To create
    or edit a content API, use the MoEngage dashboard. For more information, see
    [Add a Content
    API](/user-guide/settings/advanced-settings/add-a-content-api).
servers:
  - url: https://api-{dc}.moengage.com
    description: MoEngage Content APIs Server
    variables:
      dc:
        default: '01'
        description: >-
          The 'dc' in the API Endpoint URL refers to the MoEngage Data Center
          (DC). MoEngage hosts each customer in a different DC. You can find
          your DC number and replace the value of 'dc' in the URL by referring
          to the DC and API endpoint mapping
          [here](/api/introduction#data-centers). Your MoEngage Data Center (DC)
          can be 01, 02, 03, 04, 05, 06, or 101.
security:
  - basicAuth: []
tags:
  - name: Content APIs
    description: List, look up, and test workspace Content API configurations.
paths:
  /v5/content-apis/{id}/test:
    post:
      tags:
        - Content APIs
      summary: Test Content API
      description: >
        Loads the saved content API identified by `id` and executes it against
        the upstream endpoint, returning the response. The full definition —
        URL, method, parameters, headers, body, and authentication — comes from
        the saved configuration.


        The optional request body supplies sample values for the personalization
        tokens (`{{UserAttribute['city']}}`) in that configuration, which are
        resolved before the call. Omit the body if the configuration has no
        tokens.


        Send `Content-Type: application/json` only when you include a request
        body. When the saved configuration has no tokens and you send no body,
        omit the header as well.


        The upstream response is passed through in `data.api_response_body` —
        parsed JSON when the upstream returns JSON, and the raw body as a string
        otherwise. See the response examples for both cases.


        The URL is validated against server-side request forgery (SSRF):
        internal and private ranges are rejected with `400`.


        A well-formed `id` that matches no saved configuration returns `404`. An
        `id` that is not a valid ObjectId returns `400` with
        `VALIDATION_FAILED`.
      operationId: testContentApi
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: >-
            Content API ID of the saved config to test — a bare 24-character
            hexadecimal ObjectId, with no resource prefix. Pass it exactly as
            returned in `data[].id` from [List Content
            APIs](/api/content-apis/list-content-apis).
          example: 66b3d1e0f2a4c58e9d7b3c21
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContentApiTestRequest'
            example:
              request_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
              dynamic_values:
                UserAttribute:
                  city: Delhi
                  units: metric
                EventAttribute:
                  name: added_to_cart
                  id: id-123
      responses:
        '200':
          description: >-
            Test execution result (returned for both passing and failing
            upstream calls)
          headers:
            X-MOE-Request-Id:
              schema:
                type: string
                format: uuid
              description: >-
                Trace ID echoed from the request. Generated by MoEngage when you
                do not send one.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentApiTestResponse'
              examples:
                jsonResponse:
                  summary: Upstream returned JSON
                  value:
                    response_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
                    type: content-apis
                    data:
                      api_response_code: 200
                      api_response_body:
                        weather:
                          - main: Clouds
                            description: overcast clouds
                        main:
                          temp: 307.22
                          humidity: 50
                        name: Delhi
                        cod: 200
                plainTextResponse:
                  summary: Upstream returned plain text
                  value:
                    response_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
                    type: content-apis
                    data:
                      api_response_code: 200
                      api_response_body: '22.50'
                htmlErrorResponse:
                  summary: Upstream returned an error page
                  value:
                    response_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
                    type: content-apis
                    data:
                      api_response_code: 502
                      api_response_body: >-
                        <html><head><title>502 Bad
                        Gateway</title></head><body><h1>502 Bad
                        Gateway</h1></body></html>
        '400':
          $ref: '#/components/responses/BadRequestTest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - basicAuth: []
components:
  parameters:
    RequestId:
      name: X-MOE-Request-Id
      in: header
      required: false
      schema:
        type: string
        format: uuid
      description: >
        Client-supplied trace ID (UUID v4). Echoed back in the
        `X-MOE-Request-Id` response header and returned unchanged as
        `response_id` in the body. When you omit this header, MoEngage generates
        a 12-character hexadecimal identifier instead. Quote it when contacting
        MoEngage Support.


        On [Test Content API](/api/content-apis/test-content-api), the body
        field `request_id` takes precedence: when you send both, `response_id`
        echoes `request_id` and this header is echoed only in the
        `X-MOE-Request-Id` response header.
      example: 9f2c1b7a-4d3e-4a08-b5c6-1e7d02f43a91
  schemas:
    ContentApiTestRequest:
      type: object
      description: >
        Sample values for the personalization tokens in the saved Content API.
        Omit the body entirely if the config has no tokens.


        A config may reference tokens from more than one namespace. Worked
        example: a config whose URL is
        `https://api.example.com/v1/weather?q={{UserAttribute['city']}}&units={{UserAttribute['units']}}&event={{EventAttribute['name']}}&event_id={{EventAttribute['id']}}`
        has four tokens across the `UserAttribute` and `EventAttribute`
        namespaces, so the body carries a `dynamic_values` entry for each —
        grouped under the namespace each token belongs to.
      properties:
        request_id:
          type: string
          description: >
            Client-generated ID for tracing. Returned unchanged as `response_id`
            in the response. This field takes precedence over the
            `X-MOE-Request-Id` header — when you send both, `response_id` echoes
            this value, and the header value is returned only in the
            `X-MOE-Request-Id` response header.
          example: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
        dynamic_values:
          type: object
          additionalProperties:
            type: object
            additionalProperties:
              type: string
          description: >
            Sample values for the personalization tokens in the saved config,
            keyed by token namespace.


            | Token in the saved config | Body path |

            | --- | --- |

            | `{{UserAttribute['city']}}` | `dynamic_values.UserAttribute.city`
            |

            | `{{EventAttribute['product_id']}}` |
            `dynamic_values.EventAttribute.product_id` |


            - The namespace is the part before the square brackets. The
            attribute name is the quoted string inside them.

            - The object is exactly two levels deep, and every value is a
            string.

            - The namespaces are not mutually exclusive. Include every namespace
            the config references.

            - Send one entry per token in the config under test, and nothing
            else. Tokens may appear in the saved url, params, headers, or body.
          example:
            UserAttribute:
              city: Delhi
              units: metric
            EventAttribute:
              name: added_to_cart
              id: id-123
    ContentApiTestResponse:
      type: object
      properties:
        response_id:
          type: string
          description: >
            Unique identifier for this response. Echoes the `request_id` you
            sent in the body, returned unchanged. When you omit `request_id`, it
            echoes the `X-MOE-Request-Id` header instead; when you send neither,
            MoEngage generates a 12-character hexadecimal identifier. Quote it
            when contacting MoEngage Support.
          example: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
        type:
          type: string
          description: >-
            The resource type contained in `data`. Always `content-apis` for
            this endpoint.
          enum:
            - content-apis
        data:
          type: object
          description: The outcome of the call MoEngage made to the upstream endpoint.
          properties:
            api_response_code:
              type: integer
              description: >
                HTTP status code returned by the upstream Content API. An
                upstream failure is still reported with `200` from this
                endpoint, so check this field rather than the envelope status to
                tell whether the upstream call succeeded.
              example: 200
            api_response_body:
              description: >
                Response body returned by the upstream Content API, passed
                through unchanged. When the upstream returns JSON, the parsed
                value appears here and can be an object, array, string, number,
                boolean, or null. When the upstream returns anything else —
                plain text, HTML, XML — the raw body appears as a JSON string.
                Do not assume this field is an object: read `api_response_code`
                first, then handle the body according to what the upstream
                endpoint actually produces.
              example:
                weather:
                  - main: Clouds
                    description: overcast clouds
                main:
                  temp: 307.22
                  humidity: 50
                name: Delhi
                cod: 200
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Machine-readable UPPER_SNAKE_CASE code.
              example: INVALID_REQUEST
            message:
              type: string
              description: Human-readable description of the error.
              example: Use either 'name' or 'id', not both.
            target:
              type: string
              description: >-
                The query parameter, path parameter, or body field that caused
                the error.
              example: id
            details:
              type: array
              description: Field-level violations. Returned for validation errors only.
              items:
                type: object
                properties:
                  code:
                    type: string
                    example: INVALID_PARAMETER_COMBINATION
                  target:
                    type: string
                    example: id
                  message:
                    type: string
                    example: The 'id' parameter cannot be combined with 'name'.
        response_id:
          type: string
          description: >-
            Unique identifier for this response. Quote it when contacting
            MoEngage Support.
          example: 9f2c1b7a-4d3e-4a08-b5c6-1e7d02f43a91
  responses:
    BadRequestTest:
      description: >
        Bad request / validation failed / URL rejected by SSRF validation. An
        `id` that is not a valid ObjectId is rejected here rather than as a
        `404`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalidUrl:
              summary: URL rejected by SSRF validation
              value:
                error:
                  code: INVALID_URL
                  message: >-
                    The URL in the saved configuration resolves to a private or
                    internal address.
                  target: url
                response_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
            malformedId:
              summary: Path `id` is not a valid ObjectId
              value:
                error:
                  code: VALIDATION_FAILED
                  message: Invalid content api id
                  target: request
                  details:
                    - target: id
                      message: Invalid content api id
                response_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
    Unauthorized:
      description: Missing or invalid authentication
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: UNAUTHORIZED
              message: Missing or invalid authentication credentials.
              target: Authorization
            response_id: 9f2c1b7a-4d3e-4a08-b5c6-1e7d02f43a91
    Forbidden:
      description: Missing required scope
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: FORBIDDEN
              message: >-
                This API key does not have the scope required to read content
                APIs.
              target: Authorization
            response_id: 9f2c1b7a-4d3e-4a08-b5c6-1e7d02f43a91
    NotFound:
      description: >
        The `id` is a well-formed ObjectId, but no content API in this workspace
        has it. A malformed `id` returns `400` with `VALIDATION_FAILED` instead.
        Confirm the ID against [List Content
        APIs](/api/content-apis/list-content-apis).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: NOT_FOUND
              message: Content API not found
              target: content_api
              details:
                - target: id
                  message: Content API not found
            response_id: 4c8e1f26-7b93-4d5a-9e08-3a1b6d7c2f45
    RateLimited:
      description: Rate limited
      headers:
        Retry-After:
          schema:
            type: integer
            example: 60
          description: Seconds to wait before retrying.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: RATE_LIMIT_EXCEEDED
              message: Workspace rate limit exceeded. Retry after 60 seconds.
            response_id: 9f2c1b7a-4d3e-4a08-b5c6-1e7d02f43a91
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: INTERNAL_ERROR
              message: >-
                An unexpected error occurred while processing the request. Retry
                the request, and quote `response_id` if you contact MoEngage
                Support.
            response_id: 9f2c1b7a-4d3e-4a08-b5c6-1e7d02f43a91
  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.

````