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

# Content APIs Overview

> List the content APIs configured in your workspace and test a saved configuration against its upstream endpoint.

A content API is an external endpoint that MoEngage calls to pull dynamic data into a campaign at send time. For example, you can use one to fetch the current weather in a user's city, the live price of an item in their cart, or the status of their flight.

The MoEngage Content APIs allow you to list the content APIs configured in your workspace and 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](/docs/user-guide/settings/advanced-settings/add-a-content-api).

## Endpoints

The Content APIs are a collection of the following endpoints:

* [List Content APIs](/docs/api/content-apis/list-content-apis): Returns all content APIs in the workspace, or a single one specified by name or ID.
* [Test Content API](/docs/api/content-apis/test-content-api): Calls the upstream endpoint of a saved content API and returns the response.

## Authentication

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](/docs/user-guide/settings/account/api-and-api-keys/api-key-dashboard) for details on creating and managing API keys.

## Personalization Tokens

A content API configuration can include Jinja tokens in its URL, parameters, headers, or body. Tokens are grouped by namespace — for example, `{{UserAttribute['city']}}` or `{{EventAttribute['name']}}`.

When you test a configuration, supply sample values for these tokens in the `dynamic_values` object of the request body, keyed by namespace. A token like `{{UserAttribute['city']}}` resolves from `dynamic_values.UserAttribute.city`. MoEngage resolves every token before calling the upstream endpoint.

Omit the request body if the configuration has no tokens.

## Pagination

[List Content APIs](/docs/api/content-apis/list-content-apis) returns at most 20 items per page. Treat the cursor as opaque — do not decode or modify it.

To page through every content API in the workspace:

1. Request the first page with `limit` alone.

   ```bash First Page theme={null}
   curl --request GET \
     --url 'https://api-01.moengage.com/v5/content-apis?limit=20' \
     --header 'Authorization: Basic <base64(workspaceId:apiKey)>'
   ```

2. Check `pagination.has_more` in the response. When it is `true`, send the same request again with `pagination.next_cursor` passed back as the `cursor` parameter, keeping `limit` unchanged.

   ```bash Next Page theme={null}
   curl --request GET \
     --url 'https://api-01.moengage.com/v5/content-apis?limit=20&cursor=eyJsYXN0X2lkIjoiNjZiM2QxZTBmMmE0YzU4ZTlkN2IzYzIxIn0=' \
     --header 'Authorization: Basic <base64(workspaceId:apiKey)>'
   ```

3. Repeat step 2 until `pagination.has_more` is `false`.

## FAQs

### Manage Content APIs

<AccordionGroup>
  <Accordion title="Can I create or edit a content API with these endpoints?">
    No. These endpoints are read-only, apart from the test call. Create and edit content APIs from the MoEngage dashboard. For more information, see [Add a Content API](/docs/user-guide/settings/advanced-settings/add-a-content-api).
  </Accordion>

  <Accordion title="How do I fetch a single content API?">
    Pass either `name` or `id` to [List Content APIs](/docs/api/content-apis/list-content-apis). Supplying both returns a `400` error. Omit both to list every content API in the workspace.
  </Accordion>

  <Accordion title="Why is the request_body field empty for my content API?">
    A request body applies only to `POST` and `PUT` content APIs. For `GET` configurations, `request_body` is empty and `request_body_type` does not affect the call.
  </Accordion>

  <Accordion title="What does the verified field mean?">
    `verified` becomes `true` once the content API has returned a successful test response. `last_tested_at` records when that test ran.
  </Accordion>
</AccordionGroup>

### Test Content APIs

<AccordionGroup>
  <Accordion title="Do I always need to send a request body when testing?">
    No. The request body is optional. Send it only when the saved configuration contains Jinja tokens that need sample values. Omit it entirely otherwise.
  </Accordion>

  <Accordion title="The test returned 200, but the data looks wrong. What should I check?">
    A `200` means MoEngage reached the upstream endpoint — it does not mean the upstream call succeeded. Check `data.api_response_code` for the status code the upstream endpoint returned, and `data.api_response_body` for its response.
  </Accordion>

  <Accordion title="Why did my test return a 400 error?">
    Either the request body failed validation, or the saved configuration's URL resolves to an internal or private IP range. MoEngage validates the URL against server-side request forgery (SSRF) and rejects those addresses.
  </Accordion>

  <Accordion title="How do I stop sensitive fields from appearing in responses?">
    List them in the content API's `pii_fields_in_response` configuration. Fields marked this way are treated as personally identifiable information (PII).
  </Accordion>
</AccordionGroup>

## Postman Collection

Test these endpoints using our pre-configured Postman collection: [View MoEngage Content APIs Collection](https://www.postman.com/moengage-dev/api-docs/collection/wssclnq/moengage-content-api-v5?action=share\&source=copy-link\&creator=3486165).
