﻿{
  "openapi": "3.1.0",
  "info": {
    "title": "Loops OpenAPI Spec",
    "description": "This is the OpenAPI Spec for the [Loops API](https://loops.so/docs/api).",
    "version": "1.21.3"
  },
  "servers": [
    {
      "url": "https://app.loops.so/api"
    }
  ],
  "tags": [
    {
      "name": "API key"
    },
    {
      "name": "Audience segments",
      "description": "View audience segments"
    },
    {
      "name": "Campaigns",
      "description": "Create and manage email campaigns"
    },
    {
      "name": "Campaign groups",
      "description": "Organize campaigns into groups"
    },
    {
      "name": "Configuration",
      "description": "View configuration settings"
    },
    {
      "name": "Contacts",
      "description": "Manage contacts in your audience"
    },
    {
      "name": "Contact properties",
      "description": "Manage contact properties"
    },
    {
      "name": "Components",
      "description": "View email components"
    },
    {
      "name": "Email messages",
      "description": "Manage email message content for campaigns"
    },
    {
      "name": "Events",
      "description": "Trigger workflows with events"
    },
    {
      "name": "Event patterns",
      "description": "View workflow event patterns"
    },
    {
      "name": "Mailing lists",
      "description": "View mailing lists"
    },
    {
      "name": "Themes",
      "description": "View email themes"
    },
    {
      "name": "Transactional emails",
      "description": "Create, manage, and send transactional emails"
    },
    {
      "name": "Transactional groups",
      "description": "Organize transactional emails into groups"
    },
    {
      "name": "Uploads",
      "description": "Upload image assets"
    },
    {
      "name": "Workflows",
      "description": "View and mutate workflow graphs"
    },
    {
      "name": "Workflow nodes",
      "description": "View and mutate workflow nodes"
    },
    {
      "name": "Webhooks",
      "description": "Events Loops sends to your configured webhook endpoint when certain events happen in your account. Configure an endpoint in Settings → Webhooks. Each account supports one webhook endpoint. Events are signed with `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers and delivered at a maximum rate of 10 per second. See https://loops.so/docs/webhooks for setup, verification, and payload details."
    }
  ],
  "paths": {
    "/v1/api-key": {
      "get": {
        "operationId": "testApiKey",
        "tags": ["API key"],
        "summary": "API key",
        "description": "Test your API key and get team context.",
        "x-mint": {
          "href": "/api-reference/api-key"
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "examples": [true]
                    },
                    "teamName": {
                      "type": "string",
                      "description": "The name of the team the API key belongs to.",
                      "examples": ["Company name"]
                    }
                  },
                  "required": ["success", "teamName"]
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "examples": [false]
                    },
                    "message": {
                      "type": "string",
                      "examples": ["Invalid API key"]
                    },
                    "error": {
                      "type": "string",
                      "deprecated": true,
                      "examples": ["Invalid API key"]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/audience-segments/{audienceSegmentId}": {
      "parameters": [
        {
          "name": "audienceSegmentId",
          "in": "path",
          "required": true,
          "description": "The ID of the audience segment.",
          "schema": {
            "type": "string",
            "examples": ["cls6e8g0i2k4m6o8q0s2u4w6"]
          }
        }
      ],
      "get": {
        "operationId": "getAudienceSegment",
        "tags": ["Audience segments"],
        "summary": "Get an audience segment",
        "description": "Retrieve a single audience segment by ID.",
        "x-mint": {
          "href": "/api-reference/get-audience-segment",
          "metadata": {
            "sidebarTitle": "Get a segment"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `audienceSegmentId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Audience segment not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/audience-segments": {
      "get": {
        "operationId": "listAudienceSegments",
        "tags": ["Audience segments"],
        "summary": "List audience segments",
        "description": "Retrieve a paginated list of audience segments, most recently created first.",
        "x-mint": {
          "href": "/api-reference/list-audience-segments",
          "metadata": {
            "sidebarTitle": "List segments"
          }
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAudienceSegmentsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createAudienceSegment",
        "tags": ["Audience segments"],
        "summary": "Create an audience segment",
        "description": "Create a new audience segment.",
        "x-mint": {
          "href": "/api-reference/create-audience-segment",
          "metadata": {
            "sidebarTitle": "Create a segment"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAudienceSegmentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Audience segment created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, a name already used by another segment, or a filter with too many conditions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "The filter references a campaign, workflow or workflow email that does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSegmentFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/campaigns": {
      "get": {
        "operationId": "listCampaigns",
        "tags": ["Campaigns"],
        "summary": "List campaigns",
        "description": "Retrieve a paginated list of campaigns.",
        "x-mint": {
          "href": "/api-reference/list-campaigns"
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListCampaignsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createCampaign",
        "tags": ["Campaigns"],
        "summary": "Create a campaign",
        "description": "Create a new draft campaign. An empty email message is created automatically and its `emailMessageId` is returned. Use the `/email-messages/{emailMessageId}` endpoint to set subject, sender, preview text, and LMX content. The audience (mailing list, segment, or filter), group, and scheduling can be set on create or later via update.",
        "x-mint": {
          "href": "/api-reference/create-campaign",
          "metadata": {
            "description": "Create a draft marketing campaign and its associated email message."
          },
          "content": "This endpoint creates a draft campaign and an empty email message in one step. Use the returned `emailMessageId` with [Update an email message](/api-reference/update-email-message) to set subject, sender, preview text, and LMX content.\n\nThe audience (mailing list, segment, or filter), group, and scheduling can be set on create or later via [Update a campaign](/api-reference/update-campaign).\n\n<Tip>To send a test preview of a campaign, use the [Preview email message](/api-reference/preview-email-message) endpoint.</Tip>"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCampaignRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Campaign created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateCampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, campaign group not found, or no sending domain configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Referenced mailing list or audience segment not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/campaigns/{campaignId}": {
      "parameters": [
        {
          "name": "campaignId",
          "in": "path",
          "required": true,
          "description": "The ID of the campaign.",
          "schema": {
            "type": "string",
            "examples": ["clc4m6n8p0q2r4s6t8u0v2x4"]
          }
        }
      ],
      "get": {
        "operationId": "getCampaign",
        "tags": ["Campaigns"],
        "summary": "Get a campaign",
        "description": "Retrieve a single campaign by ID.",
        "x-mint": {
          "href": "/api-reference/get-campaign"
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `campaignId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateCampaign",
        "tags": ["Campaigns"],
        "summary": "Update a campaign",
        "description": "Update a draft campaign's name, group, audience (mailing list, segment, or filter), or scheduling. At least one field must be provided. Campaigns can only be updated while in draft status.",
        "x-mint": {
          "href": "/api-reference/update-campaign",
          "metadata": {
            "description": "Update a draft campaign's name, group, audience (mailing list, segment, or filter), or scheduling."
          },
          "content": "<Info>Campaigns can only be updated while they are in `Draft` status. At least one field must be provided.</Info>"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCampaignRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or campaign group not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Campaign, mailing list, or audience segment not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Campaign is not in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/campaign-groups": {
      "get": {
        "operationId": "listCampaignGroups",
        "tags": ["Campaign groups"],
        "summary": "List campaign groups",
        "description": "Retrieve a paginated list of campaign groups, most recently created first.",
        "x-mint": {
          "href": "/api-reference/list-campaign-groups",
          "metadata": {
            "sidebarTitle": "List groups"
          }
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListGroupsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createCampaignGroup",
        "tags": ["Campaign groups"],
        "summary": "Create a campaign group",
        "description": "Create a new campaign group.",
        "x-mint": {
          "href": "/api-reference/create-campaign-group",
          "metadata": {
            "sidebarTitle": "Create a group"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign group created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or reserved group name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/campaign-groups/{campaignGroupId}": {
      "parameters": [
        {
          "name": "campaignGroupId",
          "in": "path",
          "required": true,
          "description": "The ID of the campaign group.",
          "schema": {
            "type": "string",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          }
        }
      ],
      "get": {
        "operationId": "getCampaignGroup",
        "tags": ["Campaign groups"],
        "summary": "Get a campaign group",
        "description": "Retrieve a single campaign group by ID.",
        "x-mint": {
          "href": "/api-reference/get-campaign-group",
          "metadata": {
            "sidebarTitle": "Get a group"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `campaignGroupId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Campaign group not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateCampaignGroup",
        "tags": ["Campaign groups"],
        "summary": "Update a campaign group",
        "description": "Update a campaign group's name or description. At least one field must be provided. The reserved \"Unsorted\" group cannot be edited.",
        "x-mint": {
          "href": "/api-reference/update-campaign-group",
          "content": "<Info>At least one field must be provided. The reserved \"Unsorted\" group cannot be edited.</Info>",
          "metadata": {
            "description": "Update a campaign group's name or description.",
            "sidebarTitle": "Update a group"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign group updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, reserved group name, or the Unsorted group cannot be edited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Campaign group not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/dedicated-sending-ips": {
      "get": {
        "operationId": "listDedicatedSendingIps",
        "tags": ["Configuration"],
        "summary": "List dedicated sending IP addresses",
        "description": "Retrieve a list of Loops' dedicated sending IP addresses.\n\nThis endpoint is provided for the rare instances where you may need to whitelist our sending IPs. Please note that this list is subject to change and will not include shared IPs used for sending mail.\n\nUnless you are sure you need this and are comfortable watching for changes, we strongly recommend you _do not_ whitelist these IPs.",
        "x-mint": {
          "href": "/api-reference/dedicated-sending-ips",
          "metadata": {
            "description": "Retrieve a list of Loops' dedicated sending IP addresses.",
            "sidebarTitle": "List sending IPs"
          },
          "content": "<Warning>This endpoint is provided for the rare instances where you may need to whitelist our sending IPs. Please note that this list is subject to change and will not include shared IPs used for sending mail. Unless you are sure you need this and are comfortable watching for changes, we strongly recommend you _do not_ whitelist these IPs.</Warning>"
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "description": "Returns an array of IP address strings.",
                  "items": {
                    "type": "string",
                    "description": "IP address",
                    "examples": ["52.21.45.123"]
                  },
                  "example": ["52.21.45.123", "52.21.45.124", "52.21.45.125"]
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/contacts/create": {
      "post": {
        "operationId": "createContact",
        "tags": ["Contacts"],
        "summary": "Create a contact",
        "description": "Add a contact to your audience.",
        "x-mint": {
          "href": "/api-reference/create-contact",
          "content": "<Tip>If you want to \"update or create\" contacts, consider using the [Update a contact](https://loops.so/docs/api-reference/update-contact) endpoint instead.</Tip>"
        },
        "requestBody": {
          "description": "You can add custom contact properties as keys in this request (of type `string`, `number`, `boolean` or `date`. [See available date formats](https://loops.so/docs/contacts/properties#dates)). Make sure to create the properties in Loops before using them in API calls.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful create.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. invalid email address).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Email or `userId` already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/contacts/update": {
      "put": {
        "operationId": "updateContact",
        "tags": ["Contacts"],
        "summary": "Update a contact",
        "description": "Update a contact by `email` or `userId`. You must provide one of these parameters.\n\nIf you want to update a contact's email address, the contact will first need a `userId` value. You can then make a request containing the `userId` field along with an updated email address.\n\nThis endpoint will create a contact if a matching contact does not already exist in your audience.\n\nProvide either `email` or `userId` to identify the contact you want to update. If both are provided, the system will look for a contact with either a matching `email` or `userId` value. If a contact is found for one of the values (e.g. `email`), the other value (e.g. `userId`) will be updated. If a contact is not found, a new contact will be created using both `email` and `userId` values.",
        "x-mint": {
          "href": "/api-reference/update-contact",
          "content": "Update a contact by `email` or `userId`. You must provide one of these parameters.\n\nIf you want to update a contact's email address, the contact will first need a `userId` value. You can then make a request containing the `userId` field along with an updated email address.\n\nThis endpoint will create a contact if a matching contact does not already exist in your audience.\n\n<Note>Provide either `email` or `userId` to identify the contact you want to update. If both are provided, the system will look for a contact with either a matching `email` or `userId` value. If a contact is found for one of the values (e.g. `email`), the other value (e.g. `userId`) will be updated. If a contact is not found, a new contact will be created using both `email` and `userId` values.</Note>",
          "metadata": {
            "sidebarTitle": "Update a contact",
            "description": "Update or create a contact."
          }
        },
        "requestBody": {
          "description": "You can add custom contact properties as keys in this request (of type `string`, `number`, `boolean` or `date`. [See available date formats](https://loops.so/docs/contacts/properties#dates)). Make sure to create the properties in Loops before using them in API calls.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactUpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful update.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. `email` or `userId` are missing).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/contacts/find": {
      "get": {
        "operationId": "findContact",
        "tags": ["Contacts"],
        "summary": "Find a contact",
        "description": "Search for a contact by `email` or `userId`. Only one parameter is allowed.",
        "x-mint": {
          "href": "/api-reference/find-contact",
          "content": "Search for a contact by `email` or `userId`. Only one parameter is allowed.",
          "metadata": {
            "description": "Find a contact by email address or user ID."
          }
        },
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Email address (URI-encoded)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of contacts (or an empty array if no contact was found). Contact objects will include any custom properties.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Contact"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. invalid email address).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/contacts/delete": {
      "post": {
        "operationId": "deleteContact",
        "tags": ["Contacts"],
        "summary": "Delete a contact",
        "description": "Delete a contact by `email` or `userId`.",
        "x-mint": {
          "href": "/api-reference/delete-contact",
          "content": "Delete a contact by `email` or `userId`.",
          "metadata": {
            "sidebarTitle": "Delete a contact",
            "description": "Delete a contact by email address or user ID."
          }
        },
        "requestBody": {
          "description": "Include only one of `email` or `userId`.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactDeleteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDeleteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. `email` and `userId` are both provided).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/contacts/suppression": {
      "get": {
        "operationId": "getContactSuppression",
        "tags": ["Contacts"],
        "summary": "Get suppression status for a contact",
        "description": "Retrieve suppression status and removal quota for a contact by `email` or `userId`. Include only one query parameter.",
        "x-mint": {
          "href": "/api-reference/check-contact-suppression",
          "metadata": {
            "title": "Check contact suppression status",
            "sidebarTitle": "Check suppression",
            "description": "Check if a contact is suppressed by email address or user ID."
          }
        },
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Email address (URI-encoded)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSuppressionStatusResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. invalid email address).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "delete": {
        "operationId": "removeContactSuppression",
        "tags": ["Contacts"],
        "summary": "Remove a contact from suppression list",
        "description": "Remove a suppressed contact from the suppression list by `email` or `userId`. Include only one query parameter.",
        "x-mint": {
          "href": "/api-reference/remove-contact-suppression",
          "metadata": {
            "title": "Remove contact from suppression",
            "sidebarTitle": "Remove suppression",
            "description": "Remove suppression for a contact by email address or user ID."
          }
        },
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Email address (URI-encoded)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful removal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSuppressionRemoveResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. contact is not suppressed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/contacts/properties": {
      "post": {
        "operationId": "createContactProperty",
        "tags": ["Contact properties"],
        "summary": "Create a contact property",
        "description": "Create a custom contact property.",
        "x-mint": {
          "href": "/api-reference/create-contact-property",
          "metadata": {
            "sidebarTitle": "Create property"
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactPropertyCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful create.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactPropertySuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. invalid type).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactPropertyFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "get": {
        "operationId": "listContactProperties",
        "tags": ["Contact properties"],
        "summary": "List contact properties",
        "description": "Retrieve a list of your account's contact properties.<br>Use the `list` parameter to query \"all\" or \"custom\" properties.",
        "x-mint": {
          "href": "/api-reference/list-contact-properties",
          "metadata": {
            "sidebarTitle": "List properties",
            "description": "Retrieve a list of your account's contact properties."
          }
        },
        "parameters": [
          {
            "name": "list",
            "in": "query",
            "required": false,
            "description": "`all` (default) or `custom` (only custom contact properties)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ContactProperty"
                  }
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/components/{componentId}": {
      "parameters": [
        {
          "name": "componentId",
          "in": "path",
          "required": true,
          "description": "The ID of the component.",
          "schema": {
            "type": "string",
            "examples": ["clp2o4i6u8y0t5r3e1w7q9s1"]
          }
        }
      ],
      "get": {
        "operationId": "getComponent",
        "tags": ["Components"],
        "summary": "Get a component",
        "description": "Retrieve a single component by ID.",
        "x-mint": {
          "href": "/api-reference/get-component"
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `componentId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Component not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateComponent",
        "tags": ["Components"],
        "summary": "Update a component",
        "description": "Update a component's name and/or body. When the `lmx` body changes, the update cascades to every email using this component, and `affectedEmailCount` reports how many were affected. A change that would introduce a dynamic variable an email using the component cannot use is rejected.",
        "x-mint": {
          "href": "/api-reference/update-component",
          "content": "When the `lmx` body changes, the update cascades to every email using this component, and `affectedEmailCount` reports how many were affected. A change that would introduce a dynamic variable an email using the component cannot use is rejected.",
          "metadata": {
            "description": "Update a component's name and/or LMX body. Body changes cascade to every email using the component."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateComponentBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateComponentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `componentId` or request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Component not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "413": {
            "description": "LMX body exceeds the size limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "422": {
            "description": "Invalid LMX, or a body change that would break emails using the component.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentValidationFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/components": {
      "get": {
        "operationId": "listComponents",
        "tags": ["Components"],
        "summary": "List components",
        "description": "Retrieve a paginated list of email components.",
        "x-mint": {
          "href": "/api-reference/list-components"
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListComponentsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createComponent",
        "tags": ["Components"],
        "summary": "Create a component",
        "description": "Create a new email component from an LMX body.",
        "x-mint": {
          "href": "/api-reference/create-component"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateComponentBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Component created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "413": {
            "description": "LMX body exceeds the size limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          },
          "422": {
            "description": "Invalid LMX.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/email-messages/{emailMessageId}": {
      "parameters": [
        {
          "name": "emailMessageId",
          "in": "path",
          "required": true,
          "description": "The ID of the email message.",
          "schema": {
            "type": "string",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          }
        }
      ],
      "get": {
        "operationId": "getEmailMessage",
        "tags": ["Email messages"],
        "summary": "Get an email message",
        "description": "Retrieve an email message, including its compiled LMX content.",
        "x-mint": {
          "href": "/api-reference/get-email-message",
          "metadata": {
            "sidebarTitle": "Get an email"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `emailMessageId` or no sending domain configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Email message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Email message uses MJML format or content cannot be parsed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateEmailMessage",
        "tags": ["Email messages"],
        "summary": "Update an email message",
        "description": "Update fields on an email message (subject, preview text, sender, LMX content). The campaign must be in draft status. Supply `expectedRevisionId` matching the current `contentRevisionId` — the server rejects mismatched revisions with 409.",
        "x-mint": {
          "href": "/api-reference/update-email-message",
          "metadata": {
            "description": "Update an email message's subject, preview text, sender, or LMX content.",
            "sidebarTitle": "Update an email"
          },
          "content": "Supply `expectedRevisionId` matching the current `contentRevisionId`.\n\n<Info>The campaign or transactional email that owns this email message must be in `Draft` status.</Info>"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEmailMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email message updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Email message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Campaign is not in draft status, `contentRevisionId` is stale, content cannot be parsed, or email message uses MJML format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "413": {
            "description": "LMX payload exceeds the 100KB limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "422": {
            "description": "LMX failed to compile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/email-messages/{emailMessageId}/preview": {
      "parameters": [
        {
          "name": "emailMessageId",
          "in": "path",
          "required": true,
          "description": "The ID of the email message.",
          "schema": {
            "type": "string",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          }
        }
      ],
      "post": {
        "operationId": "previewEmailMessage",
        "tags": ["Email messages"],
        "summary": "Send a preview of an email message",
        "description": "Send a test preview of an email message to one or more addresses. The accepted variable fields depend on the parent's type - campaign previews accept `contactProperties`, workflow previews accept `contactProperties` and `eventProperties`, and transactional previews accept `dataVariables`. Supplying a field the parent cannot reference is rejected with 400.",
        "x-mint": {
          "href": "/api-reference/preview-email-message",
          "content": "Send a test email message to one or more addresses. Accepted variable fields depend on the parent's type:\n\n- **Campaign** accepts `contactProperties`.\n- **Workflow** accepts `contactProperties` and `eventProperties`.\n- **Transactional** accepts `dataVariables`.\n\nSupplying a field the parent cannot reference results in a `400 Bad Request` error.\n\nEach team can send up to 100 preview emails per day.",
          "metadata": {
            "description": "Send a test preview of an email message to one or more addresses.",
            "sidebarTitle": "Preview email"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailMessagePreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessagePreviewResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, or a variable field the parent cannot reference.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Email message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "429": {
            "description": "The daily preview limit was reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/email-messages/{emailMessageId}/guardian": {
      "parameters": [
        {
          "name": "emailMessageId",
          "in": "path",
          "required": true,
          "description": "The ID of the email message.",
          "schema": {
            "type": "string",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          }
        }
      ],
      "get": {
        "operationId": "getEmailMessageGuardian",
        "tags": ["Email messages"],
        "summary": "Run Guardian checks on an email message",
        "description": "Validate an email message's content against Guardian rules and return any errors and warnings. Errors must be resolved before the email can be published, warnings are advisory.",
        "x-mint": {
          "href": "/api-reference/run-guardian-checks",
          "content": "Run the same [Guardian](/creating-emails/guardian) checks that run in the Loops editor on a saved email message. Use this to validate campaign, workflow, and transactional email content before publishing or sending.\n\nChecks depend on the email message's parent type:\n\n- **Campaign** validates contact properties and rendered links and buttons.\n- **Workflow** validates contact properties, event properties from the workflow's event trigger, and rendered links and buttons.\n- **Transactional** validates data variables and rendered links and buttons.\n- **System transactional** validates required data variables and rendered links and buttons.\n\n<Info>This will not work on MJML email messages, as they are not supported in the API.</Info>",
          "metadata": {
            "description": "Run Guardian content validation on an email message and return errors and warnings before you publish or send.",
            "sidebarTitle": "Guardian checks"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageGuardianResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `emailMessageId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Email message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Email message uses MJML format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailMessageFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/events/send": {
      "post": {
        "operationId": "sendEvent",
        "tags": ["Events"],
        "summary": "Send an event",
        "description": "Send events to trigger workflows.",
        "x-mint": {
          "href": "/api-reference/send-event",
          "content": "<Note>Provide either an `email` or `userId` value or both to identify the contact. If both are provided, the system will look for a contact with either a matching `email` or `userId` value. If a contact is found for one of the values (e.g. `email`), the other value (e.g. `userId`) will be updated. If a contact is not found, a new contact will be created using both `email` and `userId` values.</Note>"
        },
        "requestBody": {
          "description": "Provide either `email` or `userId` to identify the contact ([read more](https://loops.so/docs/api-reference/send-event#body)).<br>Event properties will be available in emails sent by this event. Values of properties can be of type `string`, `number`, `boolean` or `date` ([see allowed date formats](https://loops.so/docs/events/properties#important-information-about-event-properties)).<br>Make sure to create the properties in Loops before using them in API calls.<br>You can add contact properties as keys in this request (of type `string`, `number`, `boolean` or `date` ([see available date formats](https://loops.so/docs/contacts/properties#dates))).",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventRequest"
              }
            }
          },
          "required": true
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Include a unique ID for this request (maximum 100 characters) to avoid duplicate emails.\n\nThe value should be a string of up to 100 characters and should be unique for each request. We recommend using V4 UUIDs or some other method with enough guaranteed entropy to avoid collisions during a 24 hour window.\n\nThis endpoint will return a `409 Conflict` response if the idempotency key has been used in the previous 24 hours.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventSuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. `eventName` is missing).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Idempotency key has been used.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdempotencyKeyFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/event-patterns": {
      "get": {
        "tags": ["Event patterns"],
        "summary": "List event patterns",
        "operationId": "listEventPatterns",
        "description": "Retrieve a paginated list of event patterns available to workflow event trigger nodes.",
        "x-mint": {
          "href": "/api-reference/list-event-patterns"
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListEventPatternsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` or `cursor` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPatternFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/event-patterns/by-name/{eventName}": {
      "parameters": [
        {
          "name": "eventName",
          "in": "path",
          "required": true,
          "description": "The exact event name. Event names are case-sensitive and should be URL-encoded if they contain special characters.",
          "schema": { "type": "string" }
        }
      ],
      "get": {
        "tags": ["Event patterns"],
        "summary": "Get an event pattern by name",
        "operationId": "getEventPatternByName",
        "description": "Retrieve event pattern details by event name for a workflow event trigger. Event names are case-sensitive, so `PaymentReceived` and `paymentReceived` are different events.",
        "x-mint": {
          "href": "/api-reference/get-event-pattern-by-name",
          "metadata": {
            "sidebarTitle": "Get by name"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPattern"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `eventName`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPatternFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Event pattern not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPatternFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/event-patterns/{eventPatternId}": {
      "parameters": [
        {
          "name": "eventPatternId",
          "in": "path",
          "required": true,
          "description": "The ID of the event pattern.",
          "schema": { "type": "string" }
        }
      ],
      "get": {
        "tags": ["Event patterns"],
        "summary": "Get an event pattern by ID",
        "operationId": "getEventPattern",
        "description": "Retrieve event pattern details for a workflow event trigger.",
        "x-mint": {
          "href": "/api-reference/get-event-pattern",
          "metadata": {
            "sidebarTitle": "Get by ID"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPattern"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `eventPatternId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPatternFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Event pattern not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPatternFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/lists": {
      "get": {
        "operationId": "listMailingLists",
        "tags": ["Mailing lists"],
        "summary": "List mailing lists",
        "description": "Retrieve a list of your account's mailing lists.",
        "x-mint": {
          "href": "/api-reference/list-mailing-lists"
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MailingList"
                  }
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/themes/{themeId}": {
      "parameters": [
        {
          "name": "themeId",
          "in": "path",
          "required": true,
          "description": "The ID of the theme.",
          "schema": {
            "type": "string",
            "examples": ["clt3u5v7w9x1y3z5a7b9c1d3"]
          }
        }
      ],
      "get": {
        "operationId": "getTheme",
        "tags": ["Themes"],
        "summary": "Get a theme",
        "description": "Retrieve a single theme by ID.",
        "x-mint": {
          "href": "/api-reference/get-theme"
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `themeId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Theme not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateTheme",
        "tags": ["Themes"],
        "summary": "Update a theme",
        "description": "Update a theme's name and/or styles. When `styles` change, the update cascades to every email using this theme, and `affectedEmailCount` in the response reports how many emails were affected. Manual style edits made on individual emails are preserved: the cascade only changes properties an email has not overridden. A per-email override is removed only when it becomes identical to the theme's new value, after which that email follows the theme for that property.",
        "x-mint": {
          "href": "/api-reference/update-theme",
          "content": "When `styles` change, the update cascades to every email using this theme, and `affectedEmailCount` in the response reports how many emails were affected.\n\nManual style edits made on individual emails are preserved: the cascade only changes properties an email has not overridden. A per-email override is removed only when it becomes identical to the theme's new value, after which that email follows the theme for that property.",
          "metadata": {
            "description": "Update a theme's name and/or styles. Style changes cascade to every email using the theme."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateThemeBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateThemeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `themeId` or request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Theme not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/themes": {
      "get": {
        "operationId": "listThemes",
        "tags": ["Themes"],
        "summary": "List themes",
        "description": "Retrieve a paginated list of email themes, most recently created first.",
        "x-mint": {
          "href": "/api-reference/list-themes"
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListThemesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createTheme",
        "tags": ["Themes"],
        "summary": "Create a theme",
        "description": "Create a new email theme for use across Loops emails.",
        "x-mint": {
          "href": "/api-reference/create-theme"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateThemeBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Theme created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThemeFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional": {
      "post": {
        "operationId": "sendTransactionalEmail",
        "tags": ["Transactional emails"],
        "summary": "Send a transactional email",
        "description": "Send a transactional email to a contact.<br>Please [email us](mailto:help@loops.so) to enable attachments on your account before using them with the API.\n\nTo set dynamic Subject, From, Reply to, CC, BCC email header fields, add data variables to those fields in the editor, then include data for each variable in the API request. Read our transactional email guide for more details.",
        "x-mint": {
          "metadata": {
            "description": "Send a transactional email.",
            "sidebarTitle": "Send transactional"
          },
          "href": "/api-reference/send-transactional-email",
          "content": "Send a transactional email, including optional data variables, to a single recipient.\n\nTo set dynamic Subject, From, Reply to, CC, BCC email header fields, add data variables to those fields in the editor, then include data for each variable in the API request. Read our [transactional email guide](/docs/transactional) for more details.\n\nTo send a test preview of a transactional email, use the [Preview email message](/api-reference/preview-email-message) endpoint.\n\n<Note>Please [email us](mailto:help@loops.so) to enable attachments on your account before using them with the API.</Note>"
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionalRequest"
              }
            }
          },
          "required": true
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Include a unique ID for this request (maximum 100 characters) to avoid duplicate emails.\n\nThe value should be a string of up to 100 characters and should be unique for each request. We recommend using V4 UUIDs or some other method with enough guaranteed entropy to avoid collisions during a 24 hour window.\n\nThis endpoint will return a `409 Conflict` response if the idempotency key has been used in the previous 24 hours.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalSuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request (e.g. transactional email is not published).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TransactionalSendFailureResponse"
                    },
                    {
                      "$ref": "#/components/schemas/TransactionalFailure2Response"
                    },
                    {
                      "$ref": "#/components/schemas/TransactionalFailure3Response"
                    },
                    {
                      "$ref": "#/components/schemas/TransactionalFailure4Response"
                    },
                    {
                      "$ref": "#/components/schemas/TransactionalFailure5Response"
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Transactional email not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailure3Response"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "Idempotency key has been used.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdempotencyKeyFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "get": {
        "operationId": "listPublishedTransactionalEmails",
        "deprecated": true,
        "tags": ["Transactional emails"],
        "summary": "List transactional emails",
        "description": "Get a list of published transactional emails.",
        "x-mint": {
          "href": "/api-reference/list-transactional-emails-v1",
          "content": "<Warning>This endpoint is deprecated. Use [List transactional emails](/api-reference/list-transactional-emails) instead.</Warning>"
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListTransactionalsResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional-emails": {
      "get": {
        "operationId": "listTransactionalEmails",
        "tags": ["Transactional emails"],
        "summary": "List transactional emails",
        "description": "Retrieve a paginated list of transactional emails, most recently created first.",
        "x-mint": {
          "href": "/api-reference/list-transactional-emails",
          "metadata": {
            "sidebarTitle": "List transactionals"
          }
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListTransactionalsResourceResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createTransactionalEmail",
        "tags": ["Transactional emails"],
        "summary": "Create a transactional email",
        "description": "Create a new transactional email. An empty draft email message is created automatically and its `draftEmailMessageId` is returned. Use the `POST /v1/email-messages/{emailMessageId}` endpoint along with the returned `draftEmailMessageContentRevisionId` to set subject, sender, preview text, and LMX content, then call `POST /v1/transactional-emails/{transactionalId}/publish` to publish the draft.",
        "x-mint": {
          "href": "/api-reference/create-transactional-email",
          "content": "This endpoint creates a transactional email and an empty draft email message in one step.\n\nUse the returned `draftEmailMessageId` and `draftEmailMessageContentRevisionId` when calling the [Update email message](/api-reference/update-email-message) endpoint to set subject, sender, preview text, and LMX content.\n\nCall [Publish transactional email draft](/api-reference/publish-transactional-email) to publish.",
          "metadata": {
            "sidebarTitle": "Create transactional",
            "description": "Create a new transactional email and its draft email message, ready for editing, previewing, and publishing through the Loops API."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTransactionalRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Transactional email created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalDraftResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or no sending domain configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional-emails/{transactionalId}": {
      "parameters": [
        {
          "name": "transactionalId",
          "in": "path",
          "required": true,
          "description": "The ID of the transactional email.",
          "schema": {
            "type": "string",
            "examples": ["cll42l54f20i1la0lfooe3z12"]
          }
        }
      ],
      "get": {
        "operationId": "getTransactionalEmail",
        "tags": ["Transactional emails"],
        "summary": "Get a transactional email",
        "description": "Retrieve a single transactional email by ID.",
        "x-mint": {
          "href": "/api-reference/get-transactional-email",
          "metadata": {
            "sidebarTitle": "Get transactional"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalResource"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `transactionalId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Transactional email not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateTransactionalEmail",
        "tags": ["Transactional emails"],
        "summary": "Update a transactional email",
        "description": "Update a transactional email by ID.",
        "x-mint": {
          "href": "/api-reference/update-transactional-email"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTransactionalRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transactional email updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalResource"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or `transactionalId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Transactional email not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional-emails/{transactionalId}/draft": {
      "parameters": [
        {
          "name": "transactionalId",
          "in": "path",
          "required": true,
          "description": "The ID of the transactional email.",
          "schema": {
            "type": "string",
            "examples": ["cll42l54f20i1la0lfooe3z12"]
          }
        }
      ],
      "post": {
        "operationId": "ensureTransactionalDraft",
        "tags": ["Transactional emails"],
        "summary": "Ensure a draft email message",
        "description": "Ensure the transactional email has a draft email message. If a draft already exists it is returned unchanged; otherwise a new empty draft is created (seeded from the most recent published version when present). Use `POST /v1/email-messages/{emailMessageId}` to edit the draft's content.",
        "x-mint": {
          "href": "/api-reference/ensure-transactional-draft",
          "content": "If a draft email message already exists, it is returned unchanged. Otherwise a new empty draft is created (seeded from the most recent published version when present).\n\nUse the returned `draftEmailMessageId` and `draftEmailMessageContentRevisionId` when calling [Update an email message](/api-reference/update-email-message) to edit the draft's content.",
          "metadata": {
            "title": "Ensure a transactional email has a draft",
            "sidebarTitle": "Ensure draft",
            "description": "Ensure a transactional email has a draft email message ready for editing, creating one from the published version if no draft currently exists."
          }
        },
        "responses": {
          "200": {
            "description": "Draft ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalDraftResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `transactionalId` or no sending domain configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Transactional email not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional-emails/{transactionalId}/publish": {
      "parameters": [
        {
          "name": "transactionalId",
          "in": "path",
          "required": true,
          "description": "The ID of the transactional email.",
          "schema": {
            "type": "string",
            "examples": ["cll42l54f20i1la0lfooe3z12"]
          }
        }
      ],
      "post": {
        "operationId": "publishTransactionalEmail",
        "tags": ["Transactional emails"],
        "summary": "Publish a transactional email draft",
        "description": "Publish the transactional email's current draft email message. The draft becomes the published version and the draft is cleared.",
        "x-mint": {
          "href": "/api-reference/publish-transactional-email",
          "content": "The transactional email's current draft email message is published. The draft becomes the published version and the draft is cleared.\n\nAfter publishing, use the returned `id` as `transactionalId` with [Send a transactional email](/api-reference/send-transactional-email) to send the email.",
          "metadata": {
            "title": "Publish a transactional email",
            "sidebarTitle": "Publish transactional"
          }
        },
        "responses": {
          "200": {
            "description": "Transactional email published.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalResource"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `transactionalId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Transactional email not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "409": {
            "description": "No draft to publish.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          },
          "422": {
            "description": "Draft failed validation, sending domain is not verified, or content was flagged as unsafe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionalFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional-groups": {
      "get": {
        "operationId": "listTransactionalGroups",
        "tags": ["Transactional groups"],
        "summary": "List transactional groups",
        "description": "Retrieve a paginated list of transactional groups, most recently created first.",
        "x-mint": {
          "href": "/api-reference/list-transactional-groups",
          "metadata": {
            "sidebarTitle": "List groups"
          }
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListGroupsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "createTransactionalGroup",
        "tags": ["Transactional groups"],
        "summary": "Create a transactional group",
        "description": "Create a new transactional group.",
        "x-mint": {
          "href": "/api-reference/create-transactional-group",
          "metadata": {
            "sidebarTitle": "Create a group"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transactional group created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or reserved group name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/transactional-groups/{transactionalGroupId}": {
      "parameters": [
        {
          "name": "transactionalGroupId",
          "in": "path",
          "required": true,
          "description": "The ID of the transactional group.",
          "schema": {
            "type": "string",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          }
        }
      ],
      "get": {
        "operationId": "getTransactionalGroup",
        "tags": ["Transactional groups"],
        "summary": "Get a transactional group",
        "description": "Retrieve a single transactional group by ID.",
        "x-mint": {
          "href": "/api-reference/get-transactional-group",
          "metadata": {
            "sidebarTitle": "Get a group"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `transactionalGroupId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Transactional group not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "operationId": "updateTransactionalGroup",
        "tags": ["Transactional groups"],
        "summary": "Update a transactional group",
        "description": "Update a transactional group's name or description. At least one field must be provided. The reserved \"Unsorted\" group cannot be edited.",
        "x-mint": {
          "href": "/api-reference/update-transactional-group",
          "content": "<Info>At least one field must be provided. The reserved \"Unsorted\" group cannot be edited.</Info>",
          "metadata": {
            "sidebarTitle": "Update a group"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transactional group updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, reserved group name, or the Unsorted group cannot be edited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Transactional group not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/uploads": {
      "post": {
        "operationId": "createUpload",
        "tags": ["Uploads"],
        "summary": "Create an upload",
        "description": "Request a pre-signed URL to upload an image asset. Upload the file with an HTTP `PUT` to the returned `presignedUrl` (sending the same `Content-Type` and `Content-Length`), then call `/uploads/{emailAssetId}/complete` to finalize the asset.",
        "x-mint": {
          "href": "/api-reference/create-upload",
          "content": "Request a pre-signed URL to upload an image asset. Upload the file with an HTTP `PUT` to the returned `presignedUrl` (sending the same `Content-Type` and `Content-Length`), then call [Complete an upload](/api-reference/complete-upload) to finalize the asset.",
          "metadata": {
            "description": "Request a pre-signed URL to upload an image asset.",
            "sidebarTitle": "Create an upload"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUploadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pre-signed upload URL created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateUploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or unsupported `contentType`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "413": {
            "description": "Upload exceeds the maximum allowed size.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/uploads/{emailAssetId}/complete": {
      "parameters": [
        {
          "name": "emailAssetId",
          "in": "path",
          "required": true,
          "description": "The `emailAssetId` returned when the upload was created via `POST /v1/uploads`.",
          "schema": {
            "type": "string",
            "examples": ["cla3s5s7e9t1i3d5f7g9h1j3"]
          }
        }
      ],
      "post": {
        "operationId": "completeUpload",
        "tags": ["Uploads"],
        "summary": "Complete an upload",
        "description": "Finalize an image upload after the file has been uploaded to the pre-signed URL. Returns the public URL of the uploaded image asset.",
        "x-mint": {
          "href": "/api-reference/complete-upload",
          "metadata": {
            "description": "Finalize an image upload after the file has been uploaded to the pre-signed URL."
          }
        },
        "responses": {
          "200": {
            "description": "Upload completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompleteUploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "Upload id is missing or the uploaded file has an unsupported content type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key or content API not enabled for this team."
          },
          "404": {
            "description": "Upload not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "429": {
            "description": "Upload limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadLimitExceededFailureResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/workflows": {
      "get": {
        "tags": ["Workflows"],
        "summary": "List workflows",
        "operationId": "listWorkflows",
        "description": "Retrieve a paginated list of workflows.",
        "x-mint": {
          "href": "/api-reference/list-workflows"
        },
        "parameters": [
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "How many results to return in each request. Must be between 10 and 50. Default is 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListWorkflowsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `perPage` or `cursor` value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      },
      "post": {
        "tags": ["Workflows"],
        "summary": "Create a workflow",
        "operationId": "createWorkflow",
        "description": "Create a draft workflow with a blank trigger and exit node.",
        "x-mint": {
          "href": "/api-reference/create-workflow"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkflowRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Workflow created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimplifiedWorkflow"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "500": {
            "description": "Workflow creation is unavailable for this team.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/workflows/{workflowId}": {
      "parameters": [
        {
          "name": "workflowId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow.",
          "schema": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          }
        }
      ],
      "get": {
        "tags": ["Workflows"],
        "summary": "Get a workflow",
        "operationId": "getWorkflow",
        "description": "Retrieve a workflow graph with node type names, connections, and selected display fields.",
        "x-mint": {
          "content": "Returns a simplified view of the workflow graph. Each node includes its `typeName`, outgoing connections in `nextNodeIds`, and selected display fields. Use [Get a workflow node](/api-reference/get-workflow-node) to retrieve full details for a single node.",
          "href": "/api-reference/get-workflow"
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimplifiedWorkflow"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      },
      "post": {
        "tags": ["Workflows"],
        "summary": "Update a workflow",
        "operationId": "updateWorkflowProperties",
        "description": "Update a workflow's display properties. At least one property must be provided. To change the workflow's mailing list, use the `POST /v1/workflows/{workflowId}/mailing-list` endpoint instead.",
        "x-mint": {
          "href": "/api-reference/update-workflow",
          "content": "<Info>To change a workflow's mailing list, use the [Change workflow mailing list](/api-reference/change-workflow-mailing-list) endpoint instead. This is because changing mailing lists may remove queued contacts from the workflow.</Info>",
          "metadata": {
            "description": "Update a workflow's display properties."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkflowPropertiesRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Workflow properties updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimplifiedWorkflow"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId` or request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/workflows/{workflowId}/mailing-list": {
      "parameters": [
        {
          "name": "workflowId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow.",
          "schema": { "type": "string" }
        }
      ],
      "post": {
        "tags": ["Workflows"],
        "summary": "Change workflow mailing list",
        "operationId": "changeWorkflowMailingList",
        "description": "Dry run or apply a workflow mailing list change. If queued contacts would be removed from the workflow due to the change of mailing list, Loops returns with `\"status\": \"queuedContactsFound\"` instead of applying the change. Retry with `queuedContactPolicy: \"discard\"` to apply the change and discard those contacts.",
        "x-mint": {
          "href": "/api-reference/change-workflow-mailing-list",
          "content": "Use this endpoint to change a workflow's mailing list.\n\nMake a dry run request using `dryRun: true`.\n\nIf queued contacts would be removed from the workflow due to the change of mailing list, Loops returns with `\"status\": \"queuedContactsFound\"` instead of applying the change. Retry with `queuedContactPolicy: \"discard\"` to apply the change and discard those contacts.",
          "metadata": {
            "sidebarTitle": "Change mailing list",
            "description": "Change a workflow's mailing list."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangeWorkflowMailingListRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Mailing-list dry run, queued-contact warning, or update result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangeWorkflowMailingListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId`, request body, mailing list, or workflow state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/workflows/{workflowId}/nodes": {
      "parameters": [
        {
          "name": "workflowId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow.",
          "schema": { "type": "string" }
        }
      ],
      "post": {
        "tags": ["Workflow nodes"],
        "summary": "Create a workflow node",
        "operationId": "createWorkflowNode",
        "description": "Create a new default workflow node and return it with the latest workflow.\n\nChoose where the node goes with `insertMode`: `between` places it between an existing `fromNodeId` -> `toNodeId` connection, and `before` places it before `beforeNodeId`.\n\nNew nodes start with default settings; update the node after creation to configure it. Branch nodes create their default paths too: `BranchNode` creates two `AudienceFilter` children, and `ExperimentBranchNode` creates two regular `VariantNode` children plus one control `VariantNode`. Public workflows can have up to 300 nodes. Generated children count toward that limit, so a normal create adds 1 node, `BranchNode` adds 3, and `ExperimentBranchNode` adds 4. To add a sibling child path to a branch or experiment branch, use the `POST /v1/workflows/{workflowId}/nodes/{nodeId}/add-branch` endpoint. Branch paths can be edited with create-node, but a workflow cannot be started unless each direct `BranchNode` child is an `AudienceFilter`. For experiments, use create-node only to insert a missing `VariantNode` before non-variant content; use add-branch for another variant path.",
        "x-mint": {
          "href": "/api-reference/create-workflow-node",
          "content": "Choose where the node goes with `insertMode`:\n- `between` places it between an existing `fromNodeId` -> `toNodeId` connection\n- `before` places it before `beforeNodeId`.\n\nNew nodes start with default settings; update the node after creation to configure it. Branch nodes create their default paths too: `BranchNode` creates two `AudienceFilter` children, and `ExperimentBranchNode` creates two regular `VariantNode` children plus one control `VariantNode`.\n\nPublic workflows can have up to 300 nodes. Generated children count toward that limit, so a normal create adds 1 node, `BranchNode` adds 3, and `ExperimentBranchNode` adds 4. To add a sibling child path to a branch or experiment branch, use the `POST /v1/workflows/{workflowId}/nodes/{nodeId}/add-branch` endpoint. Branch paths can be edited with create-node, but a workflow cannot be started unless each direct `BranchNode` child is an `AudienceFilter`. For experiments, use create-node only to insert a missing `VariantNode` before non-variant content; use add-branch for another variant path.",
          "metadata": {
            "sidebarTitle": "Create a node",
            "description": "Create a new default workflow node and return it with the latest workflow"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkflowNodeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Workflow node created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateWorkflowNodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request. Details will be shown in `message`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow or workflow node not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/workflows/{workflowId}/nodes/{nodeId}/add-branch": {
      "parameters": [
        {
          "name": "workflowId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow.",
          "schema": { "type": "string" }
        },
        {
          "name": "nodeId",
          "in": "path",
          "required": true,
          "description": "The ID of the BranchNode or ExperimentBranchNode that should receive one new child.",
          "schema": { "type": "string" }
        }
      ],
      "post": {
        "tags": ["Workflow nodes"],
        "summary": "Add a branch",
        "operationId": "addWorkflowBranch",
        "description": "Add a branch and a child node under an existing Branch or Experiment node. Returns the created child node plus the latest workflow.\n\n- Adding a branch to a `BranchNode` creates one `AudienceFilter` child node.\n- Adding a branch to an `ExperimentBranchNode` creates one `VariantNode` child node.\n\nThis endpoint does not accept node configuration fields; update the child node with `POST /v1/workflows/{workflowId}/nodes/{nodeId}` after creation. Public workflows are limited to 300 nodes, and this endpoint adds 1 node.",
        "x-mint": {
          "href": "/api-reference/add-workflow-branch",
          "content": "Adding a branch to a `BranchNode` creates one `AudienceFilter` child node.\nAdding a branch to an `ExperimentBranchNode` creates one `VariantNode` child node.\n\nThis endpoint does not accept node configuration fields; [update the child node](/api-reference/update-workflow-node) after creation. Public workflows are limited to 300 nodes, and this endpoint adds 1 node.",
          "metadata": {
            "sidebarTitle": "Add a branch",
            "description": "Add a branch and a child node under an existing Branch or Experiment node."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddWorkflowBranchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Branch added.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddWorkflowBranchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId`, `nodeId`, request body, branch target, workflow state, or workflow node cap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow or workflow node not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/workflows/{workflowId}/nodes/{nodeId}": {
      "parameters": [
        {
          "name": "workflowId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow.",
          "schema": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          }
        },
        {
          "name": "nodeId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow node.",
          "schema": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          }
        }
      ],
      "get": {
        "tags": ["Workflow nodes"],
        "summary": "Get a workflow node",
        "operationId": "getWorkflowNode",
        "description": "Retrieve detailed data for a single workflow node.",
        "x-mint": {
          "href": "/api-reference/get-workflow-node",
          "metadata": {
            "sidebarTitle": "Get a node"
          }
        },
        "responses": {
          "200": {
            "description": "Successful.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowNodeWithRevision"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId` or `nodeId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow or workflow node not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      },
      "post": {
        "tags": ["Workflow nodes"],
        "summary": "Update a workflow node",
        "operationId": "updateWorkflowNode",
        "description": "Update workflow-node-owned fields for a single node. Shared resources such as email messages and audience segments should be updated through their own APIs.",
        "x-mint": {
          "href": "/api-reference/update-workflow-node",
          "content": "Shared resources such as email messages and audience segments should be updated through their own APIs.",
          "metadata": {
            "sidebarTitle": "Update a node",
            "description": "Update workflow-node-owned fields for a single node."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkflowNodeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Workflow node updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateWorkflowNodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId`, `nodeId`, request body, or node update.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow or workflow node not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          },
          "501": {
            "description": "This node update is not implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          }
        },
        "security": [{ "apiKey": [] }]
      },
      "delete": {
        "tags": ["Workflow nodes"],
        "summary": "Delete a workflow node",
        "operationId": "deleteWorkflowNode",
        "description": "Delete a single workflow node. If contacts are queued at the node, Loops returns with `\"status\": \"queuedContactsFound\"` instead of deleting. Retry with `queuedContactPolicy: \"discard\"` to delete the node and discard those queued contacts.",
        "x-mint": {
          "href": "/api-reference/delete-workflow-node",
          "content": "Delete a node from a workflow.\n\nMake a dry run request using `dryRun: true`.\n\nIf contacts are queued at the node, Loops returns with `\"status\": \"queuedContactsFound\"` instead of deleting. Retry with `queuedContactPolicy: \"discard\"` to delete the node and discard those queued contacts.",
          "metadata": {
            "sidebarTitle": "Delete a node",
            "description": "Delete a single workflow node."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteWorkflowNodeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delete dry run, queued-contact warning, or deletion result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteWorkflowNodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId`, `nodeId`, request body, or delete target.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow or workflow node not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    },
    "/v1/workflows/{workflowId}/nodes/{nodeId}/recursive": {
      "parameters": [
        {
          "name": "workflowId",
          "in": "path",
          "required": true,
          "description": "The ID of the workflow.",
          "schema": { "type": "string" }
        },
        {
          "name": "nodeId",
          "in": "path",
          "required": true,
          "description": "The root node ID of the subtree to delete.",
          "schema": { "type": "string" }
        }
      ],
      "delete": {
        "tags": ["Workflow nodes"],
        "summary": "Delete workflow nodes recursively",
        "operationId": "deleteWorkflowNodeRecursively",
        "description": "Delete a node and its downstream subtree. If contacts are queued at any node that would be deleted, Loops returns with `\"status\": \"queuedContactsFound\"` instead of deleting. Retry with `queuedContactPolicy: \"discard\"` to delete the nodes and discard those queued contacts.",
        "x-mint": {
          "href": "/api-reference/delete-workflow-nodes",
          "content": "Delete a node and its downstream subtree.\n\nMake a dry run request using `dryRun: true`.\n\nIf contacts are queued at any node that would be deleted, Loops returns with `\"status\": \"queuedContactsFound\"` instead of deleting. Retry with `queuedContactPolicy: \"discard\"` to delete the nodes and discard those queued contacts.",
          "metadata": {
            "sidebarTitle": "Delete nodes",
            "description": "Delete a node and its downstream subtree."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteWorkflowNodeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delete dry run, queued-contact warning, or deletion result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteWorkflowNodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `workflowId`, `nodeId`, request body, or delete target.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key."
          },
          "404": {
            "description": "Workflow or workflow node not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "409": {
            "description": "`expectedRevisionId` is stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowFailureResponse"
                }
              }
            }
          },
          "405": {
            "description": "Wrong HTTP request method."
          }
        },
        "security": [{ "apiKey": [] }]
      }
    }
  },
  "webhooks": {
    "contactUnsubscribed": {
      "post": {
        "operationId": "webhookContactUnsubscribed",
        "summary": "Contact unsubscribed",
        "description": "Sent when a contact is unsubscribed from your audience, or when a contact is deleted from your audience (alongside `contact.deleted`). This is not the same as a contact unsubscribing from a mailing list (see `contact.mailingList.unsubscribed`). Contains a `contactIdentity` object.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookContactUnsubscribedPayload"
              },
              "example": {
                "eventName": "contact.unsubscribed",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "contactCreated": {
      "post": {
        "operationId": "webhookContactCreated",
        "summary": "Contact created",
        "description": "Sent when a new contact is created in your audience. Contains a `contactIdentity` object and a full `contact` object with all of the new contact's properties (including custom properties). When double opt-in is enabled, contact webhooks do not fire until the contact is confirmed; `contact.created` only fires for form-created contacts once they confirm their subscription. `optInStatus` will never be `\"pending\"` or `\"rejected\"` for this event.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookContactCreatedPayload"
              },
              "example": {
                "eventName": "contact.created",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4itta800003ow9hhekzk94o",
                  "email": "test+5@loops.so",
                  "userId": null
                },
                "contact": {
                  "id": "cm4itta800003ow9hhekzk94o",
                  "email": "test+5@loops.so",
                  "firstName": null,
                  "lastName": null,
                  "source": "API",
                  "subscribed": true,
                  "userGroup": "",
                  "userId": null,
                  "mailingLists": {
                    "cm4ittp2k000l12j3lgrzvlxt": true
                  },
                  "optInStatus": "accepted",
                  "favoriteColor": "blue",
                  "favoriteNumber": 42
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "contactDeleted": {
      "post": {
        "operationId": "webhookContactDeleted",
        "summary": "Contact deleted",
        "description": "Sent when a contact is deleted from your audience. Contains a `contactIdentity` object.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookContactDeletedPayload"
              },
              "example": {
                "eventName": "contact.deleted",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "contactMailingListSubscribed": {
      "post": {
        "operationId": "webhookContactMailingListSubscribed",
        "summary": "Contact subscribed to mailing list",
        "description": "Sent when a contact is subscribed to a mailing list. Contains `contactIdentity` and `mailingList` objects. When double opt-in is enabled, this event only fires after the contact confirms their subscription.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookContactMailingListSubscribedPayload"
              },
              "example": {
                "eventName": "contact.mailingList.subscribed",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                },
                "mailingList": {
                  "id": "cm4ittp2k000l12j3lgrzvlxt",
                  "name": "test mailing list",
                  "description": null,
                  "isPublic": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "contactMailingListUnsubscribed": {
      "post": {
        "operationId": "webhookContactMailingListUnsubscribed",
        "summary": "Contact unsubscribed from mailing list",
        "description": "Sent when a contact is unsubscribed from a mailing list. This is not the same as a contact unsubscribing from your audience (see `contact.unsubscribed`). Contains `contactIdentity` and `mailingList` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookContactMailingListUnsubscribedPayload"
              },
              "example": {
                "eventName": "contact.mailingList.unsubscribed",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                },
                "mailingList": {
                  "id": "cm4ittp2k000l12j3lgrzvlxt",
                  "name": "test mailing list",
                  "description": null,
                  "isPublic": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "transactionalEmailSent": {
      "post": {
        "operationId": "webhookTransactionalEmailSent",
        "summary": "Transactional email sent",
        "description": "Sent when a transactional email is sent to a contact. Contains a `transactionalId` value plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookTransactionalEmailSentPayload"
              },
              "example": {
                "eventName": "transactional.email.sent",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                },
                "transactionalId": "cm4t1suns001uw6atri87v54s",
                "transactionalName": "Test Transactional",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "campaignEmailSent": {
      "post": {
        "operationId": "webhookCampaignEmailSent",
        "summary": "Campaign email sent",
        "description": "Sent when a campaign email is sent to a contact. This event fires for every campaign send (for example, sending to 1,000 contacts produces 1,000 events). Contains `campaignId` and `campaignName` plus `contactIdentity` and `email` objects. If the campaign was sent to one or more mailing lists, a `mailingLists` array is also included.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCampaignEmailSentPayload"
              },
              "example": {
                "eventName": "campaign.email.sent",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                },
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "campaignName": "Test Campaign",
                "email": {
                  "id": "cm4t1sv84004yje79hawr1fi1",
                  "emailMessageId": "cm4t1suns001ww6atotin3bn1",
                  "subject": "Test Subject"
                },
                "mailingLists": [
                  {
                    "id": "cm4ittp2k000l12j3lgrzvlxt",
                    "name": "test mailing list",
                    "description": null,
                    "isPublic": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "loopEmailSent": {
      "post": {
        "operationId": "webhookLoopEmailSent",
        "summary": "Loop email sent",
        "description": "Sent when a workflow email is sent to a contact. This event keeps its `loop` naming for compatibility (Loops was renamed to Workflows on May 6, 2026). This event fires for every contact in a workflow (for example, 1,000 recipients produces 1,000 events). Contains `loopId` and `loopName` plus `contactIdentity` and `email` objects. If the workflow was sent to one or more mailing lists, a `mailingLists` array is also included.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookLoopEmailSentPayload"
              },
              "example": {
                "eventName": "loop.email.sent",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                },
                "loopId": "cm4t1snfj0052icemfshgqfcw",
                "loopName": "Test Loop",
                "email": {
                  "id": "cm4t1socj004mje79e61mgh7d",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "mailingLists": [
                  {
                    "id": "cm4ittp2k000l12j3lgrzvlxt",
                    "name": "test mailing list",
                    "description": null,
                    "isPublic": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailDelivered": {
      "post": {
        "operationId": "webhookEmailDelivered",
        "summary": "Email delivered",
        "description": "Sent when an email is delivered to its recipient. Contains `sourceType` (`campaign`, `loop`, or `transactional`) and the related `campaignId`, `loopId` (workflow ID), or `transactionalId`, plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailDeliveredPayload"
              },
              "example": {
                "eventName": "email.delivered",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailSoftBounced": {
      "post": {
        "operationId": "webhookEmailSoftBounced",
        "summary": "Email soft bounced",
        "description": "Sent when an email soft bounces. Soft bounces are temporary delivery failures (for example, a connection timing out). Soft bounces are retried multiple times and the email may still be delivered. Contains `sourceType` and the related `campaignId`, `loopId` (workflow ID), or `transactionalId`, plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailSoftBouncedPayload"
              },
              "example": {
                "eventName": "email.softBounced",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailHardBounced": {
      "post": {
        "operationId": "webhookEmailHardBounced",
        "summary": "Email hard bounced",
        "description": "Sent when an email hard bounces. Hard bounces are persistent delivery failures (for example, a mailbox that does not exist); the email will not be delivered. In Loops, a hard bounce also unsubscribes the contact from your audience, so a `contact.unsubscribed` event will also be sent. Contains `sourceType` and the related `campaignId`, `loopId` (workflow ID), or `transactionalId`, plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailHardBouncedPayload"
              },
              "example": {
                "eventName": "email.hardBounced",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "9874cm4t1sseg004tje7982991nan8732843",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailClicked": {
      "post": {
        "operationId": "webhookEmailClicked",
        "summary": "Email clicked",
        "description": "Sent when a link in a campaign or workflow email is clicked. Not available for transactional emails because link clicks are not tracked for transactional emails. Contains `sourceType` and the related `campaignId` or `loopId` (workflow ID), plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailClickedPayload"
              },
              "example": {
                "eventName": "email.clicked",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailUnsubscribed": {
      "post": {
        "operationId": "webhookEmailUnsubscribed",
        "summary": "Email unsubscribed",
        "description": "Sent when a recipient unsubscribes from marketing email or a mailing list using an email's \"Unsubscribe\" link. A `contact.unsubscribed` or `contact.mailingList.unsubscribed` event will also be sent depending on whether the email was sent to a mailing list. Not available for transactional emails because unsubscribe links are not included for transactional emails. Contains `sourceType` and the related `campaignId` or `loopId` (workflow ID), plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailUnsubscribedPayload"
              },
              "example": {
                "eventName": "email.unsubscribed",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailResubscribed": {
      "post": {
        "operationId": "webhookEmailResubscribed",
        "summary": "Email resubscribed",
        "description": "Sent when a recipient resubscribes to marketing email from an email's preference center (\"Unsubscribe\" link). Not available for transactional emails because unsubscribe links are not included for transactional emails. Contains `sourceType` and the related `campaignId` or `loopId` (workflow ID), plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailResubscribedPayload"
              },
              "example": {
                "eventName": "email.resubscribed",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailOpened": {
      "post": {
        "operationId": "webhookEmailOpened",
        "summary": "Email opened",
        "description": "Sent when a campaign or workflow email is opened. Not available for transactional emails because email opens are not tracked for transactional emails. Contains `sourceType` and the related `campaignId` or `loopId` (workflow ID), plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailOpenedPayload"
              },
              "example": {
                "eventName": "email.opened",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "emailSpamReported": {
      "post": {
        "operationId": "webhookEmailSpamReported",
        "summary": "Email spam reported",
        "description": "Sent when a recipient reports your email as spam. Contains `sourceType` and the related `campaignId`, `loopId` (workflow ID), or `transactionalId`, plus `contactIdentity` and `email` objects.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEmailSpamReportedPayload"
              },
              "example": {
                "eventName": "email.spamReported",
                "eventTime": 1734425918,
                "webhookSchemaVersion": "1.0.0",
                "sourceType": "campaign",
                "campaignId": "cm4t1suns001uw6atri87v54s",
                "email": {
                  "id": "cm4t1sseg004tje7982991nan",
                  "emailMessageId": "cm4ittv1v001oow9hruou8na8",
                  "subject": "Subject of the email"
                },
                "contactIdentity": {
                  "id": "cm4ittmhq0011ow9h6fb460yw",
                  "email": "test@example.com",
                  "userId": null
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    },
    "testingTestEvent": {
      "post": {
        "operationId": "webhookTestingTestEvent",
        "summary": "Test event",
        "description": "Test event that can be triggered from the Webhooks settings page in Loops. Use this to verify that your endpoint is working and that your signature verification code is correct. The payload contains `eventName`, `eventTime`, `message` (always `\"test\"`), and `webhookSchemaVersion`.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookTestingTestEventPayload"
              },
              "example": {
                "eventName": "testing.testEvent",
                "eventTime": 1734425918,
                "message": "test",
                "webhookSchemaVersion": "1.0.0"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received successfully. Return any 2xx status code to acknowledge delivery."
          }
        },
        "security": []
      }
    }
  },
  "components": {
    "schemas": {
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The contact's Loops ID.",
            "examples": ["clh3k9m2p4q6r8s0t2v4x6z8"]
          },
          "email": {
            "type": "string",
            "description": "The contact's email address.",
            "examples": ["alex@company.com"]
          },
          "firstName": {
            "type": ["string", "null"],
            "description": "The contact's first name.",
            "examples": ["Alex"]
          },
          "lastName": {
            "type": ["string", "null"],
            "description": "The contact's last name.",
            "examples": ["Rivera"]
          },
          "source": {
            "type": "string",
            "description": "The source the contact was created from.",
            "examples": ["API"]
          },
          "subscribed": {
            "type": "boolean",
            "description": "Whether the contact will receive campaign and workflow emails.",
            "examples": [true]
          },
          "userGroup": {
            "type": "string",
            "description": "The contact's user group.",
            "examples": ["customers"]
          },
          "userId": {
            "type": ["string", "null"],
            "description": "The contact's unique user ID.",
            "examples": ["usr_7f8e9d0c1b2a"]
          },
          "mailingLists": {
            "type": "object",
            "description": "Mailing lists the contact is subscribed to, represented by key-value pairs of mailing list IDs and `true`.",
            "examples": [
              {
                "cm06f5v0e45nf0ml5754o9cix": true
              }
            ]
          },
          "optInStatus": {
            "type": ["string", "null"],
            "description": "Double opt-in status. This will be `null` for contacts unless they are created via a form while double opt-in is enabled.",
            "enum": ["accepted", "pending", "rejected", null],
            "examples": ["accepted"]
          }
        },
        "examples": [
          {
            "id": "clh3k9m2p4q6r8s0t2v4x6z8",
            "email": "alex@company.com",
            "firstName": "Alex",
            "lastName": "Rivera",
            "source": "API",
            "subscribed": true,
            "userGroup": "customers",
            "userId": "usr_7f8e9d0c1b2a",
            "mailingLists": {
              "clm2k8j4h6g0f8d6s4a2b0z8": true
            },
            "optInStatus": "accepted"
          }
        ]
      },
      "ContactFields": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "examples": ["alex@company.com"],
            "description": "The contact's email address."
          },
          "firstName": {
            "type": "string",
            "description": "The contact's first name.",
            "examples": ["Alex"]
          },
          "lastName": {
            "type": "string",
            "description": "The contact's last name.",
            "examples": ["Rivera"]
          },
          "source": {
            "type": "string",
            "description": "A custom source value to replace the default “API”.",
            "examples": ["API"]
          },
          "subscribed": {
            "type": "boolean",
            "description": "Whether the contact will receive campaign and workflow emails. All new contacts are subscribed by default."
          },
          "userGroup": {
            "type": "string",
            "description": "The contact's user group.",
            "examples": ["customers"]
          },
          "userId": {
            "type": "string",
            "description": "A unique user ID (for example, from an external application).",
            "examples": ["usr_7f8e9d0c1b2a"]
          },
          "mailingLists": {
            "$ref": "#/components/schemas/MailingListSubscriptions"
          }
        },
        "additionalProperties": {
          "oneOf": [
            { "type": "string" },
            { "type": "number" },
            { "type": "boolean" }
          ]
        },
        "examples": [
          {
            "email": "alex@company.com",
            "firstName": "Alex",
            "lastName": "Rivera",
            "subscribed": true,
            "userGroup": "customers",
            "userId": "usr_7f8e9d0c1b2a",
            "mailingLists": {
              "clm2k8j4h6g0f8d6s4a2b0z8": true
            },
            "favoriteColor": "blue"
          }
        ]
      },
      "ContactRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/ContactFields" },
          { "type": "object", "required": ["email"] }
        ]
      },
      "ContactUpdateRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/ContactFields" },
          {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "description": "The contact's email address. **Required if `userId` is not provided.**"
              },
              "subscribed": {
                "type": "boolean",
                "description": "Whether the contact will receive campaign and workflow emails. We recommend leaving this field out of your update requests unless you specifically want to unsubscribe (`false`) or re-subscribe (`true`) a contact. All new contacts are subscribed by default."
              },
              "userId": {
                "type": "string",
                "description": "The contact's unique user ID. **Required if `email` is not provided.**"
              }
            },
            "anyOf": [{ "required": ["email"] }, { "required": ["userId"] }]
          }
        ],
        "additionalProperties": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            },
            {
              "type": "boolean"
            }
          ]
        },
        "examples": [
          {
            "email": "alex@company.com",
            "firstName": "Alex",
            "lastName": "Rivera",
            "subscribed": true,
            "userGroup": "customers",
            "userId": "usr_7f8e9d0c1b2a",
            "mailingLists": {
              "clm2k8j4h6g0f8d6s4a2b0z8": true
            },
            "favoriteColor": "blue"
          }
        ]
      },
      "ContactSuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [true]
          },
          "id": {
            "type": "string",
            "examples": ["clh3k9m2p4q6r8s0t2v4x6z8"]
          }
        },
        "required": ["success", "id"],
        "examples": [
          {
            "success": true,
            "id": "clh3k9m2p4q6r8s0t2v4x6z8"
          }
        ]
      },
      "ContactFailureResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string",
            "examples": ["Invalid email address."]
          }
        },
        "required": ["success", "message"],
        "examples": [
          {
            "success": false,
            "message": "Invalid email address."
          }
        ]
      },
      "ContactDeleteRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "examples": ["alex@company.com"]
          },
          "userId": {
            "type": "string",
            "examples": ["usr_7f8e9d0c1b2a"]
          }
        },
        "required": ["email", "userId"],
        "examples": [
          {
            "email": "alex@company.com",
            "userId": "usr_7f8e9d0c1b2a"
          }
        ]
      },
      "ContactDeleteResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [true]
          },
          "message": {
            "type": "string",
            "examples": ["Contact deleted."]
          }
        },
        "required": ["success", "message"]
      },
      "ContactSuppressionStatusResponse": {
        "type": "object",
        "properties": {
          "contact": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "The contact's Loops ID."
              },
              "email": {
                "type": "string",
                "description": "The contact's email address."
              },
              "userId": {
                "type": ["string", "null"],
                "description": "The contact's unique user ID."
              }
            },
            "required": ["id", "email", "userId"]
          },
          "isSuppressed": {
            "type": "boolean",
            "description": "Whether the contact is suppressed."
          },
          "removalQuota": {
            "$ref": "#/components/schemas/ContactSuppressionRemovalQuota",
            "description": "The removal quota for the contact."
          }
        },
        "required": ["contact", "isSuppressed", "removalQuota"],
        "examples": [
          {
            "contact": {
              "id": "clh3k9m2p4q6r8s0t2v4x6z8",
              "email": "alex@company.com",
              "userId": "usr_7f8e9d0c1b2a"
            },
            "isSuppressed": false,
            "removalQuota": {
              "limit": 5,
              "remaining": 5
            }
          }
        ]
      },
      "ContactSuppressionRemoveResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the suppression removal was successful.",
            "examples": [true]
          },
          "message": {
            "type": "string",
            "examples": ["Email removed from suppression list."]
          },
          "removalQuota": {
            "$ref": "#/components/schemas/ContactSuppressionRemovalQuota"
          }
        },
        "required": ["success", "message", "removalQuota"]
      },
      "ContactSuppressionRemovalQuota": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "number",
            "description": "The number of suppression removals allowed in a rolling 30 day period.",
            "examples": [100]
          },
          "remaining": {
            "type": "number",
            "description": "The remaining number of suppression removals left in the current 30 day period.",
            "examples": [10]
          }
        },
        "required": ["limit", "remaining"]
      },
      "ContactPropertyCreateRequest": {
        "type": "object",
        "required": ["name", "type"],
        "description": "There are a few [reserved names](https://loops.so/docs/contacts/properties#reserved-names) that you cannot use for contact properties.",
        "properties": {
          "name": {
            "type": "string",
            "examples": ["favoriteColor"],
            "description": "The name of the property. This should be in camelCase, like `planName` or `importDate`."
          },
          "type": {
            "type": "string",
            "examples": ["string"],
            "description": "The type of property.",
            "enum": ["string", "number", "boolean", "date"]
          }
        },
        "examples": [
          {
            "name": "favoriteColor",
            "type": "string"
          }
        ]
      },
      "ContactPropertySuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [true]
          }
        },
        "required": ["success"]
      },
      "ContactPropertyFailureResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string",
            "examples": ["Property already exists."]
          }
        },
        "required": ["success", "message"],
        "examples": [
          {
            "success": false,
            "message": "Property already exists."
          }
        ]
      },
      "EventRequest": {
        "type": "object",
        "required": ["eventName"],
        "anyOf": [{ "required": ["email"] }, { "required": ["userId"] }],
        "properties": {
          "email": {
            "type": "string",
            "description": "The contact's email address. **Required if `userId` is not provided.**",
            "examples": ["alex@company.com"]
          },
          "userId": {
            "type": "string",
            "description": "The contact's unique user ID. **Required if `email` is not provided.**",
            "examples": ["usr_7f8e9d0c1b2a"]
          },
          "eventName": {
            "type": "string",
            "description": "The name of the event.",
            "examples": ["signup"]
          },
          "eventProperties": {
            "type": "object",
            "description": "An object containing event property data for the event, available in emails sent by the event.",
            "examples": [
              {
                "planName": "Pro",
                "importDate": "2021-01-01"
              }
            ]
          },
          "mailingLists": {
            "$ref": "#/components/schemas/MailingListSubscriptions"
          }
        },
        "additionalProperties": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            },
            {
              "type": "boolean"
            }
          ]
        },
        "examples": [
          {
            "email": "alex@company.com",
            "userId": "usr_7f8e9d0c1b2a",
            "eventName": "signup",
            "eventProperties": {
              "plan": "pro"
            },
            "mailingLists": {
              "clm2k8j4h6g0f8d6s4a2b0z8": true
            }
          }
        ]
      },
      "EventSuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [true]
          }
        },
        "required": ["success"]
      },
      "EventFailureResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string",
            "examples": ["Contact not found."]
          }
        },
        "required": ["success", "message"],
        "examples": [
          {
            "success": false,
            "message": "Contact not found."
          }
        ]
      },
      "TransactionalRequest": {
        "type": "object",
        "required": ["email", "transactionalId"],
        "properties": {
          "email": {
            "type": "string",
            "examples": ["alex@company.com"],
            "description": "The recipient's email address."
          },
          "transactionalId": {
            "type": "string",
            "description": "The ID of the transactional email to send.",
            "examples": ["cll42l54f20i1la0lfooe3z12"]
          },
          "addToAudience": {
            "type": "boolean",
            "description": "If `true`, a contact will be created in your audience using the `email` value (if a matching contact doesn't already exist).",
            "examples": [true]
          },
          "dataVariables": {
            "type": "object",
            "description": "An object containing data as defined by the data variables added to the transactional email template. Values can be of type string or number.\n\nIf you have added optional data variables to your email, you can exclude them from the dataVariables object or set the value to \"\".\n\nIf you have added an array data variable to your email, make sure to include an array matching the data variables you added to your array block.",
            "examples": [
              {
                "name": "Chris",
                "passwordResetLink": "https://example.com/reset-password"
              }
            ]
          },
          "attachments": {
            "type": "array",
            "description": "A list containing file objects to be sent along with an email message. Attachments must be enabled by Loops support before they can be used with the API.",
            "items": {
              "type": "object",
              "required": ["filename", "contentType", "data"],
              "properties": {
                "filename": {
                  "type": "string",
                  "description": "The name of the file, shown in email clients."
                },
                "contentType": {
                  "type": "string",
                  "description": "The MIME type of the file."
                },
                "data": {
                  "type": "string",
                  "description": "The base64-encoded content of the file."
                }
              }
            }
          }
        },
        "examples": [
          {
            "email": "alex@company.com",
            "transactionalId": "cll42l54f20i1la0lfooe3z12",
            "addToAudience": true,
            "dataVariables": {
              "name": "Alex",
              "passwordResetLink": "https://app.company.com/reset/abc123"
            }
          }
        ]
      },
      "TransactionalSuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [true]
          }
        },
        "required": ["success"]
      },
      "TransactionalFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "examples": ["Transactional email not found."]
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Transactional email not found."
          }
        ]
      },
      "TransactionalSendFailureResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string",
            "examples": ["Missing required data variable(s): confirmationUrl"]
          }
        },
        "required": ["success", "message"],
        "examples": [
          {
            "success": false,
            "message": "Missing required data variable(s): confirmationUrl"
          }
        ]
      },
      "TransactionalFailure2Response": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string"
          },
          "path": {
            "type": "string"
          }
        },
        "required": ["success", "message", "path"]
      },
      "TransactionalFailure3Response": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string"
          },
          "error": {
            "type": "object",
            "properties": {
              "path": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        },
        "required": ["success", "message", "error"]
      },
      "TransactionalFailure4Response": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string"
          },
          "error": {
            "type": "object",
            "properties": {
              "path": {
                "type": "string"
              },
              "reason": {
                "type": "string"
              }
            }
          }
        },
        "required": ["success", "message", "error"]
      },
      "TransactionalFailure5Response": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string"
          },
          "error": {
            "type": "object",
            "properties": {
              "path": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "transactionalId": {
            "type": "string",
            "examples": ["cll42l54f20i1la0lfooe3z12"]
          }
        },
        "required": ["success", "message", "error", "transactionalId"],
        "examples": [
          {
            "success": false,
            "message": "Missing required data variable(s): confirmationUrl",
            "error": {
              "path": "dataVariables",
              "message": "Missing required data variable(s): confirmationUrl"
            },
            "transactionalId": "cll42l54f20i1la0lfooe3z12"
          }
        ]
      },
      "IdempotencyKeyFailureResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "examples": [false]
          },
          "message": {
            "type": "string"
          }
        },
        "required": ["success", "message"],
        "examples": [
          {
            "success": false,
            "message": "Idempotency key already used with a different request body."
          }
        ]
      },
      "TransactionalEmail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the transactional email."
          },
          "name": {
            "type": "string",
            "description": "The name of the transactional email."
          },
          "lastUpdated": {
            "type": "string",
            "description": "The date and time the transactional email was last updated in ISO 8601 format."
          },
          "dataVariables": {
            "type": "array",
            "description": "The data variables used by the transactional email."
          }
        },
        "examples": [
          {
            "id": "cll42l54f20i1la0lfooe3z12",
            "name": "Sign up confirmation",
            "lastUpdated": "2025-02-02T02:56:28.845Z",
            "dataVariables": ["confirmationUrl"]
          }
        ],
        "required": ["id", "name", "lastUpdated", "dataVariables"]
      },
      "ListTransactionalsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionalEmail"
            }
          }
        },
        "examples": [
          {
            "pagination": {
              "totalResults": 2,
              "returnedResults": 2,
              "perPage": 20,
              "totalPages": 1,
              "nextCursor": null,
              "nextPage": null
            },
            "data": [
              {
                "id": "cll42l54f20i1la0lfooe3z12",
                "name": "Sign up confirmation",
                "lastUpdated": "2025-06-29T07:47:39.370Z",
                "dataVariables": ["confirmationUrl"]
              }
            ]
          }
        ]
      },
      "TransactionalResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the transactional email.",
            "examples": ["cll42l54f20i1la0lfooe3z12"]
          },
          "name": {
            "type": "string",
            "description": "The name of the transactional email.",
            "examples": ["Sign up confirmation"]
          },
          "draftEmailMessageId": {
            "type": ["string", "null"],
            "description": "The ID of the draft email message. `null` if there is no draft version.",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          },
          "publishedEmailMessageId": {
            "type": ["string", "null"],
            "description": "The ID of the published email message. `null` if there is no published version.",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          },
          "transactionalGroupId": {
            "type": ["string", "null"],
            "description": "The ID of the group this transactional email belongs to.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp for when the transactional email was created.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp for when the transactional email was last updated.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "dataVariables": {
            "type": "array",
            "description": "Data variable names used by the published email. Empty for unpublished transactional emails.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "name",
          "draftEmailMessageId",
          "publishedEmailMessageId",
          "transactionalGroupId",
          "createdAt",
          "updatedAt",
          "dataVariables"
        ],
        "examples": [
          {
            "id": "cll42l54f20i1la0lfooe3z12",
            "name": "Sign up confirmation",
            "draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "dataVariables": ["confirmationUrl"]
          }
        ]
      },
      "TransactionalDraftResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the transactional email."
          },
          "name": {
            "type": "string",
            "description": "The name of the transactional email."
          },
          "draftEmailMessageId": {
            "type": ["string", "null"],
            "description": "The ID of the draft email message."
          },
          "draftEmailMessageContentRevisionId": {
            "type": ["string", "null"],
            "description": "The `contentRevisionId` of the draft email message. Pass this as `expectedRevisionId` on your first update via `POST /v1/email-messages/{emailMessageId}`.",
            "examples": ["clrev1s10n2i3d4e5f6g7h8"]
          },
          "publishedEmailMessageId": {
            "type": ["string", "null"],
            "description": "The ID of the published email message. `null` if there is no published version."
          },
          "transactionalGroupId": {
            "type": ["string", "null"],
            "description": "The ID of the group this transactional email belongs to. Returned when creating a transactional email."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp for when the transactional email was created."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp for when the transactional email was last updated."
          },
          "dataVariables": {
            "type": "array",
            "description": "Data variable names used by the published email. Empty for unpublished transactional emails.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "name",
          "draftEmailMessageId",
          "draftEmailMessageContentRevisionId",
          "publishedEmailMessageId",
          "createdAt",
          "updatedAt",
          "dataVariables"
        ],
        "examples": [
          {
            "id": "cll42l54f20i1la0lfooe3z12",
            "name": "Sign up confirmation",
            "draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "dataVariables": ["confirmationUrl"],
            "draftEmailMessageContentRevisionId": "clrev1s10n2i3d4e5f6g7h8"
          }
        ]
      },
      "ListTransactionalsResourceResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionalResource"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 2,
              "returnedResults": 2,
              "perPage": 20,
              "totalPages": 1,
              "nextCursor": null,
              "nextPage": null
            },
            "data": [
              {
                "id": "cll42l54f20i1la0lfooe3z12",
                "name": "Sign up confirmation",
                "draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
                "publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
                "transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
                "createdAt": "2025-06-29T07:47:39.370Z",
                "updatedAt": "2025-06-29T07:47:39.370Z",
                "dataVariables": ["confirmationUrl"]
              }
            ]
          }
        ]
      },
      "CreateTransactionalRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the transactional email.",
            "examples": ["Welcome email"]
          },
          "transactionalGroupId": {
            "type": "string",
            "description": "The ID of the group to add this transactional email to. Defaults to the team's default group when omitted.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          }
        },
        "required": ["name"],
        "additionalProperties": false
      },
      "UpdateTransactionalRequest": {
        "type": "object",
        "minProperties": 1,
        "description": "At least one field must be provided.",
        "properties": {
          "name": {
            "type": "string",
            "examples": ["Password reset email"]
          },
          "transactionalGroupId": {
            "type": "string",
            "description": "The ID of the group to move this transactional email to.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          }
        },
        "additionalProperties": false
      },
      "ContactProperty": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The key of the contact property."
          },
          "label": {
            "type": "string",
            "description": "The human-friendly label for this property."
          },
          "type": {
            "type": "string",
            "description": "The type of property.",
            "enum": ["string", "number", "boolean", "date"]
          }
        },
        "examples": [
          {
            "key": "favoriteColor",
            "label": "Favorite color",
            "type": "string"
          }
        ],
        "required": ["key", "label", "type"]
      },
      "MailingList": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the mailing list.",
            "examples": ["clm2k8j4h6g0f8d6s4a2b0z8"]
          },
          "name": {
            "type": "string",
            "description": "The name of the mailing list.",
            "examples": ["Product updates"]
          },
          "description": {
            "type": ["string", "null"],
            "description": "The description of the mailing list. `null` if no description is set.",
            "examples": ["Monthly product news and release notes"]
          },
          "isPublic": {
            "type": "boolean",
            "description": "Whether the mailing list is public (`true`) or private (`false`).",
            "examples": [true]
          }
        },
        "examples": [
          {
            "id": "clm2k8j4h6g0f8d6s4a2b0z8",
            "name": "Product updates",
            "description": "Monthly product news and release notes",
            "isPublic": true
          },
          {
            "id": "clm2k8j4h6g0f8d6s4a2b0z8",
            "name": "Product updates",
            "description": null,
            "isPublic": true
          }
        ],
        "required": ["id", "name", "description", "isPublic"]
      },
      "MailingListSubscriptions": {
        "type": "object",
        "description": "Manage mailing list subscriptions.\n\nInclude key-value pairs of mailing list IDs and a `boolean` denoting if the contact should be added (`true`) or removed (`false`) from the list.",
        "examples": [
          {
            "cm06f5v0e45nf0ml5754o9cix": true,
            "cm16k73gq014h0mmj5b6jdi9r": false
          }
        ]
      },
      "Theme": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the theme.",
            "examples": ["clt3u5v7w9x1y3z5a7b9c1d3"]
          },
          "name": {
            "type": "string",
            "description": "The name of the theme.",
            "examples": ["Default"]
          },
          "styles": {
            "$ref": "#/components/schemas/ThemeStyles"
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this theme is the team's default.",
            "examples": [true]
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 timestamp for when the theme was created.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 timestamp for when the theme was last updated.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          }
        },
        "required": [
          "id",
          "name",
          "styles",
          "isDefault",
          "createdAt",
          "updatedAt"
        ],
        "examples": [
          {
            "id": "clt3u5v7w9x1y3z5a7b9c1d3",
            "name": "Default",
            "styles": {
              "backgroundColor": "#f5f5f5",
              "backgroundXPadding": 24,
              "backgroundYPadding": 24,
              "bodyColor": "#ffffff",
              "bodyXPadding": 24,
              "bodyYPadding": 24,
              "bodyFontFamily": "Helvetica",
              "bodyFontCategory": "sans-serif",
              "borderColor": "#e5e5e5",
              "borderWidth": 1,
              "borderRadius": 8,
              "buttonBodyColor": "#111827",
              "buttonBodyXPadding": 16,
              "buttonBodyYPadding": 12,
              "buttonBorderColor": "#111827",
              "buttonBorderWidth": 0,
              "buttonBorderRadius": 6,
              "buttonTextColor": "#ffffff",
              "buttonTextFormat": 0,
              "buttonTextFontSize": 16,
              "dividerColor": "#e5e5e5",
              "dividerBorderWidth": 1,
              "textBaseColor": "#374151",
              "textBaseFontSize": 16,
              "textBaseLineHeight": 24,
              "textBaseLetterSpacing": 0,
              "textLinkColor": "#2563eb",
              "heading1Color": "#111827",
              "heading1FontSize": 28,
              "heading1LineHeight": 36,
              "heading1LetterSpacing": -0.5,
              "heading2Color": "#111827",
              "heading2FontSize": 22,
              "heading2LineHeight": 30,
              "heading2LetterSpacing": -0.25,
              "heading3Color": "#111827",
              "heading3FontSize": 18,
              "heading3LineHeight": 26,
              "heading3LetterSpacing": 0
            },
            "isDefault": true,
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z"
          }
        ]
      },
      "ThemeStyles": {
        "type": "object",
        "description": "Flat map of style attributes, matching the attribute names accepted by the LMX `<Style />` tag.",
        "properties": {
          "backgroundColor": {
            "type": "string"
          },
          "backgroundXPadding": {
            "type": "number"
          },
          "backgroundYPadding": {
            "type": "number"
          },
          "bodyColor": {
            "type": "string"
          },
          "bodyXPadding": {
            "type": "number"
          },
          "bodyYPadding": {
            "type": "number"
          },
          "bodyFontFamily": {
            "type": "string"
          },
          "bodyFontCategory": {
            "type": "string"
          },
          "borderColor": {
            "type": "string"
          },
          "borderWidth": {
            "type": "number"
          },
          "borderRadius": {
            "type": "number"
          },
          "buttonBodyColor": {
            "type": "string"
          },
          "buttonBodyXPadding": {
            "type": "number"
          },
          "buttonBodyYPadding": {
            "type": "number"
          },
          "buttonBorderColor": {
            "type": "string"
          },
          "buttonBorderWidth": {
            "type": "number"
          },
          "buttonBorderRadius": {
            "type": "number"
          },
          "buttonTextColor": {
            "type": "string"
          },
          "buttonTextFormat": {
            "type": "number"
          },
          "buttonTextFontSize": {
            "type": "number"
          },
          "dividerColor": {
            "type": "string"
          },
          "dividerBorderWidth": {
            "type": "number"
          },
          "textBaseColor": {
            "type": "string"
          },
          "textBaseFontSize": {
            "type": "number"
          },
          "textBaseLineHeight": {
            "type": "number"
          },
          "textBaseLetterSpacing": {
            "type": "number"
          },
          "textLinkColor": {
            "type": "string"
          },
          "heading1Color": {
            "type": "string"
          },
          "heading1FontSize": {
            "type": "number"
          },
          "heading1LineHeight": {
            "type": "number"
          },
          "heading1LetterSpacing": {
            "type": "number"
          },
          "heading2Color": {
            "type": "string"
          },
          "heading2FontSize": {
            "type": "number"
          },
          "heading2LineHeight": {
            "type": "number"
          },
          "heading2LetterSpacing": {
            "type": "number"
          },
          "heading3Color": {
            "type": "string"
          },
          "heading3FontSize": {
            "type": "number"
          },
          "heading3LineHeight": {
            "type": "number"
          },
          "heading3LetterSpacing": {
            "type": "number"
          }
        }
      },
      "ListThemesResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Theme"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 2,
              "returnedResults": 2,
              "perPage": 20,
              "totalPages": 1,
              "nextCursor": null,
              "nextPage": null
            },
            "data": [
              {
                "id": "clt3u5v7w9x1y3z5a7b9c1d3",
                "name": "Default",
                "styles": {
                  "backgroundColor": "#f5f5f5",
                  "backgroundXPadding": 24,
                  "backgroundYPadding": 24,
                  "bodyColor": "#ffffff",
                  "bodyXPadding": 24,
                  "bodyYPadding": 24,
                  "bodyFontFamily": "Helvetica",
                  "bodyFontCategory": "sans-serif",
                  "borderColor": "#e5e5e5",
                  "borderWidth": 1,
                  "borderRadius": 8,
                  "buttonBodyColor": "#111827",
                  "buttonBodyXPadding": 16,
                  "buttonBodyYPadding": 12,
                  "buttonBorderColor": "#111827",
                  "buttonBorderWidth": 0,
                  "buttonBorderRadius": 6,
                  "buttonTextColor": "#ffffff",
                  "buttonTextFormat": 0,
                  "buttonTextFontSize": 16,
                  "dividerColor": "#e5e5e5",
                  "dividerBorderWidth": 1,
                  "textBaseColor": "#374151",
                  "textBaseFontSize": 16,
                  "textBaseLineHeight": 24,
                  "textBaseLetterSpacing": 0,
                  "textLinkColor": "#2563eb",
                  "heading1Color": "#111827",
                  "heading1FontSize": 28,
                  "heading1LineHeight": 36,
                  "heading1LetterSpacing": -0.5,
                  "heading2Color": "#111827",
                  "heading2FontSize": 22,
                  "heading2LineHeight": 30,
                  "heading2LetterSpacing": -0.25,
                  "heading3Color": "#111827",
                  "heading3FontSize": 18,
                  "heading3LineHeight": 26,
                  "heading3LetterSpacing": 0
                },
                "isDefault": true,
                "createdAt": "2025-06-29T07:47:39.370Z",
                "updatedAt": "2025-06-29T07:47:39.370Z"
              }
            ]
          }
        ]
      },
      "ThemeResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["clt3u5v7w9x1y3z5a7b9c1d3"],
            "description": "The ID of the theme."
          },
          "name": {
            "type": "string",
            "examples": ["Default"],
            "description": "The name of the theme."
          },
          "styles": {
            "$ref": "#/components/schemas/ThemeStyles"
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this theme is the team's default.",
            "examples": [true]
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 timestamp for when the theme was created.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 timestamp for when the theme was last updated.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          }
        },
        "required": [
          "id",
          "name",
          "styles",
          "isDefault",
          "createdAt",
          "updatedAt"
        ],
        "examples": [
          {
            "id": "clt3u5v7w9x1y3z5a7b9c1d3",
            "name": "Default",
            "styles": {
              "backgroundColor": "#f5f5f5",
              "backgroundXPadding": 24,
              "backgroundYPadding": 24,
              "bodyColor": "#ffffff",
              "bodyXPadding": 24,
              "bodyYPadding": 24,
              "bodyFontFamily": "Helvetica",
              "bodyFontCategory": "sans-serif",
              "borderColor": "#e5e5e5",
              "borderWidth": 1,
              "borderRadius": 8,
              "buttonBodyColor": "#111827",
              "buttonBodyXPadding": 16,
              "buttonBodyYPadding": 12,
              "buttonBorderColor": "#111827",
              "buttonBorderWidth": 0,
              "buttonBorderRadius": 6,
              "buttonTextColor": "#ffffff",
              "buttonTextFormat": 0,
              "buttonTextFontSize": 16,
              "dividerColor": "#e5e5e5",
              "dividerBorderWidth": 1,
              "textBaseColor": "#374151",
              "textBaseFontSize": 16,
              "textBaseLineHeight": 24,
              "textBaseLetterSpacing": 0,
              "textLinkColor": "#2563eb",
              "heading1Color": "#111827",
              "heading1FontSize": 28,
              "heading1LineHeight": 36,
              "heading1LetterSpacing": -0.5,
              "heading2Color": "#111827",
              "heading2FontSize": 22,
              "heading2LineHeight": 30,
              "heading2LetterSpacing": -0.25,
              "heading3Color": "#111827",
              "heading3FontSize": 18,
              "heading3LineHeight": 26,
              "heading3LetterSpacing": 0
            },
            "isDefault": true,
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z"
          }
        ]
      },
      "ThemeFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Theme not found."
          }
        ]
      },
      "CreateThemeBody": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The theme name.",
            "examples": ["Dark mode"]
          },
          "styles": {
            "description": "Style attributes for the theme. Attributes use the same names as the LMX [`<Style />`](/creating-emails/lmx#document-styles) tag attributes.",
            "$ref": "#/components/schemas/ThemeStyles"
          }
        },
        "required": ["name"],
        "examples": [
          {
            "name": "Dark mode",
            "styles": {
              "backgroundColor": "#111827",
              "bodyColor": "#1f2937"
            }
          }
        ]
      },
      "UpdateThemeBody": {
        "type": "object",
        "description": "At least one of `name` or `styles` must be provided.",
        "properties": {
          "name": {
            "type": "string"
          },
          "styles": {
            "$ref": "#/components/schemas/ThemeStyles"
          }
        }
      },
      "UpdateThemeResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ThemeResponse"
          },
          {
            "type": "object",
            "properties": {
              "affectedEmailCount": {
                "type": "number",
                "description": "The number of emails using this theme that are affected by the style change. `0` when only the name changed."
              }
            },
            "required": ["affectedEmailCount"]
          }
        ],
        "examples": [
          {
            "id": "clt3u5v7w9x1y3z5a7b9c1d3",
            "name": "Default",
            "styles": {
              "backgroundColor": "#f5f5f5",
              "backgroundXPadding": 24,
              "backgroundYPadding": 24,
              "bodyColor": "#ffffff",
              "bodyXPadding": 24,
              "bodyYPadding": 24,
              "bodyFontFamily": "Helvetica",
              "bodyFontCategory": "sans-serif",
              "borderColor": "#e5e5e5",
              "borderWidth": 1,
              "borderRadius": 8,
              "buttonBodyColor": "#111827",
              "buttonBodyXPadding": 16,
              "buttonBodyYPadding": 12,
              "buttonBorderColor": "#111827",
              "buttonBorderWidth": 0,
              "buttonBorderRadius": 6,
              "buttonTextColor": "#ffffff",
              "buttonTextFormat": 0,
              "buttonTextFontSize": 16,
              "dividerColor": "#e5e5e5",
              "dividerBorderWidth": 1,
              "textBaseColor": "#374151",
              "textBaseFontSize": 16,
              "textBaseLineHeight": 24,
              "textBaseLetterSpacing": 0,
              "textLinkColor": "#2563eb",
              "heading1Color": "#111827",
              "heading1FontSize": 28,
              "heading1LineHeight": 36,
              "heading1LetterSpacing": -0.5,
              "heading2Color": "#111827",
              "heading2FontSize": 22,
              "heading2LineHeight": 30,
              "heading2LetterSpacing": -0.25,
              "heading3Color": "#111827",
              "heading3FontSize": 18,
              "heading3LineHeight": 26,
              "heading3LetterSpacing": 0
            },
            "isDefault": true,
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "affectedEmailCount": 12
          }
        ]
      },
      "Component": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["clp2o4i6u8y0t5r3e1w7q9s1"]
          },
          "name": {
            "type": "string",
            "examples": ["Header"]
          },
          "lmx": {
            "type": "string",
            "description": "The component body serialized as LMX.",
            "examples": ["<Paragraph>Welcome to Acme</Paragraph>"]
          }
        },
        "required": ["id", "name", "lmx"],
        "examples": [
          {
            "id": "clp2o4i6u8y0t5r3e1w7q9s1",
            "name": "Header",
            "lmx": "<Paragraph>Welcome to Acme</Paragraph>"
          }
        ]
      },
      "ListComponentsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Component"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 2,
              "returnedResults": 2,
              "perPage": 20,
              "totalPages": 1,
              "nextCursor": null,
              "nextPage": null
            },
            "data": [
              {
                "id": "clp2o4i6u8y0t5r3e1w7q9s1",
                "name": "Header",
                "lmx": "<Paragraph>Welcome to Acme</Paragraph>"
              }
            ]
          }
        ]
      },
      "ComponentResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the component."
          },
          "name": {
            "type": "string",
            "description": "The name of the component."
          },
          "lmx": {
            "type": "string",
            "description": "The component body serialized as LMX."
          }
        },
        "required": ["id", "name", "lmx"],
        "examples": [
          {
            "id": "clp2o4i6u8y0t5r3e1w7q9s1",
            "name": "Header",
            "lmx": "<Paragraph>Welcome to Acme</Paragraph>"
          }
        ]
      },
      "ComponentFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Component not found."
          }
        ]
      },
      "ComponentValidationFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "invalidTags": {
            "type": "array",
            "description": "The dynamic variables that the change would push into an email that cannot use them. Present only when the update was rejected for that reason.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Component uses unsupported contact properties.",
            "invalidTags": ["companyName"]
          }
        ]
      },
      "CreateComponentBody": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The component name."
          },
          "lmx": {
            "type": "string",
            "description": "The component body as an LMX string."
          }
        },
        "required": ["name", "lmx"],
        "examples": [
          {
            "name": "Header",
            "lmx": "<Paragraph>Welcome to Acme</Paragraph>"
          }
        ]
      },
      "UpdateComponentBody": {
        "type": "object",
        "description": "At least one of `name` or `lmx` must be provided.",
        "properties": {
          "name": {
            "type": "string"
          },
          "lmx": {
            "type": "string",
            "description": "The component body as an LMX string."
          }
        }
      },
      "UpdateComponentResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ComponentResponse"
          },
          {
            "type": "object",
            "properties": {
              "affectedEmailCount": {
                "type": "number",
                "description": "The number of emails using this component that were updated by the body change. `0` when only the name changed."
              }
            },
            "required": ["affectedEmailCount"]
          }
        ],
        "examples": [
          {
            "id": "clp2o4i6u8y0t5r3e1w7q9s1",
            "name": "Header",
            "lmx": "<Paragraph>Welcome to Acme</Paragraph>",
            "affectedEmailCount": 3
          }
        ]
      },
      "AudienceSegment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the audience segment.",
            "examples": ["cls6e8g0i2k4m6o8q0s2u4w6"]
          },
          "name": {
            "type": "string",
            "description": "The name of the audience segment.",
            "examples": ["Power users"]
          },
          "description": {
            "type": ["string", "null"],
            "description": "An optional description of the audience segment.",
            "examples": ["Contacts on the pro plan"]
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 timestamp for when the audience segment was created.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 timestamp for when the audience segment was last updated.",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "filter": {
            "$ref": "#/components/schemas/AudienceFilter"
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "createdAt",
          "updatedAt",
          "filter"
        ],
        "examples": [
          {
            "id": "cls6e8g0i2k4m6o8q0s2u4w6",
            "name": "Power users",
            "description": "Contacts on the pro plan",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "filter": {
              "match": "all",
              "conditions": [
                {
                  "type": "property",
                  "key": "plan",
                  "operator": "equals",
                  "value": "pro"
                }
              ]
            }
          }
        ]
      },
      "ListAudienceSegmentsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudienceSegment"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 2,
              "returnedResults": 2,
              "perPage": 20,
              "totalPages": 1,
              "nextCursor": null,
              "nextPage": null
            },
            "data": [
              {
                "id": "cls6e8g0i2k4m6o8q0s2u4w6",
                "name": "Power users",
                "description": "Contacts on the pro plan",
                "createdAt": "2025-06-29T07:47:39.370Z",
                "updatedAt": "2025-06-29T07:47:39.370Z",
                "filter": {
                  "match": "all",
                  "conditions": [
                    {
                      "type": "property",
                      "key": "plan",
                      "operator": "equals",
                      "value": "pro"
                    }
                  ]
                }
              }
            ]
          }
        ]
      },
      "AudienceSegmentResponse": {
        "$ref": "#/components/schemas/AudienceSegment",
        "examples": [
          {
            "id": "cls6e8g0i2k4m6o8q0s2u4w6",
            "name": "Power users",
            "description": "Contacts on the pro plan",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "filter": {
              "match": "all",
              "conditions": [
                {
                  "type": "property",
                  "key": "plan",
                  "operator": "equals",
                  "value": "pro"
                }
              ]
            }
          }
        ]
      },
      "CreateAudienceSegmentRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "The name of the audience segment. Must be unique within the team.",
            "examples": ["Active users"]
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "description": "An optional description of the audience segment."
          },
          "filter": {
            "type": "object",
            "description": "A tree of audience conditions combined with `match`.",
            "properties": {
              "match": {
                "type": "string",
                "enum": ["all", "any"]
              },
              "conditions": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "$ref": "#/components/schemas/AudienceFilterCondition"
                }
              }
            },
            "required": ["match", "conditions"],
            "additionalProperties": false
          }
        },
        "required": ["name", "filter"],
        "additionalProperties": false
      },
      "AudienceSegmentFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Audience segment not found."
          }
        ]
      },
      "CampaignScheduling": {
        "type": "object",
        "description": "When the campaign is scheduled to send.",
        "properties": {
          "method": {
            "type": "string",
            "enum": ["now", "schedule"]
          },
          "timestamp": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "ISO 8601 send time. Null when the method is `now`."
          }
        },
        "required": ["method", "timestamp"],
        "examples": [
          {
            "method": "schedule",
            "timestamp": "2025-07-15T14:00:00.000Z"
          }
        ]
      },
      "CampaignSchedulingRequest": {
        "type": "object",
        "description": "When the campaign should send. `timestamp` is required and must be in the future when `method` is `schedule`, and must be omitted when `method` is `now`.",
        "properties": {
          "method": {
            "type": "string",
            "enum": ["now", "schedule"]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": ["method"],
        "additionalProperties": false,
        "examples": [
          {
            "method": "schedule",
            "timestamp": "2025-07-15T14:00:00.000Z"
          }
        ]
      },
      "AudienceFilter": {
        "type": ["object", "null"],
        "description": "A tree of audience conditions combined with `match`.",
        "properties": {
          "match": { "type": "string", "enum": ["all", "any"] },
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": { "$ref": "#/components/schemas/AudienceFilterCondition" }
          }
        },
        "required": ["match", "conditions"],
        "additionalProperties": false
      },
      "AudienceFilterInRequest": {
        "type": ["object", "null"],
        "description": "A tree of audience conditions combined with `match`. Setting this without also providing `audienceSegmentId` clears any existing `audienceSegmentId`. When both are provided, this filter is applied on top of the segment's filter.",
        "properties": {
          "match": {
            "type": "string",
            "enum": ["all", "any"]
          },
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/AudienceFilterCondition"
            }
          }
        },
        "required": ["match", "conditions"],
        "additionalProperties": false
      },
      "AudienceFilterCondition": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/PropertyCondition"
          },
          {
            "$ref": "#/components/schemas/OptInCondition"
          },
          {
            "$ref": "#/components/schemas/ActivityCondition"
          }
        ],
        "discriminator": {
          "propertyName": "type"
        }
      },
      "PropertyCondition": {
        "type": "object",
        "description": "Matches contacts by a property value.",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["property"]
          },
          "key": {
            "type": "string",
            "description": "The contact property name."
          },
          "operator": {
            "type": "string",
            "enum": [
              "any",
              "contains",
              "notContains",
              "equals",
              "notEquals",
              "greaterThan",
              "lessThan",
              "isTrue",
              "isFalse",
              "empty",
              "notEmpty",
              "dateEmpty",
              "dateNotEmpty",
              "after",
              "before",
              "between"
            ]
          },
          "value": {
            "description": "The comparison value. Omitted for value-less operators (e.g. `isTrue`, `empty`). A `{ from, to }` object for `between`.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "object",
                "properties": {
                  "from": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "to": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": ["from", "to"]
              }
            ]
          }
        },
        "required": ["type", "key", "operator"],
        "examples": [
          {
            "type": "property",
            "key": "plan",
            "operator": "equals",
            "value": "pro"
          }
        ]
      },
      "OptInCondition": {
        "type": "object",
        "description": "Matches contacts by mailing-list opt-in status.",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["optIn"]
          },
          "status": {
            "type": ["string", "null"],
            "enum": ["accepted", "pending", "rejected", null]
          }
        },
        "required": ["type", "status"],
        "examples": [
          {
            "type": "optIn",
            "status": "accepted"
          }
        ]
      },
      "ActivityCondition": {
        "type": "object",
        "description": "Matches contacts by their activity on a campaign or workflow.",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["activity"]
          },
          "action": {
            "type": "string",
            "enum": ["sent", "opened", "clicked"]
          },
          "negate": {
            "type": "boolean"
          },
          "target": {
            "type": "string",
            "enum": ["campaign", "workflow", "workflowEmail"]
          },
          "id": {
            "type": "string",
            "description": "The ID of the campaign, workflow, or workflow email."
          }
        },
        "required": ["type", "action", "negate", "target", "id"],
        "examples": [
          {
            "type": "activity",
            "action": "opened",
            "negate": false,
            "target": "campaign",
            "id": "clc4m6n8p0q2r4s6t8u0v2x4"
          }
        ]
      },
      "CampaignListItem": {
        "$ref": "#/components/schemas/CampaignResponse"
      },
      "ListCampaignsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CampaignResponse"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 45,
              "returnedResults": 20,
              "perPage": 20,
              "totalPages": 3,
              "nextCursor": "clp9k2m4n6p8q0r2s4t6u8v0",
              "nextPage": "https://app.loops.so/api/v1/campaign-groups?cursor=clp9k2m4n6p8q0r2s4t6u8v0&perPage=20"
            },
            "data": [
              {
                "id": "clc4m6n8p0q2r4s6t8u0v2x4",
                "name": "Spring announcement",
                "status": "Draft",
                "createdAt": "2025-06-29T07:47:39.370Z",
                "updatedAt": "2025-06-29T07:47:39.370Z",
                "emailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
                "campaignGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
                "mailingListId": "clm2k8j4h6g0f8d6s4a2b0z8",
                "audienceSegmentId": null,
                "audienceFilter": null,
                "scheduling": {
                  "method": "now",
                  "timestamp": null
                }
              }
            ]
          }
        ]
      },
      "CreateCampaignRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The campaign name.",
            "examples": ["Spring announcement"]
          },
          "campaignGroupId": {
            "type": "string",
            "description": "The ID of the group to add this campaign to. Defaults to the team's default group when omitted.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of the mailing list to send to.",
            "examples": ["clm2k8j4h6g0f8d6s4a2b0z8"]
          },
          "audienceSegmentId": {
            "type": ["string", "null"],
            "description": "The ID of an audience segment. Setting this without also providing `audienceFilter` clears any existing `audienceFilter`. If both are provided, the filter is applied on top of the segment's filter.",
            "examples": ["cls6e8g0i2k4m6o8q0s2u4w6"]
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilterInRequest"
          },
          "scheduling": {
            "$ref": "#/components/schemas/CampaignSchedulingRequest"
          }
        },
        "required": ["name"],
        "additionalProperties": false
      },
      "CreateCampaignResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the campaign.",
            "examples": ["clc4m6n8p0q2r4s6t8u0v2x4"]
          },
          "name": {
            "type": "string",
            "description": "The name of the campaign.",
            "examples": ["Spring announcement"]
          },
          "status": {
            "type": "string",
            "examples": ["Draft"],
            "enum": ["Draft"],
            "description": "The status of the campaign (always `Draft` for new campaigns)."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the campaign was created."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the campaign was last updated."
          },
          "emailMessageId": {
            "type": ["string", "null"],
            "description": "The ID of the empty email message created for this campaign. Use `POST /v1/email-messages/{emailMessageId}` to set its fields and LMX content.",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          },
          "emailMessageContentRevisionId": {
            "type": ["string", "null"],
            "description": "The `contentRevisionId` of the newly created email message. Pass this as `expectedRevisionId` on your first update.",
            "examples": ["clrev1s10n2i3d4e5f6g7h8"]
          },
          "campaignGroupId": {
            "type": ["string", "null"],
            "description": "The ID of the campaign group this campaign belongs to, if set.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of the mailing list this campaign sends to, if set.",
            "examples": ["clm2k8j4h6g0f8d6s4a2b0z8"]
          },
          "audienceSegmentId": {
            "type": ["string", "null"],
            "description": "The ID of the audience segment this campaign targets, if set.",
            "examples": ["cls6e8g0i2k4m6o8q0s2u4w6"]
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilter",
            "description": "The filter rules that define the audience for this campaign, if set."
          },
          "scheduling": {
            "$ref": "#/components/schemas/CampaignScheduling",
            "description": "When the campaign is scheduled to send."
          }
        },
        "required": [
          "id",
          "name",
          "status",
          "createdAt",
          "updatedAt",
          "emailMessageId",
          "emailMessageContentRevisionId",
          "campaignGroupId",
          "mailingListId",
          "audienceSegmentId",
          "audienceFilter",
          "scheduling"
        ],
        "examples": [
          {
            "id": "clc4m6n8p0q2r4s6t8u0v2x4",
            "name": "Spring announcement",
            "status": "Draft",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "emailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "campaignGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
            "mailingListId": "clm2k8j4h6g0f8d6s4a2b0z8",
            "audienceSegmentId": null,
            "audienceFilter": null,
            "scheduling": {
              "method": "now",
              "timestamp": null
            },
            "emailMessageContentRevisionId": "clrev1s10n2i3d4e5f6g7h8"
          }
        ]
      },
      "UpdateCampaignRequest": {
        "type": "object",
        "description": "At least one field must be provided.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The updated campaign name.",
            "examples": ["Spring announcement"]
          },
          "campaignGroupId": {
            "type": "string",
            "description": "The ID of the group to move this campaign to.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of the mailing list to send to.",
            "examples": ["clm2k8j4h6g0f8d6s4a2b0z8"]
          },
          "audienceSegmentId": {
            "type": ["string", "null"],
            "description": "The ID of an audience segment. Setting this without also providing `audienceFilter` clears any existing `audienceFilter`. If both are provided, the filter is applied on top of the segment's filter.",
            "examples": ["cls6e8g0i2k4m6o8q0s2u4w6"]
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilterInRequest"
          },
          "scheduling": {
            "$ref": "#/components/schemas/CampaignSchedulingRequest"
          }
        },
        "additionalProperties": false
      },
      "CampaignResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the campaign.",
            "examples": ["clc4m6n8p0q2r4s6t8u0v2x4"]
          },
          "name": {
            "type": "string",
            "description": "The name of the campaign.",
            "examples": ["Spring announcement"]
          },
          "status": {
            "type": "string",
            "description": "The status of the campaign.",
            "enum": ["Draft", "Scheduled", "Sending", "Sent"],
            "examples": ["Draft"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the campaign was created."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the campaign was last updated."
          },
          "emailMessageId": {
            "type": ["string", "null"],
            "description": "The associated email message ID.",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          },
          "campaignGroupId": {
            "type": ["string", "null"],
            "description": "The ID of the campaign group this campaign belongs to.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          },
          "mailingListId": {
            "type": ["string", "null"],
            "examples": ["clm2k8j4h6g0f8d6s4a2b0z8"],
            "description": "The ID of the mailing list this campaign sends to, if set."
          },
          "audienceSegmentId": {
            "type": ["string", "null"],
            "description": "The ID of the audience segment this campaign targets, if set.",
            "examples": ["cls6e8g0i2k4m6o8q0s2u4w6"]
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilter",
            "description": "The filter rules that define the audience for this campaign, if set."
          },
          "scheduling": {
            "$ref": "#/components/schemas/CampaignScheduling"
          }
        },
        "required": [
          "id",
          "name",
          "status",
          "createdAt",
          "updatedAt",
          "emailMessageId",
          "campaignGroupId",
          "mailingListId",
          "audienceSegmentId",
          "audienceFilter",
          "scheduling"
        ],
        "examples": [
          {
            "id": "clc4m6n8p0q2r4s6t8u0v2x4",
            "name": "Spring announcement",
            "status": "Draft",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z",
            "emailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "campaignGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
            "mailingListId": "clm2k8j4h6g0f8d6s4a2b0z8",
            "audienceSegmentId": null,
            "audienceFilter": null,
            "scheduling": {
              "method": "now",
              "timestamp": null
            }
          }
        ]
      },
      "CampaignFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Campaign not found."
          }
        ]
      },
      "WorkflowSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the workflow.",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "name": {
            "type": "string",
            "description": "The name of the workflow.",
            "examples": ["Welcome series"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the workflow was created."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the workflow was last updated."
          }
        },
        "required": ["id", "name", "createdAt", "updatedAt"],
        "examples": [
          {
            "id": "clw1a3b5c7d9e1f3g5h7i9j1",
            "name": "Welcome series",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z"
          }
        ]
      },
      "ListWorkflowsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowSummary"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 45,
              "returnedResults": 20,
              "perPage": 20,
              "totalPages": 3,
              "nextCursor": "clp9k2m4n6p8q0r2s4t6u8v0",
              "nextPage": "https://app.loops.so/api/v1/campaign-groups?cursor=clp9k2m4n6p8q0r2s4t6u8v0&perPage=20"
            },
            "data": [
              {
                "id": "clw1a3b5c7d9e1f3g5h7i9j1",
                "name": "Welcome series",
                "createdAt": "2025-06-29T07:47:39.370Z",
                "updatedAt": "2025-06-29T07:47:39.370Z"
              }
            ]
          }
        ]
      },
      "WorkflowRevisionId": {
        "type": ["string"],
        "description": "The current workflow revision token. Pass the latest value as `expectedRevisionId` on the next workflow mutation."
      },
      "NullableWorkflowRevisionId": {
        "type": ["string", "null"],
        "description": "The current workflow revision token. Pass the latest value as `expectedRevisionId` on the next workflow mutation. Will be `null` for workflows without a revision token yet."
      },
      "WorkflowReEligible": {
        "type": "boolean",
        "description": "If `true`, the contacts will be able to enter this workflow every time the trigger is matched. If `false`, contacts will only ever enter this workflow once. Matches the \"Trigger frequency\" option in the UI."
      },
      "WorkflowNextNodeIds": {
        "type": "array",
        "items": { "type": "string" },
        "description": "The IDs of the nodes that are downstream of this node."
      },
      "WorkflowExpectedRevisionId": {
        "type": ["string", "null"],
        "description": "The workflow revision token returned by the latest workflow read or mutation. Older workflows may return `null` before their first revision-aware mutation; pass `null` back as `expectedRevisionId` in that case. If the token is stale, the API returns a `409 Conflict` error."
      },
      "WorkflowQueuedContactPolicy": {
        "type": "string",
        "enum": ["fail", "discard"],
        "default": "fail",
        "description": "`fail` returns queued-contact impact instead of mutating. `discard` confirms that matching queued contacts should be discarded. Defaults to `fail` when omitted."
      },
      "SimplifiedWorkflow": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "description": "The ID of the workflow." },
          "workflowRevisionId": {
            "$ref": "#/components/schemas/NullableWorkflowRevisionId"
          },
          "status": {
            "type": "string",
            "enum": ["Draft", "Sending", "Paused", "PausedAndQueueing"]
          },
          "name": {
            "type": "string",
            "description": "The name of the workflow."
          },
          "description": {
            "type": "string",
            "description": "The description of the workflow."
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of the mailing list the workflow sends to."
          },
          "rootNodeId": {
            "type": "string",
            "description": "The ID of the root node in the workflow graph."
          },
          "nodes": {
            "type": "object",
            "description": "A map of node IDs to simplified node objects. Each node includes `typeName` and `nextNodeIds`, plus type-specific fields when present. To get the full node object, use the `GET /v1/workflows/{workflowId}/nodes/{nodeId}` endpoint.",
            "additionalProperties": {
              "$ref": "#/components/schemas/SimplifiedWorkflowNode"
            },
            "example": {
              "cf16k73gq014h3mmj5b6jdi9r": {
                "typeName": "SignupTrigger",
                "nextNodeIds": [
                  "cf16k73gq014h3mmj5b4jdifg",
                  "cf16k73gq014h3mmj5b4jdifh"
                ]
              }
            }
          }
        },
        "required": [
          "id",
          "workflowRevisionId",
          "status",
          "mailingListId",
          "rootNodeId",
          "nodes"
        ],
        "examples": [
          {
            "id": "clw1a3b5c7d9e1f3g5h7i9j1",
            "status": "Draft",
            "name": "Welcome series",
            "description": "Onboarding emails for new signups",
            "mailingListId": "clm2k8j4h6g0f8d6s4a2b0z8",
            "rootNodeId": "cln8p0q2r4s6t8u0v2w4x6z8",
            "nodes": {
              "cln8p0q2r4s6t8u0v2w4x6z8": {
                "typeName": "SignupTrigger",
                "nextNodeIds": ["cln1a3b5c7d9e1f3g5h7i9j1"]
              },
              "cln1a3b5c7d9e1f3g5h7i9j1": {
                "typeName": "SendEmailAction",
                "nextNodeIds": [],
                "emailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
                "subject": "Welcome to Acme!"
              }
            }
          }
        ]
      },
      "CreateWorkflowRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the workflow."
          },
          "description": {
            "type": "string",
            "description": "The description of the workflow."
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of a mailing list the workflow sends to. After creation, the mailing list can be changed with the `/v1/workflows/{workflowId}/mailing-list` endpoint."
          }
        },
        "required": ["name"],
        "additionalProperties": false
      },
      "UpdateWorkflowPropertiesRequest": {
        "type": "object",
        "description": "At least one property must be provided.",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          },
          "name": {
            "type": "string",
            "description": "The updated workflow name."
          },
          "description": {
            "type": "string",
            "description": "The updated workflow description."
          }
        },
        "required": ["expectedRevisionId"],
        "anyOf": [{ "required": ["name"] }, { "required": ["description"] }],
        "additionalProperties": false
      },
      "WorkflowMutationNode": {
        "description": "Detailed workflow node returned from create and update mutations. The exact fields depend on `typeName`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/SignupTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/EventTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/AddToListTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/BlankTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/AudienceFilterWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/TimerActionWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/SendEmailActionWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/ExitActionWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/BranchWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/ExperimentBranchWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/VariantWorkflowMutationNode"
          }
        ],
        "discriminator": {
          "propertyName": "typeName",
          "mapping": {
            "SignupTrigger": "#/components/schemas/SignupTriggerWorkflowMutationNode",
            "EventTrigger": "#/components/schemas/EventTriggerWorkflowMutationNode",
            "ContactPropertyTrigger": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNode",
            "AddToListTrigger": "#/components/schemas/AddToListTriggerWorkflowMutationNode",
            "BlankTrigger": "#/components/schemas/BlankTriggerWorkflowMutationNode",
            "AudienceFilter": "#/components/schemas/AudienceFilterWorkflowMutationNode",
            "TimerAction": "#/components/schemas/TimerActionWorkflowMutationNode",
            "SendEmailAction": "#/components/schemas/SendEmailActionWorkflowMutationNode",
            "ExitAction": "#/components/schemas/ExitActionWorkflowMutationNode",
            "BranchNode": "#/components/schemas/BranchWorkflowMutationNode",
            "ExperimentBranchNode": "#/components/schemas/ExperimentBranchWorkflowMutationNode",
            "VariantNode": "#/components/schemas/VariantWorkflowMutationNode"
          }
        }
      },
      "WorkflowMutationNodeRevision": {
        "type": "object",
        "properties": {
          "workflowRevisionId": {
            "$ref": "#/components/schemas/WorkflowRevisionId"
          }
        },
        "required": ["workflowRevisionId"]
      },
      "SignupTriggerWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["SignupTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "typeName", "nextNodeIds"]
      },
      "EventTriggerWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["EventTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "eventName": {
            "type": "string",
            "description": "The name of the event pattern that triggers this node."
          },
          "eventProperties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowEventProperty"
            },
            "description": "The properties of the event pattern, which can be used in emails."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": ["id", "typeName", "nextNodeIds", "reEligible"]
      },
      "ContactPropertyTriggerWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["ContactPropertyTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "contactPropertyQuery": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/WorkflowContactPropertyQuery"
              },
              {
                "type": "null"
              }
            ]
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": [
          "id",
          "typeName",
          "nextNodeIds",
          "contactPropertyQuery",
          "reEligible"
        ]
      },
      "AddToListTriggerWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["AddToListTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of the mailing list this trigger sends to, if set."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": [
          "id",
          "typeName",
          "nextNodeIds",
          "mailingListId",
          "reEligible"
        ]
      },
      "BlankTriggerWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["BlankTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "typeName", "nextNodeIds"]
      },
      "AudienceFilterWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["AudienceFilter"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilter"
          },
          "audienceSegmentId": {
            "type": "string",
            "description": "The ID of the audience segment this trigger targets."
          },
          "appliesDownstream": {
            "description": "If `true`, the audience filter will apply to all downstream nodes. If `false`, the audience filter will only apply to the current node. Matches the \"Filter scope\" option in the UI.",
            "type": "boolean"
          }
        },
        "required": ["id", "typeName", "nextNodeIds", "appliesDownstream"]
      },
      "TimerActionWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["TimerAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "amount": {
            "$ref": "#/components/schemas/WorkflowTimerAmount"
          },
          "unit": {
            "$ref": "#/components/schemas/WorkflowTimerUnit"
          }
        },
        "required": ["id", "typeName", "nextNodeIds", "amount", "unit"]
      },
      "SendEmailActionWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["SendEmailAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "emailMessageId": {
            "type": "string",
            "description": "The ID of the email message to send. To edit this email, use the `POST /v1/email-messages/{emailMessageId}` endpoint."
          },
          "subject": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "typeName",
          "nextNodeIds",
          "emailMessageId",
          "subject"
        ]
      },
      "ExitActionWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["ExitAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "typeName", "nextNodeIds"]
      },
      "BranchWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["BranchNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "typeName", "nextNodeIds"]
      },
      "ExperimentBranchWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["ExperimentBranchNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "samplingRate": {
            "type": "number",
            "description": "The percentage of contacts that will be sent to variant branches, between `0` and `100`. The remaining percentage will be sent to the control branch. `100` sends all contacts to variant branches."
          }
        },
        "required": ["id", "typeName", "nextNodeIds", "samplingRate"]
      },
      "VariantWorkflowMutationNode": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "typeName": {
            "type": "string",
            "enum": ["VariantNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "isControl": {
            "type": "boolean",
            "description": "Whether this is the control variant of an experiment."
          }
        },
        "required": ["id", "typeName", "nextNodeIds"]
      },
      "UpdateWorkflowNodePayload": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/WorkflowSignupTriggerPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowEventTriggerPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowContactPropertyTriggerPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowAddToListTriggerPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowAudienceFilterPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowTimerActionPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowExperimentBranchPayload"
          },
          {
            "$ref": "#/components/schemas/WorkflowVariantPayload"
          }
        ],
        "description": "Node-type-specific fields to update. The allowed fields depend on the existing node type. Trigger node updates may include `typeName` when changing one trigger node type to another trigger node type."
      },
      "WorkflowSignupTriggerPayload": {
        "type": "object",
        "description": "Changes an existing trigger node to a signup trigger.",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["SignupTrigger"]
          }
        },
        "required": ["typeName"],
        "additionalProperties": false
      },
      "WorkflowEventTriggerPayload": {
        "type": "object",
        "description": "Updates an event trigger, or changes an existing trigger node to an event trigger. Assign the event pattern with either `eventPatternId` or `eventName`, not both. Set either field to `null` to clear the event-pattern relationship.",
        "minProperties": 1,
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["EventTrigger"]
          },
          "eventPatternId": {
            "type": ["string", "null"],
            "description": "The ID of the event pattern to trigger on. Use either `eventPatternId` or `eventName`, not both. Set to `null` to clear the event-pattern relationship."
          },
          "eventName": {
            "type": ["string", "null"],
            "description": "The name of the event pattern to trigger on. Use this when you know the event name but not the internal event pattern ID. Use either `eventName` or `eventPatternId`, not both. Set to `null` to clear the event-pattern relationship."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "additionalProperties": false
      },
      "WorkflowContactPropertyTriggerPayload": {
        "type": "object",
        "description": "Updates a contact-property trigger, or changes an existing trigger node to a contact-property trigger.",
        "minProperties": 1,
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["ContactPropertyTrigger"]
          },
          "contactPropertyQuery": {
            "$ref": "#/components/schemas/WorkflowContactPropertyQuery"
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "additionalProperties": false
      },
      "WorkflowAddToListTriggerPayload": {
        "type": "object",
        "description": "Updates an add-to-list trigger, or changes an existing trigger node to an add-to-list trigger.",
        "minProperties": 1,
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["AddToListTrigger"]
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "additionalProperties": false
      },
      "WorkflowAudienceFilterPayload": {
        "type": "object",
        "minProperties": 1,
        "description": "Configuration for the audience filter node.",
        "properties": {
          "audienceSegmentId": {
            "type": ["string", "null"],
            "description": "The ID of an audience segment. Setting this without also providing `audienceFilter` clears any existing `audienceFilter`. If both are provided, the filter is applied on top of the segment's filter."
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilterInRequest"
          },
          "appliesDownstream": {
            "type": "boolean",
            "description": "If `true`, the audience filter will apply to all downstream nodes. If `false`, the audience filter will only apply to the current node. Matches the \"Filter scope\" option in the UI."
          }
        },
        "additionalProperties": false
      },
      "WorkflowTimerActionPayload": {
        "type": "object",
        "minProperties": 1,
        "description": "Configuration for the timer action node.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/WorkflowTimerAmount"
          },
          "unit": {
            "$ref": "#/components/schemas/WorkflowTimerUnit"
          }
        },
        "additionalProperties": false
      },
      "WorkflowExperimentBranchPayload": {
        "type": "object",
        "minProperties": 1,
        "description": "Configuration for the experiment branch node.",
        "properties": {
          "samplingRate": {
            "type": "number",
            "description": "The percentage of contacts that will be sent to variant branches, between `0` and `100`. The remaining percentage will be sent to the control branch. `100` sends all contacts to variant branches."
          }
        },
        "additionalProperties": false
      },
      "WorkflowVariantPayload": {
        "type": "object",
        "minProperties": 1,
        "description": "Configuration for the variant node.",
        "properties": {
          "isControl": {
            "type": "boolean",
            "description": "Use `true` to set this variant as the control of the experiment. This will set `false` on the existing control, if one exists. Experiments do not require a control variant."
          }
        },
        "additionalProperties": false
      },
      "CreateWorkflowNodeTypeName": {
        "type": "string",
        "enum": [
          "AudienceFilter",
          "BranchNode",
          "ExperimentBranchNode",
          "TimerAction",
          "SendEmailAction",
          "VariantNode"
        ],
        "description": "Node types that can be created with the API. `*Trigger` nodes and `ExitAction` nodes cannot be created."
      },
      "CreateWorkflowNodeBetweenRequest": {
        "type": "object",
        "description": "Insert a new node between two existing nodes, `fromNodeId` and `toNodeId`. When `fromNodeId` is an `ExperimentBranchNode`, `nodeTypeName` must be `VariantNode`, and `toNodeId` cannot already be a `VariantNode`; use add-branch to add sibling variants. Branch paths can be edited with create-node, but a workflow cannot be started unless each direct `BranchNode` child is an `AudienceFilter`.",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          },
          "insertMode": {
            "type": "string",
            "enum": ["between"]
          },
          "nodeTypeName": {
            "$ref": "#/components/schemas/CreateWorkflowNodeTypeName"
          },
          "fromNodeId": {
            "type": "string",
            "description": "The node to insert after. This node must currently point to `toNodeId`. If this is an `ExperimentBranchNode`, `nodeTypeName` must be `VariantNode` and `toNodeId` cannot already be a `VariantNode`."
          },
          "toNodeId": {
            "type": "string",
            "description": "The node to insert before."
          }
        },
        "required": [
          "expectedRevisionId",
          "insertMode",
          "nodeTypeName",
          "fromNodeId",
          "toNodeId"
        ],
        "additionalProperties": false
      },
      "CreateWorkflowNodeBeforeRequest": {
        "type": "object",
        "description": "Insert a new node before `beforeNodeId`. `VariantNode` cannot use `insertMode: \"before\"`; to restore a missing variant path, use `insertMode: \"between\"` with the experiment branch as `fromNodeId`.",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          },
          "insertMode": {
            "type": "string",
            "enum": ["before"]
          },
          "nodeTypeName": {
            "$ref": "#/components/schemas/CreateWorkflowNodeTypeName"
          },
          "beforeNodeId": {
            "type": "string",
            "description": "The node to insert before. The target must have at least one incoming parent and cannot be a trigger node."
          }
        },
        "required": [
          "expectedRevisionId",
          "insertMode",
          "nodeTypeName",
          "beforeNodeId"
        ],
        "additionalProperties": false
      },
      "CreateWorkflowNodeRequest": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/CreateWorkflowNodeBetweenRequest"
          },
          {
            "$ref": "#/components/schemas/CreateWorkflowNodeBeforeRequest"
          }
        ],
        "description": "Create a new workflow node with an explicit `insertMode`. To configure the node after creation, use the `POST /v1/workflows/{workflowId}/nodes/{nodeId}` endpoint.",
        "discriminator": {
          "propertyName": "insertMode",
          "mapping": {
            "between": "#/components/schemas/CreateWorkflowNodeBetweenRequest",
            "before": "#/components/schemas/CreateWorkflowNodeBeforeRequest"
          }
        }
      },
      "WorkflowMutationNodeWithRevision": {
        "description": "Detailed workflow node returned from a mutation, plus the latest workflow revision token.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/SignupTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/EventTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/AddToListTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/BlankTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/AudienceFilterWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/TimerActionWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/SendEmailActionWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/ExitActionWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/BranchWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/ExperimentBranchWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/VariantWorkflowMutationNodeWithRevision"
          }
        ],
        "discriminator": {
          "propertyName": "typeName",
          "mapping": {
            "SignupTrigger": "#/components/schemas/SignupTriggerWorkflowMutationNodeWithRevision",
            "EventTrigger": "#/components/schemas/EventTriggerWorkflowMutationNodeWithRevision",
            "ContactPropertyTrigger": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNodeWithRevision",
            "AddToListTrigger": "#/components/schemas/AddToListTriggerWorkflowMutationNodeWithRevision",
            "BlankTrigger": "#/components/schemas/BlankTriggerWorkflowMutationNodeWithRevision",
            "AudienceFilter": "#/components/schemas/AudienceFilterWorkflowMutationNodeWithRevision",
            "TimerAction": "#/components/schemas/TimerActionWorkflowMutationNodeWithRevision",
            "SendEmailAction": "#/components/schemas/SendEmailActionWorkflowMutationNodeWithRevision",
            "ExitAction": "#/components/schemas/ExitActionWorkflowMutationNodeWithRevision",
            "BranchNode": "#/components/schemas/BranchWorkflowMutationNodeWithRevision",
            "ExperimentBranchNode": "#/components/schemas/ExperimentBranchWorkflowMutationNodeWithRevision",
            "VariantNode": "#/components/schemas/VariantWorkflowMutationNodeWithRevision"
          }
        }
      },
      "SignupTriggerWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SignupTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "EventTriggerWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EventTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "ContactPropertyTriggerWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "AddToListTriggerWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AddToListTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "BlankTriggerWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BlankTriggerWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "AudienceFilterWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AudienceFilterWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "TimerActionWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TimerActionWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "SendEmailActionWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SendEmailActionWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "ExitActionWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExitActionWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "BranchWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BranchWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "ExperimentBranchWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExperimentBranchWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "VariantWorkflowMutationNodeWithRevision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/VariantWorkflowMutationNode"
          },
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeRevision"
          }
        ]
      },
      "CreatedWorkflowNode": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WorkflowMutationNodeWithRevision"
          },
          {
            "type": "object",
            "properties": {
              "createdChildNodes": {
                "type": "array",
                "description": "Default child nodes created along with the requested node. BranchNode creation returns two AudienceFilter children. ExperimentBranchNode creation returns two regular VariantNode children and one control VariantNode.",
                "items": {
                  "$ref": "#/components/schemas/WorkflowMutationNode"
                }
              }
            }
          }
        ]
      },
      "CreateWorkflowNodeResponse": {
        "type": "object",
        "properties": {
          "node": {
            "$ref": "#/components/schemas/CreatedWorkflowNode"
          },
          "workflow": {
            "$ref": "#/components/schemas/SimplifiedWorkflow"
          }
        },
        "required": ["node", "workflow"],
        "additionalProperties": false
      },
      "AddWorkflowBranchRequest": {
        "type": "object",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          }
        },
        "required": ["expectedRevisionId"],
        "additionalProperties": false
      },
      "AddWorkflowBranchResponse": {
        "type": "object",
        "properties": {
          "node": {
            "$ref": "#/components/schemas/WorkflowMutationNodeWithRevision"
          },
          "workflow": {
            "$ref": "#/components/schemas/SimplifiedWorkflow"
          }
        },
        "required": ["node", "workflow"],
        "additionalProperties": false
      },
      "UpdateWorkflowNodeRequest": {
        "type": "object",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          },
          "payload": {
            "$ref": "#/components/schemas/UpdateWorkflowNodePayload"
          }
        },
        "required": ["expectedRevisionId", "payload"],
        "additionalProperties": false
      },
      "UpdateWorkflowNodeResponse": {
        "description": "The updated workflow node. The exact fields depend on `typeName`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/SignupTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/EventTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/AddToListTriggerWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/AudienceFilterWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/TimerActionWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/ExperimentBranchWorkflowMutationNodeWithRevision"
          },
          {
            "$ref": "#/components/schemas/VariantWorkflowMutationNodeWithRevision"
          }
        ],
        "discriminator": {
          "propertyName": "typeName",
          "mapping": {
            "SignupTrigger": "#/components/schemas/SignupTriggerWorkflowMutationNodeWithRevision",
            "EventTrigger": "#/components/schemas/EventTriggerWorkflowMutationNodeWithRevision",
            "ContactPropertyTrigger": "#/components/schemas/ContactPropertyTriggerWorkflowMutationNodeWithRevision",
            "AddToListTrigger": "#/components/schemas/AddToListTriggerWorkflowMutationNodeWithRevision",
            "AudienceFilter": "#/components/schemas/AudienceFilterWorkflowMutationNodeWithRevision",
            "TimerAction": "#/components/schemas/TimerActionWorkflowMutationNodeWithRevision",
            "ExperimentBranchNode": "#/components/schemas/ExperimentBranchWorkflowMutationNodeWithRevision",
            "VariantNode": "#/components/schemas/VariantWorkflowMutationNodeWithRevision"
          }
        }
      },
      "DeleteWorkflowNodeRequest": {
        "type": "object",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          },
          "dryRun": {
            "type": "boolean",
            "description": "If `true`, the request will be validated but the workflow will not be modified."
          },
          "queuedContactPolicy": {
            "$ref": "#/components/schemas/WorkflowQueuedContactPolicy"
          }
        },
        "required": ["expectedRevisionId"],
        "additionalProperties": false
      },
      "WorkflowQueuedContactDeletePreview": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["dryRun", "queuedContactsFound"]
          },
          "nodeIds": {
            "type": "array",
            "items": { "type": "string" },
            "description": "The IDs of the nodes that would be deleted."
          },
          "queuedContactCount": {
            "type": "number",
            "description": "The number of queued contacts that would be removed from the workflow due to the node deletion."
          }
        },
        "required": ["status", "nodeIds", "queuedContactCount"]
      },
      "WorkflowDeletedResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["deleted"]
          },
          "nodeIds": {
            "type": "array",
            "items": { "type": "string" }
          },
          "workflowRevisionId": {
            "$ref": "#/components/schemas/WorkflowRevisionId"
          },
          "queuedContactCount": {
            "type": "number",
            "description": "The number of queued contacts that were removed from the workflow due to the node deletion."
          }
        },
        "required": [
          "status",
          "nodeIds",
          "workflowRevisionId",
          "queuedContactCount"
        ]
      },
      "DeleteWorkflowNodeResponse": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/WorkflowQueuedContactDeletePreview"
          },
          {
            "$ref": "#/components/schemas/WorkflowDeletedResponse"
          }
        ]
      },
      "ChangeWorkflowMailingListRequest": {
        "type": "object",
        "properties": {
          "expectedRevisionId": {
            "$ref": "#/components/schemas/WorkflowExpectedRevisionId"
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The mailing list to use for the workflow. When assigning a mailing list, queued contacts excluded by the new list can return `queuedContactsFound`; retry with `queuedContactPolicy: \"discard\"` to apply the change and discard those contacts. Use `null` to clear the workflow mailing list; clearing does not discard queued contacts."
          },
          "dryRun": {
            "type": "boolean",
            "description": "If `true`, the request will be validated but the workflow will not be modified."
          },
          "queuedContactPolicy": {
            "$ref": "#/components/schemas/WorkflowQueuedContactPolicy"
          }
        },
        "required": ["expectedRevisionId", "mailingListId"],
        "additionalProperties": false
      },
      "WorkflowMailingListPreview": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["dryRun", "queuedContactsFound"]
          },
          "mailingListId": {
            "type": ["string", "null"]
          },
          "queuedContactCount": {
            "type": "number",
            "description": "The number of queued contacts that would be removed from the workflow due to the mailing list changing."
          }
        },
        "required": ["status", "mailingListId", "queuedContactCount"]
      },
      "WorkflowMailingListUpdatedResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["updated"]
          },
          "mailingListId": {
            "type": ["string", "null"]
          },
          "workflowRevisionId": {
            "$ref": "#/components/schemas/WorkflowRevisionId"
          },
          "queuedContactCount": {
            "type": "number",
            "description": "The number of queued contacts that were removed from the workflow due to the mailing list changing."
          }
        },
        "required": [
          "status",
          "mailingListId",
          "workflowRevisionId",
          "queuedContactCount"
        ]
      },
      "ChangeWorkflowMailingListResponse": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/WorkflowMailingListPreview"
          },
          {
            "$ref": "#/components/schemas/WorkflowMailingListUpdatedResponse"
          }
        ]
      },
      "EventPatternSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the event pattern."
          },
          "eventName": {
            "type": "string",
            "description": "The name of the event pattern. Use this when sending events with the API."
          },
          "incomingWebhookPlatform": {
            "type": ["string", "null"],
            "description": "The platform that sent this event pattern, if the event pattern is from an incoming webhook. Will be `null` for custom events.",
            "enum": ["clerk", "polar", "stripe", "supabase", "null"]
          }
        },
        "required": ["id", "eventName", "incomingWebhookPlatform"]
      },
      "ListEventPatternsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "type": "object",
            "properties": {
              "totalResults": { "type": "number" },
              "returnedResults": { "type": "number" },
              "perPage": { "type": "number" },
              "totalPages": { "type": "number" },
              "nextCursor": {
                "type": ["string", "null"]
              },
              "nextPage": {
                "type": ["string", "null"]
              }
            }
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventPatternSummary"
            }
          }
        },
        "required": ["pagination", "data"]
      },
      "EventPattern": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "eventName": {
            "type": "string",
            "description": "The name of the event pattern. Use this when sending events with the API."
          },
          "eventProperties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowEventProperty"
            },
            "description": "The properties of the event pattern, which can be used in emails."
          },
          "incomingWebhookPlatform": {
            "type": ["string", "null"],
            "description": "The platform that sent this event pattern, if the event pattern is from an incoming webhook. Will be `null` for custom events.",
            "enum": ["clerk", "polar", "stripe", "supabase", "null"]
          }
        },
        "required": [
          "id",
          "eventName",
          "eventProperties",
          "incomingWebhookPlatform"
        ]
      },
      "EventPatternFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"]
      },
      "SimplifiedWorkflowNode": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/SimplifiedSignupTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedEventTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedContactPropertyTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedAddToListTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedBlankTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedAudienceFilterWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedTimerActionWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedSendEmailActionWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedExitActionWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedBranchWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedExperimentBranchWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SimplifiedVariantWorkflowNode"
          }
        ],
        "discriminator": {
          "propertyName": "typeName"
        }
      },
      "SimplifiedSignupTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["SignupTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "SimplifiedEventTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["EventTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "eventName": {
            "type": ["string", "null"],
            "description": "The name of the event that triggers the workflow."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": ["typeName", "nextNodeIds", "eventName", "reEligible"],
        "additionalProperties": false,
        "examples": [
          {
            "typeName": "EventTrigger",
            "nextNodeIds": ["cln1a3b5c7d9e1f3g5h7i9j1"],
            "eventName": "signup",
            "reEligible": false
          }
        ]
      },
      "SimplifiedContactPropertyTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["ContactPropertyTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "contactPropertyQuery": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/WorkflowContactPropertyQuery"
              },
              {
                "type": "null"
              }
            ]
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": [
          "typeName",
          "nextNodeIds",
          "contactPropertyQuery",
          "reEligible"
        ],
        "additionalProperties": false
      },
      "SimplifiedAddToListTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["AddToListTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "mailingListId": {
            "type": ["string", "null"],
            "description": "The ID of the mailing list that triggers the workflow."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": ["typeName", "nextNodeIds", "mailingListId", "reEligible"],
        "additionalProperties": false
      },
      "SimplifiedBlankTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["BlankTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "SimplifiedAudienceFilterWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["AudienceFilter"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "SimplifiedTimerActionWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["TimerAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "amount": {
            "$ref": "#/components/schemas/WorkflowTimerAmount"
          },
          "unit": {
            "$ref": "#/components/schemas/WorkflowTimerUnit"
          }
        },
        "required": ["typeName", "nextNodeIds", "amount", "unit"],
        "additionalProperties": false,
        "examples": [
          {
            "typeName": "TimerAction",
            "nextNodeIds": ["cln1a3b5c7d9e1f3g5h7i9j1"],
            "amount": 2,
            "unit": "d"
          }
        ]
      },
      "SimplifiedSendEmailActionWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["SendEmailAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "emailMessageId": {
            "type": ["string", "null"],
            "description": "The ID of the email message to send. To edit this email, use the `POST /v1/email-messages/{emailMessageId}` endpoint."
          },
          "subject": {
            "type": "string",
            "description": "The subject of the email message (reference only)."
          }
        },
        "required": ["typeName", "nextNodeIds", "emailMessageId", "subject"],
        "additionalProperties": false,
        "examples": [
          {
            "typeName": "SendEmailAction",
            "nextNodeIds": [],
            "emailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
            "subject": "Welcome to Acme!"
          }
        ]
      },
      "SimplifiedExitActionWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["ExitAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "SimplifiedBranchWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["BranchNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "SimplifiedExperimentBranchWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["ExperimentBranchNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "samplingRate": {
            "type": "number",
            "description": "The percentage of contacts that will be sent to variant branches, between `0` and `100`. The remaining percentage will be sent to the control branch."
          }
        },
        "required": ["typeName", "nextNodeIds", "samplingRate"],
        "additionalProperties": false
      },
      "SimplifiedVariantWorkflowNode": {
        "type": "object",
        "properties": {
          "typeName": {
            "type": "string",
            "enum": ["VariantNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "isControl": {
            "type": "boolean",
            "description": "Whether this is the control variant of an experiment."
          }
        },
        "required": ["typeName", "nextNodeIds", "isControl"],
        "additionalProperties": false
      },
      "WorkflowNode": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/SignupTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/EventTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/ContactPropertyTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/AddToListTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/BlankTriggerWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/AudienceFilterWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/TimerActionWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/SendEmailActionWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/ExitActionWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/BranchWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/ExperimentBranchWorkflowNode"
          },
          {
            "$ref": "#/components/schemas/VariantWorkflowNode"
          }
        ],
        "discriminator": {
          "propertyName": "typeName"
        }
      },
      "WorkflowNodeWithRevision": {
        "description": "Detailed workflow node returned from read operations. The exact fields depend on `typeName`.",
        "allOf": [
          {
            "$ref": "#/components/schemas/WorkflowNode"
          },
          {
            "type": "object",
            "properties": {
              "workflowRevisionId": {
                "$ref": "#/components/schemas/NullableWorkflowRevisionId"
              }
            },
            "required": ["workflowRevisionId"]
          }
        ]
      },
      "SignupTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["SignupTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "workflowId", "typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "EventTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["EventTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "eventName": {
            "type": "string",
            "examples": ["signup"],
            "description": "The name of the event pattern that triggers this node."
          },
          "eventProperties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowEventProperty"
            },
            "description": "The properties of the event pattern, which can be used in emails."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "reEligible"
        ],
        "additionalProperties": false
      },
      "ContactPropertyTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["ContactPropertyTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "contactPropertyQuery": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/WorkflowContactPropertyQuery"
              },
              {
                "type": "null"
              }
            ]
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "contactPropertyQuery",
          "reEligible"
        ],
        "additionalProperties": false
      },
      "AddToListTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["AddToListTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "mailingListId": {
            "type": ["string", "null"],
            "examples": ["clm2k8j4h6g0f8d6s4a2b0z8", null],
            "description": "The ID of the mailing list that triggers the workflow."
          },
          "reEligible": {
            "$ref": "#/components/schemas/WorkflowReEligible"
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "mailingListId",
          "reEligible"
        ],
        "additionalProperties": false
      },
      "BlankTriggerWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["BlankTrigger"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "workflowId", "typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "AudienceFilterWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["AudienceFilter"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "audienceFilter": {
            "$ref": "#/components/schemas/AudienceFilter"
          },
          "audienceSegmentId": {
            "type": "string"
          },
          "appliesDownstream": {
            "description": "If `true`, the audience filter will apply to all downstream nodes. If `false`, the audience filter will only apply to the current node. Matches the \"Filter scope\" option in the UI.",
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "appliesDownstream"
        ],
        "additionalProperties": false
      },
      "TimerActionWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["TimerAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "amount": {
            "$ref": "#/components/schemas/WorkflowTimerAmount"
          },
          "unit": {
            "$ref": "#/components/schemas/WorkflowTimerUnit"
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "amount",
          "unit"
        ],
        "additionalProperties": false
      },
      "SendEmailActionWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["SendEmailAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "emailMessageId": {
            "type": "string",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"],
            "description": "The ID of the email message to send. To edit this email, use the `POST /v1/email-messages/{emailMessageId}` endpoint."
          },
          "subject": {
            "type": "string",
            "examples": ["Welcome to Acme!"]
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "emailMessageId",
          "subject"
        ],
        "additionalProperties": false
      },
      "ExitActionWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["ExitAction"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "workflowId", "typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "BranchWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["BranchNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          }
        },
        "required": ["id", "workflowId", "typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "ExperimentBranchWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["ExperimentBranchNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "samplingRate": {
            "type": "number",
            "description": "The percentage of contacts that will be sent to variant branches, between `0` and `100`. The remaining percentage will be sent to the control branch. `100` sends all contacts to variant branches."
          }
        },
        "required": [
          "id",
          "workflowId",
          "typeName",
          "nextNodeIds",
          "samplingRate"
        ],
        "additionalProperties": false
      },
      "VariantWorkflowNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cln8p0q2r4s6t8u0v2w4x6z8"]
          },
          "workflowId": {
            "type": "string",
            "examples": ["clw1a3b5c7d9e1f3g5h7i9j1"]
          },
          "typeName": {
            "type": "string",
            "enum": ["VariantNode"]
          },
          "nextNodeIds": {
            "$ref": "#/components/schemas/WorkflowNextNodeIds"
          },
          "isControl": {
            "type": "boolean",
            "description": "Whether this is the control variant of an experiment."
          }
        },
        "required": ["id", "workflowId", "typeName", "nextNodeIds"],
        "additionalProperties": false
      },
      "WorkflowEventProperty": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": ["string", "number", "boolean", "date"]
          }
        },
        "required": ["name", "type"]
      },
      "WorkflowContactPropertyQuery": {
        "type": "object",
        "description": "Define the contact property change that triggers the workflow. In update requests, `key` must resolve to an existing contact property that is available for Contact Updated triggers. Hidden or unsupported fields, such as `createdAt`, `notes`, and computed contact properties, are rejected.",
        "properties": {
          "key": {
            "type": "string",
            "description": "The camel-cased `key` of the contact property to query. The property must exist for the team and must be available for Contact Updated triggers.",
            "examples": ["firstName", "email", "planName"]
          },
          "is": {
            "description": "Comparison for the new contact property value after the update.",
            "$ref": "#/components/schemas/WorkflowContactPropertyComparison"
          },
          "was": {
            "description": "Comparison for the previous contact property value before the update.",
            "$ref": "#/components/schemas/WorkflowContactPropertyComparison"
          }
        },
        "required": ["key", "is", "was"]
      },
      "WorkflowContactPropertyComparison": {
        "type": "object",
        "description": "For Contact Updated triggers, the API validates `operator` against the selected contact property's type and the side of the comparison. The `was` comparison can use any operator supported by the selected property type. The `is` comparison uses the same operators, except number and boolean properties cannot use `empty`. String properties support `any`, `equal`, `not_equal`, `contains`, `not_contains`, `empty`, and `not_empty`. Number properties support `any`, `greater_than`, `less_than`, `numeric_equal`, `numeric_not_equal`, `empty`, and `not_empty`. Boolean properties support `any`, `true`, `false`, `empty`, and `not_empty`. Date properties support `any`, `empty`, `not_empty`, `after`, `before`, and `between`.",
        "properties": {
          "value": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "operator": {
            "type": "string",
            "description": "The comparison operator. It must be valid for the selected contact property's type and for the `is` or `was` side of the comparison. Number and boolean properties allow `empty` on `was`, but not on `is`.",
            "enum": [
              "any",
              "contains",
              "not_contains",
              "empty",
              "not_empty",
              "equal",
              "not_equal",
              "greater_than",
              "less_than",
              "true",
              "false",
              "numeric_equal",
              "numeric_not_equal",
              "after",
              "before",
              "between"
            ]
          }
        },
        "required": ["value", "operator"]
      },
      "WorkflowTimerAmount": {
        "type": "number",
        "description": "The amount of time to wait before triggering the next node. Set to `0` to move to the next node immediately."
      },
      "WorkflowTimerUnit": {
        "type": "string",
        "enum": ["m", "h", "d"],
        "description": "The unit of time for the timer action node. m = minutes, h = hours, d = days."
      },
      "WorkflowFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Workflow not found."
          }
        ]
      },
      "GroupResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the group.",
            "examples": ["clg7n5p3q1r9s7t5u3v1w9y7"]
          },
          "name": {
            "type": "string",
            "description": "The name of the group.",
            "examples": ["Onboarding"]
          },
          "description": {
            "type": "string",
            "description": "The description of the group.",
            "examples": ["Top of funnel campaigns"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the group was created."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"],
            "description": "ISO 8601 timestamp for when the group was last updated."
          }
        },
        "required": ["id", "name", "description", "createdAt", "updatedAt"],
        "examples": [
          {
            "id": "clg7n5p3q1r9s7t5u3v1w9y7",
            "name": "Onboarding",
            "description": "Top of funnel campaigns",
            "createdAt": "2025-06-29T07:47:39.370Z",
            "updatedAt": "2025-06-29T07:47:39.370Z"
          }
        ]
      },
      "ListGroupsResponse": {
        "type": "object",
        "properties": {
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GroupResponse"
            }
          }
        },
        "required": ["pagination", "data"],
        "examples": [
          {
            "pagination": {
              "totalResults": 2,
              "returnedResults": 2,
              "perPage": 20,
              "totalPages": 1,
              "nextCursor": null,
              "nextPage": null
            },
            "data": [
              {
                "id": "clg7n5p3q1r9s7t5u3v1w9y7",
                "name": "Onboarding",
                "description": "Top of funnel campaigns",
                "createdAt": "2025-06-29T07:47:39.370Z",
                "updatedAt": "2025-06-29T07:47:39.370Z"
              },
              {
                "id": "clg8m4n6p8q0r2s4t6u8v0w2",
                "name": "Retention",
                "description": "",
                "createdAt": "2025-06-30T12:00:00.000Z",
                "updatedAt": "2025-06-30T12:00:00.000Z"
              }
            ]
          }
        ]
      },
      "CreateGroupRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The group name. Cannot be the reserved name \"Unsorted\".",
            "examples": ["Newsletters"]
          },
          "description": {
            "type": "string",
            "description": "An optional description for the group.",
            "examples": ["Monthly newsletter campaigns"]
          }
        },
        "required": ["name"],
        "additionalProperties": false,
        "examples": [
          {
            "name": "Newsletters",
            "description": "Monthly newsletter campaigns"
          }
        ]
      },
      "UpdateGroupRequest": {
        "type": "object",
        "description": "At least one field must be provided.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The group name. Cannot be the reserved name \"Unsorted\"."
          },
          "description": {
            "type": "string",
            "description": "A description for the group."
          }
        },
        "additionalProperties": false
      },
      "GroupFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "examples": ["Group not found."]
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Group not found."
          }
        ]
      },
      "UpdateEmailMessageRequest": {
        "type": "object",
        "properties": {
          "expectedRevisionId": {
            "type": "string",
            "description": "The `contentRevisionId` you last fetched, or the `emailMessageContentRevisionId` you received when creating the campaign."
          },
          "subject": {
            "type": "string"
          },
          "previewText": {
            "type": "string"
          },
          "fromName": {
            "type": "string"
          },
          "fromEmail": {
            "type": "string",
            "description": "The email sender email address, without the team's sending domain.",
            "examples": ["hello"]
          },
          "replyToEmail": {
            "type": "string",
            "description": "Reply-to email. Must be empty or a valid email address."
          },
          "ccEmail": {
            "type": "string",
            "description": "CC email address. Requires the team to have CC/BCC enabled."
          },
          "bccEmail": {
            "type": "string",
            "description": "BCC email address. Requires the team to have CC/BCC enabled."
          },
          "languageCode": {
            "type": "string",
            "description": "ISO 639-1 language code for the email, e.g. `en` or `fr`."
          },
          "emailFormat": {
            "type": "string",
            "enum": ["styled", "plain"],
            "description": "The rendering format of the email."
          },
          "lmx": {
            "type": "string",
            "description": "The email body serialized as LMX. Styles must be embedded in the LMX `<Style />` tag."
          },
          "contactPropertiesFallbacks": {
            "type": "object",
            "description": "Fallback values for contact properties, keyed by property name. Per-key merge: a string value sets the fallback, a null value deletes it, and keys omitted from the map are left unchanged.",
            "additionalProperties": {
              "type": ["string", "null"]
            }
          },
          "eventPropertiesFallbacks": {
            "type": "object",
            "description": "Fallback values for event properties, keyed by property name. Per-key merge: a string value sets the fallback, a null value deletes it, and keys omitted from the map are left unchanged.",
            "additionalProperties": {
              "type": ["string", "null"]
            }
          },
          "dataVariablesFallbacks": {
            "type": "object",
            "description": "Fallback values for data variables, keyed by variable name. Per-key merge: a string value sets the fallback, a null value deletes it, and keys omitted from the map are left unchanged.",
            "additionalProperties": {
              "type": ["string", "null"]
            }
          }
        },
        "additionalProperties": false,
        "examples": [
          {
            "expectedRevisionId": "clrev1s10n2i3d4e5f6g7h8",
            "subject": "Spring product updates",
            "previewText": "See what's new this season",
            "fromName": "Acme Team",
            "fromEmail": "hello",
            "replyToEmail": "support@company.com",
            "emailFormat": "styled",
            "lmx": "<Paragraph>Hello, {firstName}!</Paragraph>",
            "contactPropertiesFallbacks": {
              "firstName": "there"
            }
          }
        ]
      },
      "EmailMessageResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"],
            "description": "The ID of the email message."
          },
          "campaignId": {
            "type": "string",
            "description": "The campaign this email message belongs to. Present only when the message belongs to a campaign (mutually exclusive with `transactionalId`).",
            "examples": ["clc4m6n8p0q2r4s6t8u0v2x4"]
          },
          "transactionalId": {
            "type": "string",
            "description": "The transactional email this email message belongs to. Present only when the message belongs to a transactional email (mutually exclusive with `campaignId`)."
          },
          "subject": {
            "type": "string",
            "description": "The email subject.",
            "examples": ["Spring product updates"]
          },
          "previewText": {
            "type": "string",
            "description": "The email preview text.",
            "examples": ["See what's new this season"]
          },
          "fromName": {
            "type": "string",
            "description": "The email sender name.",
            "examples": ["Acme Team"]
          },
          "fromEmail": {
            "type": "string",
            "description": "The email sender email address, without the team's sending domain.",
            "examples": ["hello"]
          },
          "replyToEmail": {
            "type": "string",
            "description": "The email reply-to address.",
            "examples": ["support@company.com"]
          },
          "ccEmail": {
            "type": "string",
            "description": "The email CC address. Only present when set."
          },
          "bccEmail": {
            "type": "string",
            "description": "The email BCC address. Only present when set."
          },
          "languageCode": {
            "type": "string",
            "description": "ISO 639-1 language code for the email, e.g. `en` or `fr`. Only present when set."
          },
          "emailFormat": {
            "type": "string",
            "enum": ["styled", "plain"],
            "description": "The rendering format of the email.",
            "examples": ["styled"]
          },
          "lmx": {
            "type": "string",
            "description": "The email body serialized as LMX.",
            "examples": ["<Paragraph>Hello, {firstName}!</Paragraph>"]
          },
          "contentRevisionId": {
            "type": ["string", "null"],
            "description": "The current content revision. Pass this as `expectedRevisionId` on your next update.",
            "examples": ["clrev1s10n2i3d4e5f6g7h8"]
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "examples": ["2025-06-29T07:47:39.370Z"]
          },
          "contactPropertiesFallbacks": {
            "type": "object",
            "description": "Fallback values for contact properties. Only present when set.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "eventPropertiesFallbacks": {
            "type": "object",
            "description": "Fallback values for event properties. Only present when set.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "dataVariablesFallbacks": {
            "type": "object",
            "description": "Fallback values for data variables. Only present when set.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "warnings": {
            "type": "array",
            "description": "Non-fatal issues raised while compiling the submitted LMX. Only present on update responses when warnings were produced.",
            "items": {
              "type": "object",
              "properties": {
                "rule": {
                  "type": "string"
                },
                "severity": {
                  "type": "string",
                  "enum": ["warning"]
                },
                "message": {
                  "type": "string"
                },
                "path": {
                  "type": "string"
                }
              },
              "required": ["rule", "severity", "message"]
            }
          }
        },
        "required": [
          "id",
          "subject",
          "previewText",
          "fromName",
          "fromEmail",
          "replyToEmail",
          "emailFormat",
          "lmx",
          "contentRevisionId",
          "updatedAt"
        ],
        "examples": [
          {
            "id": "cle5f7g9h1i3j5k7l9m1n3p5",
            "campaignId": "clc4m6n8p0q2r4s6t8u0v2x4",
            "subject": "Spring product updates",
            "previewText": "See what's new this season",
            "fromName": "Acme Team",
            "fromEmail": "hello",
            "replyToEmail": "support@company.com",
            "emailFormat": "styled",
            "lmx": "<Paragraph>Hello, {firstName}!</Paragraph>",
            "contentRevisionId": "clrev1s10n2i3d4e5f6g7h8",
            "updatedAt": "2025-06-29T07:47:39.370Z"
          }
        ]
      },
      "EmailMessageFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Email message not found."
          }
        ]
      },
      "EmailMessagePreviewRequest": {
        "type": "object",
        "properties": {
          "emails": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "One or more addresses to send the preview to."
          },
          "contactProperties": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Contact property values to render. Accepted for campaign and workflow previews.",
            "example": {
              "firstName": "Alex"
            }
          },
          "eventProperties": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Event property values to render. Accepted for workflow previews only.",
            "example": {
              "planName": "Pro"
            }
          },
          "dataVariables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Transactional data variables to render. Accepted for transactional previews only.",
            "example": {
              "loginUrl": "https://app.company.com/login"
            }
          }
        },
        "required": ["emails"],
        "additionalProperties": false,
        "examples": [
          {
            "emails": ["alex@company.com"],
            "contactProperties": {
              "firstName": "Alex"
            },
            "eventProperties": {
              "planName": "Pro"
            },
            "dataVariables": {
              "loginUrl": "https://app.company.com/login"
            }
          }
        ]
      },
      "EmailMessagePreviewResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the email message the preview was sent for.",
            "examples": ["cle5f7g9h1i3j5k7l9m1n3p5"]
          }
        },
        "required": ["id"],
        "examples": [
          {
            "id": "cle5f7g9h1i3j5k7l9m1n3p5"
          }
        ]
      },
      "EmailMessageGuardianResponse": {
        "type": "object",
        "properties": {
          "errors": {
            "type": "array",
            "description": "Validation errors. These must be resolved before the email can be published.",
            "items": {
              "$ref": "#/components/schemas/GuardianRule"
            }
          },
          "warnings": {
            "type": "array",
            "description": "Validation warnings. These are advisory and do not block publishing.",
            "items": {
              "$ref": "#/components/schemas/GuardianRule"
            }
          }
        },
        "required": ["errors", "warnings"],
        "example": {
          "errors": [
            {
              "rule": "missingButtonHrefs",
              "title": "Missing button link",
              "description": "Buttons won't work without href value",
              "items": [
                {
                  "label": "Click here"
                }
              ]
            },
            {
              "rule": "missingLinkHrefs",
              "title": "Missing text link",
              "description": "Links won't work without href value",
              "items": [
                {
                  "label": "See more"
                }
              ]
            }
          ],
          "warnings": []
        }
      },
      "GuardianRule": {
        "type": "object",
        "properties": {
          "rule": {
            "type": "string",
            "description": "The identifier of the Guardian rule that fired.",
            "enum": [
              "unsupportedContactProperties",
              "missingFallbackContactProperties",
              "unsupportedEventProperties",
              "missingFallbackEventProperties",
              "unsupportedDataVariables",
              "invalidCustomDataVariables",
              "missingRequiredDataVariables",
              "missingButtonHrefs",
              "invalidButtonHrefs",
              "shortenedYouTubeButtonHrefs",
              "missingLinkHrefs",
              "invalidLinkHrefs",
              "shortenedYouTubeLinkHrefs",
              "shortenedYouTubeImageHrefs",
              "emailWithoutMailtoButtonHrefs",
              "emailWithoutMailtoLinkHrefs",
              "emailWithoutMailtoImageHrefs",
              "bareArrayNodes",
              "missingSocialIconHrefs"
            ]
          },
          "title": {
            "type": "string",
            "description": "A short summary of the rule."
          },
          "description": {
            "type": "string",
            "description": "A longer explanation of why the issue matters."
          },
          "items": {
            "type": "array",
            "description": "The specific elements that triggered the rule.",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string",
                  "description": "A human-readable label for the item (for example, link text or a property name)."
                },
                "codeName": {
                  "type": "string",
                  "description": "Machine-readable identifier when the rule refers to a property or variable, when applicable.",
                  "example": "firstName"
                }
              },
              "required": ["label"]
            }
          }
        },
        "required": ["rule", "title", "description", "items"]
      },
      "CreateUploadRequest": {
        "type": "object",
        "properties": {
          "contentType": {
            "type": "string",
            "description": "The MIME type of the file to upload. Supported types are `image/jpeg`, `image/png`, `image/gif` and `image/webp`.",
            "examples": ["image/png"]
          },
          "contentLength": {
            "type": "integer",
            "description": "The size of the file in bytes. Must be a positive integer no greater than 4,000,000 bytes.",
            "examples": [102400]
          }
        },
        "required": ["contentType", "contentLength"],
        "additionalProperties": false
      },
      "CreateUploadResponse": {
        "type": "object",
        "properties": {
          "emailAssetId": {
            "type": "string",
            "examples": ["cla3s5s7e9t1i3d5f7g9h1j3"],
            "description": "The ID of the created asset. Pass this as `emailAssetId` to `POST /v1/uploads/{emailAssetId}/complete` once the file has been uploaded."
          },
          "presignedUrl": {
            "type": "string",
            "description": "The pre-signed URL to upload the file to with an HTTP `PUT` request. Send the same `Content-Type` and `Content-Length` used in the create request.",
            "examples": [
              "https://loops-assets.s3.amazonaws.com/uploads/cla3s5s7e9t1i3d5f7g9h1j3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=..."
            ]
          }
        },
        "required": ["emailAssetId", "presignedUrl"],
        "examples": [
          {
            "emailAssetId": "cla3s5s7e9t1i3d5f7g9h1j3",
            "presignedUrl": "https://loops-assets.s3.amazonaws.com/uploads/cla3s5s7e9t1i3d5f7g9h1j3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=..."
          }
        ]
      },
      "CompleteUploadResponse": {
        "type": "object",
        "properties": {
          "emailAssetId": {
            "type": "string",
            "examples": ["cla3s5s7e9t1i3d5f7g9h1j3"],
            "description": "The ID of the created asset."
          },
          "finalUrl": {
            "type": "string",
            "description": "The public URL of the uploaded asset.",
            "examples": [
              "https://assets.loops.so/cla3s5s7e9t1i3d5f7g9h1j3/logo.png"
            ]
          }
        },
        "required": ["emailAssetId", "finalUrl"],
        "examples": [
          {
            "emailAssetId": "cla3s5s7e9t1i3d5f7g9h1j3",
            "finalUrl": "https://assets.loops.so/cla3s5s7e9t1i3d5f7g9h1j3/logo.png"
          }
        ]
      },
      "UploadLimitExceededFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "examples": [
              "Upload limit exceeded: max 50 uploads per 24 hours. Please contact support if you need to increase your upload limit."
            ]
          },
          "maxUploads": {
            "type": "integer",
            "description": "The maximum number of uploads allowed per window.",
            "examples": [50]
          },
          "windowHours": {
            "type": "integer",
            "description": "The number of hours in the upload limit window.",
            "examples": [24]
          }
        }
      },
      "UploadFailureResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "examples": ["Unsupported content type."]
          },
          "supportedContentTypes": {
            "type": "array",
            "description": "Present when the request was rejected for an unsupported `contentType`. Lists the accepted MIME types.",
            "items": {
              "type": "string"
            }
          },
          "maxBytes": {
            "type": "integer",
            "description": "Present when the upload exceeds the size limit. The maximum allowed size in bytes."
          }
        },
        "required": ["message"],
        "examples": [
          {
            "message": "Unsupported content type.",
            "supportedContentTypes": [
              "image/jpeg",
              "image/png",
              "image/gif",
              "image/webp"
            ],
            "maxBytes": 4000000
          }
        ]
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "totalResults": {
            "type": "number",
            "examples": [2]
          },
          "returnedResults": {
            "type": "number",
            "examples": [2]
          },
          "perPage": {
            "type": "number",
            "examples": [20]
          },
          "totalPages": {
            "type": "number",
            "examples": [1]
          },
          "nextCursor": {
            "type": ["string", "null"],
            "examples": [null]
          },
          "nextPage": {
            "type": ["string", "null"],
            "examples": [null]
          }
        },
        "required": [
          "totalResults",
          "returnedResults",
          "perPage",
          "totalPages",
          "nextCursor",
          "nextPage"
        ],
        "examples": [
          {
            "totalResults": 2,
            "returnedResults": 2,
            "perPage": 20,
            "totalPages": 1,
            "nextCursor": null,
            "nextPage": null
          }
        ]
      },
      "WebhookContactIdentity": {
        "type": "object",
        "required": ["id", "email", "userId"],
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "userId": {
            "type": ["string", "null"]
          }
        }
      },
      "WebhookBasePayload": {
        "type": "object",
        "required": [
          "eventName",
          "eventTime",
          "webhookSchemaVersion",
          "contactIdentity"
        ],
        "properties": {
          "eventName": {
            "type": "string"
          },
          "eventTime": {
            "type": "integer",
            "description": "Unix timestamp in seconds."
          },
          "webhookSchemaVersion": {
            "type": "string",
            "const": "1.0.0"
          },
          "contactIdentity": {
            "$ref": "#/components/schemas/WebhookContactIdentity"
          }
        }
      },
      "WebhookContact": {
        "type": "object",
        "required": [
          "id",
          "email",
          "firstName",
          "lastName",
          "source",
          "subscribed",
          "userGroup",
          "userId",
          "mailingLists",
          "optInStatus"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "firstName": {
            "type": ["string", "null"]
          },
          "lastName": {
            "type": ["string", "null"]
          },
          "source": {
            "type": "string"
          },
          "subscribed": {
            "type": "boolean"
          },
          "userGroup": {
            "type": "string"
          },
          "userId": {
            "type": ["string", "null"]
          },
          "notes": {
            "type": ["string", "null"]
          },
          "mailingLists": {
            "type": "object",
            "description": "An object of mailing list IDs and boolean subscription statuses.",
            "additionalProperties": {
              "type": "boolean"
            }
          },
          "optInStatus": {
            "type": ["string", "null"],
            "description": "Double opt-in status.",
            "enum": ["accepted", "pending", "rejected", null]
          }
        },
        "additionalProperties": true,
        "description": "Full contact object, including custom properties."
      },
      "WebhookEmail": {
        "type": "object",
        "required": ["id", "emailMessageId", "subject"],
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the email."
          },
          "emailMessageId": {
            "type": "string",
            "description": "The ID of the sent version of the campaign, workflow or transactional email."
          },
          "subject": {
            "type": "string",
            "description": "The subject of the email."
          }
        }
      },
      "WebhookMailingList": {
        "type": "object",
        "description": "Details of the mailing list.",
        "required": ["id", "name", "description", "isPublic"],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": ["string", "null"]
          },
          "isPublic": {
            "type": "boolean"
          }
        }
      },
      "WebhookEmailMetricPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["email", "sourceType"],
            "properties": {
              "email": {
                "$ref": "#/components/schemas/WebhookEmail"
              },
              "sourceType": {
                "type": "string",
                "enum": ["loop", "campaign", "transactional"],
                "description": "The type of email this event relates to. Workflow emails use `loop`."
              },
              "campaignId": {
                "type": "string",
                "description": "The ID of the campaign if `sourceType` is `campaign`."
              },
              "loopId": {
                "type": "string",
                "description": "The ID of the workflow if `sourceType` is `loop`."
              },
              "transactionalId": {
                "type": "string",
                "description": "The ID of the transactional email if `sourceType` is `transactional`."
              }
            }
          }
        ]
      },
      "WebhookMarketingEmailMetricPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["email", "sourceType"],
            "properties": {
              "email": {
                "$ref": "#/components/schemas/WebhookEmail"
              },
              "sourceType": {
                "type": "string",
                "enum": ["loop", "campaign"],
                "description": "The type of email this event relates to. Workflow emails use `loop`. Not available for transactional emails."
              },
              "campaignId": {
                "type": "string",
                "description": "The ID of the campaign if `sourceType` is `campaign`."
              },
              "loopId": {
                "type": "string",
                "description": "The ID of the workflow if `sourceType` is `loop`."
              }
            }
          }
        ]
      },
      "WebhookContactUnsubscribedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "contact.unsubscribed"
              }
            }
          }
        ]
      },
      "WebhookContactCreatedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["eventName", "contact"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "contact.created"
              },
              "contact": {
                "$ref": "#/components/schemas/WebhookContact"
              }
            }
          }
        ]
      },
      "WebhookContactDeletedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "contact.deleted"
              }
            }
          }
        ]
      },
      "WebhookContactMailingListSubscribedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["eventName", "mailingList"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "contact.mailingList.subscribed"
              },
              "mailingList": {
                "$ref": "#/components/schemas/WebhookMailingList"
              }
            }
          }
        ]
      },
      "WebhookContactMailingListUnsubscribedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": ["eventName", "mailingList"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "contact.mailingList.unsubscribed"
              },
              "mailingList": {
                "$ref": "#/components/schemas/WebhookMailingList"
              }
            }
          }
        ]
      },
      "WebhookTransactionalEmailSentPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": [
              "eventName",
              "transactionalId",
              "email",
              "transactionalName"
            ],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "transactional.email.sent"
              },
              "transactionalId": {
                "type": "string"
              },
              "transactionalName": {
                "type": "string"
              },
              "email": {
                "$ref": "#/components/schemas/WebhookEmail"
              }
            }
          }
        ]
      },
      "WebhookCampaignEmailSentPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": [
              "eventName",
              "campaignId",
              "email",
              "mailingLists",
              "campaignName"
            ],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "campaign.email.sent"
              },
              "campaignId": {
                "type": "string"
              },
              "campaignName": {
                "type": "string"
              },
              "email": {
                "$ref": "#/components/schemas/WebhookEmail"
              },
              "mailingLists": {
                "type": "array",
                "description": "The mailing list(s) the email was sent to, or an empty array.",
                "items": {
                  "$ref": "#/components/schemas/WebhookMailingList"
                }
              }
            }
          }
        ]
      },
      "WebhookLoopEmailSentPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookBasePayload"
          },
          {
            "type": "object",
            "required": [
              "eventName",
              "loopId",
              "email",
              "mailingLists",
              "loopName"
            ],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "loop.email.sent"
              },
              "loopId": {
                "type": "string",
                "description": "The ID of the workflow."
              },
              "loopName": {
                "type": "string",
                "description": "The name of the workflow."
              },
              "email": {
                "$ref": "#/components/schemas/WebhookEmail"
              },
              "mailingLists": {
                "type": "array",
                "description": "The mailing list(s) the email was sent to, or an empty array.",
                "items": {
                  "$ref": "#/components/schemas/WebhookMailingList"
                }
              }
            }
          }
        ]
      },
      "WebhookEmailDeliveredPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.delivered"
              }
            }
          }
        ]
      },
      "WebhookEmailSoftBouncedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.softBounced"
              }
            }
          }
        ]
      },
      "WebhookEmailHardBouncedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.hardBounced"
              }
            }
          }
        ]
      },
      "WebhookEmailClickedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookMarketingEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.clicked"
              }
            }
          }
        ]
      },
      "WebhookEmailUnsubscribedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookMarketingEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.unsubscribed"
              }
            }
          }
        ]
      },
      "WebhookEmailResubscribedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookMarketingEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.resubscribed"
              }
            }
          }
        ]
      },
      "WebhookEmailOpenedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookMarketingEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.opened"
              }
            }
          }
        ]
      },
      "WebhookEmailSpamReportedPayload": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookEmailMetricPayload"
          },
          {
            "type": "object",
            "required": ["eventName"],
            "properties": {
              "eventName": {
                "type": "string",
                "const": "email.spamReported"
              }
            }
          }
        ]
      },
      "WebhookTestingTestEventPayload": {
        "type": "object",
        "required": [
          "eventName",
          "eventTime",
          "message",
          "webhookSchemaVersion"
        ],
        "properties": {
          "eventName": {
            "type": "string",
            "const": "testing.testEvent"
          },
          "eventTime": {
            "type": "integer",
            "description": "Unix timestamp in seconds."
          },
          "message": {
            "type": "string",
            "const": "test"
          },
          "webhookSchemaVersion": {
            "type": "string",
            "const": "1.0.0"
          }
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "parameters": {
      "WebhookId": {
        "name": "webhook-id",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Unique message ID. Use to deduplicate deliveries."
      },
      "WebhookTimestamp": {
        "name": "webhook-timestamp",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Unix timestamp of when the message was sent."
      },
      "WebhookSignature": {
        "name": "webhook-signature",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "HMAC signature for verifying the request. Verify using your endpoint signing secret from the Loops dashboard."
      }
    }
  }
}
