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

# Campaigns API examples

> Copy/paste code examples for creating campaigns, updating email messages using content revisions, and querying themes/components for LMX.

## Create a campaign

This creates a draft campaign and a related email message in one request.

Only a `name` value is required.

<Tip>
  Save the returned `emailMessageContentRevisionId`. Pass it as
  `expectedRevisionId` when updating an email message to avoid `409 Conflict` errors caused by stale revisions.
</Tip>

[API reference](/api-reference/create-campaign)

<CodeGroup>
  ```js JavaScript theme={"dark"}
  const response = await fetch("https://app.loops.so/api/v1/campaigns", {
    method: "POST",
    headers: {
      "Authorization": "Bearer <your-api-key>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Spring product announcement",
    }),
  });

  const data = await response.json();
  const emailMessageId = data.emailMessageId;
  const emailMessageContentRevisionId = data.emailMessageContentRevisionId;
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.post(
      "https://app.loops.so/api/v1/campaigns",
      headers={
          "Authorization": "Bearer <your-api-key>",
          "Content-Type": "application/json",
      },
      json={
          "name": "Spring product announcement",
      },
  )

  data = response.json()
  email_message_id = data["emailMessageId"]
  content_revision_id = data["emailMessageContentRevisionId"]
  ```
</CodeGroup>

## Query themes and components for your LMX

You can fetch your available themes and reusable components before building
the `lmx` payload.

[List themes API reference](/api-reference/list-themes)\
[List components API reference](/api-reference/list-components)

<CodeGroup>
  ```js JavaScript theme={"dark"}
  const [themesResponse, componentsResponse] = await Promise.all([
    fetch("https://app.loops.so/api/v1/themes?perPage=20", {
      method: "GET",
      headers: {
        "Authorization": "Bearer <your-api-key>",
      },
    }),
    fetch("https://app.loops.so/api/v1/components?perPage=20", {
      method: "GET",
      headers: {
        "Authorization": "Bearer <your-api-key>",
      },
    }),
  ]);

  const themes = await themesResponse.json();
  const components = await componentsResponse.json();
  ```

  ```python Python theme={"dark"}
  import requests

  themes_response = requests.get(
      "https://app.loops.so/api/v1/themes",
      headers={
          "Authorization": "Bearer <your-api-key>",
      },
      params={"perPage": 20},
  )

  components_response = requests.get(
      "https://app.loops.so/api/v1/components",
      headers={
          "Authorization": "Bearer <your-api-key>",
      },
      params={"perPage": 20},
  )

  themes = themes_response.json()
  components = components_response.json()
  ```
</CodeGroup>

## Update the related email message with `contentRevisionId`

Use `emailMessageId` from when you created the campaign as the path parameter, and pass the `emailMessageContentRevisionId` as `expectedRevisionId`.

Apply styles or a theme in `<Style />`, and create an email using LMX elements.

Themes and components you queried in step 2 can be referenced by their IDs.

<Tip>
  Save the returned `contentRevisionId` after each update. Pass it as
  `expectedRevisionId` on the next update to avoid `409 Conflict` errors caused
  by stale revisions.
</Tip>

[API reference](/api-reference/update-email-message)\
[Get theme API reference](/api-reference/get-theme)\
[Get component API reference](/api-reference/get-component)

<CodeGroup>
  ```js JavaScript theme={"dark"}
  const lmxContent = `
  <Style themeId="default" />
  <Paragraph>
    <Text>Hey there, here is what's new.</Text>
  </Paragraph>
  <Component componentId="logo" />
  <Section> 
    ...
  </Section>`;

  const response = await fetch(
    `https://app.loops.so/api/v1/email-messages/${emailMessageId}`,
    {
      method: "POST",
      headers: {
        "Authorization": "Bearer <your-api-key>",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        expectedRevisionId: emailMessageContentRevisionId,
        subject: "Big spring updates",
        previewText: "A quick look at what's new",
        fromName: "Loops",
        fromEmail: "hello",
        replyToEmail: "support@example.com",
        lmx: lmxContent,
      }),
    },
  );

  const updated = await response.json();
  const nextContentRevisionId = updated.contentRevisionId;
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.post(
      f"https://app.loops.so/api/v1/email-messages/{email_message_id}",
      headers={
          "Authorization": "Bearer <your-api-key>",
          "Content-Type": "application/json",
      },
      json={
          "expectedRevisionId": email_message_content_revision_id,
          "subject": "Big spring updates",
          "previewText": "A quick look at what's new",
          "fromName": "Loops",
          "fromEmail": "hello",
          "replyToEmail": "support@example.com",
          "lmx": "<Email><Style backgroundColor=\"#ffffff\" textBaseColor=\"#111111\" /><Section><Text>Hey there, here is what's new.</Text></Section></Email>",
      },
  )

  updated = response.json()
  next_content_revision_id = updated["contentRevisionId"]
  ```
</CodeGroup>

## Upload an image asset

If your LMX includes `<Image />` tags, upload image files with the Upload API
and use the returned `finalUrl` as the image `src`.

[Create upload API reference](/api-reference/create-upload)\
[Complete upload API reference](/api-reference/complete-upload)

<CodeGroup>
  ```js JavaScript theme={"dark"}
  const createResponse = await fetch("https://app.loops.so/api/v1/uploads", {
    method: "POST",
    headers: {
      "Authorization": "Bearer <your-api-key>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      contentType: "image/png",
      contentLength: imageBuffer.byteLength,
    }),
  });

  const { emailAssetId, presignedUrl } = await createResponse.json();

  await fetch(presignedUrl, {
    method: "PUT",
    headers: {
      "Content-Type": "image/png",
      "Content-Length": String(imageBuffer.byteLength),
    },
    body: imageBuffer,
  });

  const completeResponse = await fetch(
    `https://app.loops.so/api/v1/uploads/${emailAssetId}/complete`,
    {
      method: "POST",
      headers: {
        "Authorization": "Bearer <your-api-key>",
      },
    },
  );

  const { finalUrl } = await completeResponse.json();
  ```

  ```python Python theme={"dark"}
  import requests

  create_response = requests.post(
      "https://app.loops.so/api/v1/uploads",
      headers={
          "Authorization": "Bearer <your-api-key>",
          "Content-Type": "application/json",
      },
      json={
          "contentType": "image/png",
          "contentLength": len(image_bytes),
      },
  )

  create_data = create_response.json()
  email_asset_id = create_data["emailAssetId"]
  presigned_url = create_data["presignedUrl"]

  requests.put(
      presigned_url,
      headers={
          "Content-Type": "image/png",
          "Content-Length": str(len(image_bytes)),
      },
      data=image_bytes,
  )

  complete_response = requests.post(
      f"https://app.loops.so/api/v1/uploads/{email_asset_id}/complete",
      headers={
          "Authorization": "Bearer <your-api-key>",
      },
  )

  final_url = complete_response.json()["finalUrl"]
  ```
</CodeGroup>
