{
  "openapi": "3.1.0",
  "info": {
    "title": "Lettr API",
    "version": "1.0.0",
    "description": "Lettr Email API - Send transactional emails with tracking, attachments, and personalization.",
    "contact": {
      "name": "Lettr Support",
      "url": "https://lettr.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://lettr.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://app.lettr.com/api",
      "description": "Production"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health Check",
        "description": "Check the health status of the API. This endpoint does not require authentication.",
        "tags": [
          "System"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Health check passed."
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "status",
                        "timestamp"
                      ],
                      "properties": {
                        "status": {
                          "type": "string",
                          "example": "ok"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time",
                          "example": "2024-01-15T10:30:00.000Z"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Health check passed.",
                  "data": {
                    "status": "ok",
                    "timestamp": "2024-01-15T10:30:00.000Z"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/check": {
      "get": {
        "operationId": "authCheck",
        "summary": "Validate API Key",
        "description": "Validate the provided API key and return associated team information. Use this endpoint to verify API key validity in client libraries.",
        "tags": [
          "System"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "API key is valid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "API key is valid."
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "team_id",
                        "timestamp"
                      ],
                      "properties": {
                        "team_id": {
                          "type": "integer",
                          "description": "The team ID associated with the API key",
                          "example": 123
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time",
                          "example": "2024-01-15T10:30:00.000Z"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "API key is valid.",
                  "data": {
                    "team_id": 123,
                    "timestamp": "2024-01-15T10:30:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          }
        }
      }
    },
    "/emails": {
      "post": {
        "operationId": "sendEmail",
        "summary": "Send Email",
        "description": "Send a transactional email with optional attachments, tracking, and personalization. At least one of `html` or `text` content must be provided. Supply `Idempotency-Key` for safe retries using SparkPost native transmission idempotency. Keys are namespaced per Lettr API key and retained by SparkPost for 24 hours. Repeating the same transmission payload returns its original result without another delivery; conflicting payloads or in-progress transmissions return 409. Retry transport failures with the same key. Lettr still validates authorization, domains and sending quota before contacting SparkPost, so an exhausted quota returns 429 even for a retry. Replayed responses do not increment sending counters again. Requests without this header are sent independently.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A unique key for one logical send. Reuse it with the same payload and API key when retrying. SparkPost retains the key for 24 hours. If using a template, keep the resolved template content unchanged across retries.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9._-]{1,255}$"
            },
            "example": "order-confirmation-12345"
          }
        ],
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendEmailRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal request (required fields only)",
                  "description": "The absolute minimum required to send an email: from, to, subject, and either html or text content. Subject is required when not using a template.",
                  "value": {
                    "from": "sender@example.com",
                    "to": [
                      "recipient@example.com"
                    ],
                    "subject": "Hello",
                    "html": "<p>Hello!</p>"
                  }
                },
                "html-and-text": {
                  "summary": "HTML and plain text (recommended)",
                  "description": "Sending both HTML and plain text ensures email renders correctly in all email clients.",
                  "value": {
                    "from": "sender@example.com",
                    "from_name": "Sender Name",
                    "to": [
                      "recipient@example.com"
                    ],
                    "subject": "Welcome to Lettr",
                    "html": "<h1>Hello</h1><p>Welcome to our service!</p>",
                    "text": "Hello\n\nWelcome to our service!",
                    "options": {
                      "click_tracking": true,
                      "open_tracking": true
                    }
                  }
                },
                "html-only": {
                  "summary": "HTML only",
                  "description": "Send HTML content only. Some email clients may not render properly without a text fallback.",
                  "value": {
                    "from": "sender@example.com",
                    "to": [
                      "recipient@example.com"
                    ],
                    "subject": "Welcome to Lettr",
                    "html": "<h1>Hello</h1><p>Welcome to our service!</p>"
                  }
                },
                "text-only": {
                  "summary": "Plain text only",
                  "description": "Send plain text content only. Ideal for simple notifications.",
                  "value": {
                    "from": "sender@example.com",
                    "to": [
                      "recipient@example.com"
                    ],
                    "subject": "Order Confirmation",
                    "text": "Your order #12345 has been confirmed.\n\nThank you for your purchase!"
                  }
                },
                "with-attachments": {
                  "summary": "Email with attachments",
                  "description": "Send an email with file attachments. Attachments must be base64 encoded.",
                  "value": {
                    "from": "billing@example.com",
                    "from_name": "Billing Department",
                    "to": [
                      "customer@example.com"
                    ],
                    "subject": "Your Invoice",
                    "html": "<p>Please find your invoice attached.</p>",
                    "text": "Please find your invoice attached.",
                    "attachments": [
                      {
                        "name": "invoice.pdf",
                        "type": "application/pdf",
                        "data": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlL1BhZ2U="
                      }
                    ]
                  }
                },
                "with-personalization": {
                  "summary": "Personalized email with substitution",
                  "description": "Use substitution_data to personalize email content with dynamic variables.",
                  "value": {
                    "from": "hello@example.com",
                    "from_name": "Acme Inc",
                    "to": [
                      "john@example.com"
                    ],
                    "subject": "Welcome, {{first_name}}!",
                    "html": "<h1>Hello {{first_name}}</h1><p>Welcome to {{company}}!</p>",
                    "text": "Hello {{first_name}},\n\nWelcome to {{company}}!",
                    "substitution_data": {
                      "first_name": "John",
                      "company": "Acme Inc"
                    },
                    "metadata": {
                      "user_id": "12345",
                      "campaign": "onboarding"
                    }
                  }
                },
                "with-template": {
                  "summary": "Email using a template",
                  "description": "Send an email using a pre-defined template. The template's HTML content and subject will be used. You can optionally override the subject.",
                  "value": {
                    "from": "hello@example.com",
                    "to": [
                      "john@example.com"
                    ],
                    "template_slug": "welcome-email",
                    "substitution_data": {
                      "first_name": "John"
                    }
                  }
                },
                "with-template-and-project": {
                  "summary": "Email using a template from a specific project",
                  "description": "Send an email using a template from a specific project with a specific version. Subject is taken from the template unless explicitly provided.",
                  "value": {
                    "from": "hello@example.com",
                    "to": [
                      "john@example.com"
                    ],
                    "project_id": 123,
                    "template_slug": "welcome-email",
                    "template_version": 2,
                    "substitution_data": {
                      "first_name": "John"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email queued for delivery. Free tier teams receive quota headers indicating their usage and limits.",
            "headers": {
              "Idempotency-Replayed": {
                "description": "Present with value true when SparkPost returns an existing transmission. Quota headers describe current usage before this attempt.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "X-Monthly-Limit": {
                "description": "Total monthly email limit for this team. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 3000
                }
              },
              "X-Monthly-Remaining": {
                "description": "Remaining emails allowed this month. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 2500
                }
              },
              "X-Monthly-Reset": {
                "description": "Unix timestamp when the monthly quota resets (start of next month). Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 1740787200
                }
              },
              "X-Daily-Limit": {
                "description": "Total daily email limit for this team. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 100
                }
              },
              "X-Daily-Remaining": {
                "description": "Remaining emails allowed today. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 75
                }
              },
              "X-Daily-Reset": {
                "description": "Unix timestamp when the daily quota resets (tomorrow midnight UTC). Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 1739600000
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendEmailSuccessResponse"
                },
                "example": {
                  "message": "Email queued for delivery.",
                  "data": {
                    "request_id": "12345678901234567890",
                    "accepted": 1,
                    "rejected": 0
                  }
                }
              }
            }
          },
          "400": {
            "description": "Failed to send email (domain errors)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_domain": {
                    "summary": "Invalid sender domain",
                    "value": {
                      "message": "The sender domain could not be determined from the email address.",
                      "error_code": "invalid_domain"
                    }
                  },
                  "unconfigured_domain": {
                    "summary": "Unconfigured sender domain",
                    "value": {
                      "message": "The sender domain is not configured or approved for sending.",
                      "error_code": "unconfigured_domain"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Template or project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "template_not_found": {
                    "summary": "Template not found",
                    "value": {
                      "message": "Template with slug 'welcome-email' was not found.",
                      "error_code": "template_not_found"
                    }
                  },
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "template_not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "template_not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "SparkPost idempotency conflict: the key was used with a different transmission payload, or the original transmission is still processing.",
            "headers": {
              "Retry-After": {
                "description": "Present for idempotency_in_progress. Retry with the same key after this many seconds.",
                "schema": {
                  "type": "integer",
                  "example": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "conflict": {
                    "value": {
                      "message": "This Idempotency-Key was already used with a different request payload.",
                      "error_code": "idempotency_key_conflict"
                    }
                  },
                  "in_progress": {
                    "value": {
                      "message": "A request with this Idempotency-Key is still processing. Retry with the same key.",
                      "error_code": "idempotency_in_progress"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "from": [
                      "The sender email address is required."
                    ],
                    "to": [
                      "At least one recipient email address is required."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "description": "Sending quota exceeded. The response includes quota headers to help determine current usage and when the limit resets.",
            "headers": {
              "X-Monthly-Limit": {
                "description": "Total monthly email limit for this team.",
                "schema": {
                  "type": "integer",
                  "example": 3000
                }
              },
              "X-Monthly-Remaining": {
                "description": "Remaining emails allowed this month (0 when limit is hit).",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "X-Monthly-Reset": {
                "description": "Unix timestamp when the monthly quota resets (start of next month).",
                "schema": {
                  "type": "integer",
                  "example": 1740787200
                }
              },
              "X-Daily-Limit": {
                "description": "Total daily email limit for this team.",
                "schema": {
                  "type": "integer",
                  "example": 100
                }
              },
              "X-Daily-Remaining": {
                "description": "Remaining emails allowed today (0 when limit is hit).",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "X-Daily-Reset": {
                "description": "Unix timestamp when the daily quota resets (tomorrow midnight UTC).",
                "schema": {
                  "type": "integer",
                  "example": 1739600000
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "monthly_quota_exceeded": {
                    "summary": "Monthly sending quota exceeded",
                    "value": {
                      "message": "Sending quota exceeded. Upgrade your plan to continue sending.",
                      "error_code": "quota_exceeded"
                    }
                  },
                  "daily_quota_exceeded": {
                    "summary": "Daily sending quota exceeded",
                    "value": {
                      "message": "Daily sending quota exceeded. Please try again tomorrow.",
                      "error_code": "daily_quota_exceeded"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to send email. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          },
          "502": {
            "description": "Email transmission failed (upstream provider error). Retry with the same Idempotency-Key so SparkPost can resolve an uncertain outcome without creating a duplicate transmission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Unconfigured Sending Domain <sender.example.com>",
                  "error_code": "transmission_failed"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listEmails",
        "summary": "List Sent Emails",
        "description": "Retrieve a paginated list of sent emails. Supports filtering by recipient email and date range. Uses cursor-based pagination.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "description": "Number of results per page (1-100). Defaults to 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Cursor for pagination. Use the `next_cursor` value from the previous response. Any other value fails with a 422.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "recipients",
            "in": "query",
            "description": "Filter by recipient email address.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "email"
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Only emails sent at or after this time (ISO 8601). Defaults to 10 days ago. Sent emails are kept for about 10 days, so an earlier date is pulled forward; `from` in the response shows the window actually covered.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Only emails sent before this time (ISO 8601, exclusive). Must be after `from`, otherwise the request fails with a 422.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Emails retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListEmailsResponse"
                },
                "example": {
                  "message": "Emails retrieved successfully.",
                  "data": {
                    "events": {
                      "data": [
                        {
                          "event_id": "abc123",
                          "type": "injection",
                          "timestamp": "2024-01-15T10:30:00Z",
                          "request_id": "12345678901234567890",
                          "message_id": "msg-abc123",
                          "subject": "Welcome Email",
                          "friendly_from": "sender@example.com",
                          "sending_domain": "example.com",
                          "rcpt_to": "recipient@example.com",
                          "click_tracking": true,
                          "open_tracking": true,
                          "transactional": true
                        }
                      ],
                      "total_count": 1,
                      "from": "2024-01-05T00:00:00Z",
                      "to": "2024-01-15T23:59:59Z",
                      "pagination": {
                        "next_cursor": null,
                        "per_page": 25
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Retrieval error (e.g., sandbox key without associated user)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Sandbox API key does not have an associated user with an email address.",
                  "error_code": "retrieval_error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "per_page": [
                      "The per_page parameter must be an integer."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve emails. Please try again later.",
                  "error_code": "retrieval_error"
                }
              }
            }
          }
        }
      }
    },
    "/emails/events": {
      "get": {
        "operationId": "listEmailEvents",
        "summary": "List Email Events",
        "description": "Retrieve email events (deliveries, bounces, opens, clicks, etc.) for your account. Events are returned in reverse chronological order. If no `from` date is provided, defaults to the last 10 days.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "events",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of event types to filter by. Valid types: `injection`, `delivery`, `bounce`, `delay`, `out_of_band`, `spam_complaint`, `policy_rejection`, `click`, `open`, `initial_open`, `amp_click`, `amp_open`, `amp_initial_open`, `generation_failure`, `generation_rejection`, `list_unsubscribe`, `link_unsubscribe`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "injection",
                  "delivery",
                  "bounce",
                  "delay",
                  "out_of_band",
                  "spam_complaint",
                  "policy_rejection",
                  "click",
                  "open",
                  "initial_open",
                  "amp_click",
                  "amp_open",
                  "amp_initial_open",
                  "generation_failure",
                  "generation_rejection",
                  "list_unsubscribe",
                  "link_unsubscribe"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "examples": {
              "single": {
                "summary": "Single event type",
                "value": [
                  "delivery"
                ]
              },
              "multiple": {
                "summary": "Multiple event types",
                "value": [
                  "delivery",
                  "bounce",
                  "open"
                ]
              }
            }
          },
          {
            "name": "recipients",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of recipient email addresses to filter by.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "email"
              }
            },
            "style": "form",
            "explode": false,
            "examples": {
              "single": {
                "summary": "Single recipient",
                "value": [
                  "recipient@example.com"
                ]
              },
              "multiple": {
                "summary": "Multiple recipients",
                "value": [
                  "recipient@example.com",
                  "other@example.com"
                ]
              }
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start of the event search range (ISO 8601, inclusive). Defaults to 10 days ago. Events are kept for about 10 days, so an earlier date is pulled forward; `from` in the response shows the window actually covered.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2024-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End of the event search range (ISO 8601, exclusive). Defaults to now. Must be after `from`, otherwise the request fails with a 422.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2024-01-31"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "description": "Number of events per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "example": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor: the `next_cursor` value from the previous response. Any other value fails with a 422.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "transmissions",
            "in": "query",
            "required": false,
            "description": "Filter events by transmission ID (request_id).",
            "schema": {
              "type": "string",
              "example": "12345678901234567890"
            }
          },
          {
            "name": "bounce_classes",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of bounce classification codes to filter by.",
            "schema": {
              "type": "string",
              "example": "10,30"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email events retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListEmailEventsResponse"
                },
                "example": {
                  "message": "Email events retrieved successfully.",
                  "data": {
                    "events": {
                      "data": [
                        {
                          "event_id": "event-delivery-1",
                          "type": "delivery",
                          "timestamp": "2024-01-15T10:31:00.000Z",
                          "request_id": "12345678901234567890",
                          "rcpt_to": "recipient@example.com",
                          "raw_rcpt_to": "recipient@example.com",
                          "recipient_domain": "example.com",
                          "mailbox_provider": "Gmail",
                          "mailbox_provider_region": "Global",
                          "subject": "Welcome to Lettr",
                          "friendly_from": "sender@example.com",
                          "queue_time": 500
                        },
                        {
                          "event_id": "event-bounce-1",
                          "type": "bounce",
                          "timestamp": "2024-01-15T10:32:00.000Z",
                          "request_id": "12345678901234567891",
                          "rcpt_to": "bounced@example.com",
                          "raw_rcpt_to": "bounced@example.com",
                          "recipient_domain": "example.com",
                          "mailbox_provider": "Gmail",
                          "mailbox_provider_region": "Global",
                          "subject": "Welcome to Lettr",
                          "bounce_class": 10,
                          "error_code": "550",
                          "reason": "User unknown"
                        }
                      ],
                      "total_count": 2,
                      "from": "2024-01-05T00:00:00+00:00",
                      "to": "2024-01-15T10:35:00+00:00",
                      "pagination": {
                        "next_cursor": null,
                        "per_page": 25
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "per_page": [
                      "The per_page parameter must be an integer."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/emails/{requestId}": {
      "get": {
        "operationId": "getEmailDetail",
        "summary": "Get Email Detail",
        "description": "Retrieve all events for a specific sent email by its request ID. Returns delivery, bounce, open, click, and other events in reverse chronological order. If no `from` date is provided, defaults to the last 10 days.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "requestId",
            "in": "path",
            "required": true,
            "description": "The request ID (transmission ID) of the sent email.",
            "schema": {
              "type": "string",
              "example": "7610639000055488914"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the event search range. Defaults to 10 days ago if not provided.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2024-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the event search range. Defaults to now if not provided.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2024-01-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Email detail retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetEmailDetailResponse"
                },
                "example": {
                  "message": "Email retrieved successfully.",
                  "data": {
                    "transmission_id": "7610639000055488914",
                    "state": "delivered",
                    "scheduled_at": null,
                    "from": "sender@example.com",
                    "from_name": null,
                    "subject": "Welcome to Lettr",
                    "recipients": [
                      "recipient@example.com"
                    ],
                    "num_recipients": 1,
                    "events": [
                      {
                        "event_id": "event-open-1",
                        "type": "open",
                        "timestamp": "2024-01-15T10:32:00.000Z",
                        "request_id": "7610639000055488914",
                        "rcpt_to": "recipient@example.com",
                        "raw_rcpt_to": "recipient@example.com",
                        "recipient_domain": "example.com",
                        "mailbox_provider": "Gmail",
                        "mailbox_provider_region": "Global",
                        "subject": "Welcome to Lettr",
                        "friendly_from": "sender@example.com"
                      },
                      {
                        "event_id": "event-delivery-1",
                        "type": "delivery",
                        "timestamp": "2024-01-15T10:31:00.000Z",
                        "request_id": "7610639000055488914",
                        "rcpt_to": "recipient@example.com",
                        "raw_rcpt_to": "recipient@example.com",
                        "recipient_domain": "example.com",
                        "mailbox_provider": "Gmail",
                        "mailbox_provider_region": "Global",
                        "subject": "Welcome to Lettr",
                        "friendly_from": "sender@example.com",
                        "queue_time": 500
                      },
                      {
                        "event_id": "event-injection-1",
                        "type": "injection",
                        "timestamp": "2024-01-15T10:30:00.000Z",
                        "request_id": "7610639000055488914",
                        "rcpt_to": "recipient@example.com",
                        "raw_rcpt_to": "recipient@example.com",
                        "recipient_domain": "example.com",
                        "mailbox_provider": "Gmail",
                        "mailbox_provider_region": "Global",
                        "subject": "Welcome to Lettr",
                        "friendly_from": "sender@example.com"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Email not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Email not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "from": [
                      "The from parameter must be a valid date."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/emails/scheduled": {
      "post": {
        "operationId": "scheduleEmail",
        "summary": "Schedule Email",
        "description": "Schedule a transactional email for future delivery. Accepts the same payload as `POST /emails` with an additional required `scheduled_at` field. The email must be scheduled at least 5 minutes in the future and within 30 days.\n\n**Breaking change.** Scheduled emails are no longer parked inside SparkPost with `options.start_time` — SparkPost retired its per-transmission GET and DELETE endpoints, so Lettr now holds the email in its own store and injects it into SparkPost only when it is due. `request_id` is therefore Lettr's own id, prefixed `sch_` (for example `sch_01JQZ3N2K8XW9V6M4TBRC7YHDE`), and it is the id you pass to `GET` and `DELETE /emails/scheduled/{transmissionId}`. SparkPost's transmission id is now the separate `transmission_id` field, which is `null` until the email is actually injected; that is the value that appears as `transmission_id` on your webhook events, so use it to correlate webhooks. `state` values are now Lettr's own (`scheduled`, `sending`, `sent`, `cancelled`, `failed`) rather than SparkPost's pass-through states.\n\n`Idempotency-Key` is **not** honoured here and is ignored if sent — it applies to `POST /emails` only. A scheduled email is created once and then listed, read or cancelled by the `request_id` returned here, so use that to check whether a retry is needed.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleEmailRequest"
              },
              "example": {
                "from": "sender@example.com",
                "from_name": "Sender Name",
                "to": [
                  "recipient@example.com"
                ],
                "subject": "Scheduled Newsletter",
                "html": "<h1>Hello</h1><p>This email was scheduled!</p>",
                "scheduled_at": "2024-01-16T10:00:00Z",
                "options": {
                  "click_tracking": true,
                  "open_tracking": true
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Email scheduled for delivery. Free tier teams receive quota headers indicating their usage and limits.",
            "headers": {
              "X-Monthly-Limit": {
                "description": "Total monthly email limit for this team. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 3000
                }
              },
              "X-Monthly-Remaining": {
                "description": "Remaining emails allowed this month. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 2500
                }
              },
              "X-Monthly-Reset": {
                "description": "Unix timestamp when the monthly quota resets.",
                "schema": {
                  "type": "integer",
                  "example": 1740787200
                }
              },
              "X-Daily-Limit": {
                "description": "Total daily email limit for this team. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 100
                }
              },
              "X-Daily-Remaining": {
                "description": "Remaining emails allowed today. Only present for free tier teams.",
                "schema": {
                  "type": "integer",
                  "example": 75
                }
              },
              "X-Daily-Reset": {
                "description": "Unix timestamp when the daily quota resets.",
                "schema": {
                  "type": "integer",
                  "example": 1739600000
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Email scheduled for delivery."
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduledEmailResponse"
                    }
                  }
                },
                "example": {
                  "message": "Email scheduled for delivery.",
                  "data": {
                    "request_id": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE",
                    "transmission_id": null,
                    "state": "scheduled",
                    "scheduled_at": "2024-01-16T10:00:00Z",
                    "from": "sender@example.com",
                    "from_name": "Sender Name",
                    "subject": "Scheduled Newsletter",
                    "recipients": [
                      "recipient@example.com"
                    ],
                    "num_recipients": 1,
                    "accepted": 1,
                    "rejected": 0,
                    "tag": null,
                    "failure_reason": null,
                    "events": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Failed to schedule email (domain errors)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_domain": {
                    "summary": "Invalid sender domain",
                    "value": {
                      "message": "The sender domain could not be determined from the email address.",
                      "error_code": "invalid_domain"
                    }
                  },
                  "unconfigured_domain": {
                    "summary": "Unconfigured sender domain",
                    "value": {
                      "message": "The sender domain is not configured or approved for sending.",
                      "error_code": "unconfigured_domain"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "scheduled_at": [
                      "The scheduled delivery time is required."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "description": "Sending quota exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Sending quota exceeded. Upgrade your plan to continue sending.",
                  "error_code": "quota_exceeded"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "Email transmission failed (upstream provider error)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Unconfigured Sending Domain <sender.example.com>",
                  "error_code": "transmission_failed"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listScheduledEmails",
        "summary": "List Scheduled Emails",
        "description": "List the scheduled emails of your team, newest first. Requires the `emails:read` scope.\n\nThis endpoint is new: listing was previously impossible because SparkPost's transmission list endpoint returns 404. Lettr now holds scheduled emails in its own store, so they can be listed, read back and cancelled at any point before they are injected.\n\nA sandbox key only sees the emails it scheduled itself.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "scheduled",
                "sending",
                "sent",
                "cancelled",
                "failed"
              ]
            },
            "description": "Filter by scheduled email state"
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Number of results per page (1-100). Defaults to 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number. Defaults to 1.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Scheduled emails retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListScheduledEmailsResponse"
                },
                "example": {
                  "message": "Scheduled emails retrieved successfully.",
                  "data": {
                    "scheduled_emails": [
                      {
                        "request_id": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE",
                        "transmission_id": null,
                        "state": "scheduled",
                        "scheduled_at": "2024-01-16T10:00:00Z",
                        "from": "sender@example.com",
                        "from_name": "Sender Name",
                        "subject": "Scheduled Newsletter",
                        "recipients": [
                          "recipient@example.com"
                        ],
                        "num_recipients": 1,
                        "accepted": 1,
                        "rejected": 0,
                        "tag": null,
                        "failure_reason": null,
                        "events": []
                      }
                    ],
                    "pagination": {
                      "total": 1,
                      "per_page": 25,
                      "current_page": 1,
                      "last_page": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "per_page": [
                      "The per_page parameter must not exceed 100."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to list scheduled emails. Please try again later.",
                  "error_code": "retrieval_error"
                }
              }
            }
          }
        }
      }
    },
    "/emails/scheduled/{transmissionId}": {
      "get": {
        "operationId": "showScheduledEmail",
        "summary": "Get Scheduled Email",
        "description": "Retrieve a scheduled email by the `request_id` returned when it was scheduled (`sch_...`).\n\n**Breaking change.** Scheduled emails are no longer parked inside SparkPost with `options.start_time`, because SparkPost retired its per-transmission GET endpoint. Lettr now answers from its own store, so the response is correct the instant the email is scheduled and a cancelled email can be told apart from one that never existed. `request_id` is Lettr's own `sch_...` id, SparkPost's id is the separate `transmission_id` field (`null` until the email is injected, and the value that appears as `transmission_id` on your webhook events), and `state` is one of `scheduled`, `sending`, `sent`, `cancelled` or `failed`.\n\nFor emails scheduled **before** this change there is no Lettr record, only the SparkPost transmission id you stored. Those ids are still accepted and fall back to a delivery-events lookup, which returns the **old** response shape (`ShowScheduledTransmissionResponse`, with SparkPost's pass-through `state` values and no `request_id`).\n\nA sandbox key only sees the emails it scheduled itself.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "transmissionId",
            "in": "path",
            "required": true,
            "description": "The `request_id` returned when the email was scheduled (`sch_...`). A bare SparkPost transmission id is also accepted, for emails scheduled before Lettr owned the schedule; those return the legacy response shape.",
            "schema": {
              "type": "string",
              "example": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Scheduled transmission retrieved successfully. Returns the scheduled email when Lettr knows the id, or the legacy events-derived shape for a SparkPost transmission id from before this change.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "description": "Returned for a `sch_...` id that Lettr knows about.",
                      "required": [
                        "message",
                        "data"
                      ],
                      "properties": {
                        "message": {
                          "type": "string",
                          "example": "Scheduled transmission retrieved successfully."
                        },
                        "data": {
                          "$ref": "#/components/schemas/ScheduledEmailResponse"
                        }
                      }
                    },
                    {
                      "$ref": "#/components/schemas/ShowScheduledTransmissionResponse"
                    }
                  ]
                },
                "examples": {
                  "scheduled": {
                    "summary": "Waiting for its delivery time",
                    "value": {
                      "message": "Scheduled transmission retrieved successfully.",
                      "data": {
                        "request_id": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE",
                        "transmission_id": null,
                        "state": "scheduled",
                        "scheduled_at": "2024-01-16T10:00:00Z",
                        "from": "sender@example.com",
                        "from_name": "Sender Name",
                        "subject": "Scheduled Newsletter",
                        "recipients": [
                          "recipient@example.com"
                        ],
                        "num_recipients": 1,
                        "accepted": 1,
                        "rejected": 0,
                        "tag": null,
                        "failure_reason": null,
                        "events": []
                      }
                    }
                  },
                  "sent": {
                    "summary": "Injected into SparkPost (delivery events populated)",
                    "value": {
                      "message": "Scheduled transmission retrieved successfully.",
                      "data": {
                        "request_id": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE",
                        "transmission_id": "12345678901234567890",
                        "state": "sent",
                        "scheduled_at": "2024-01-16T10:00:00Z",
                        "from": "sender@example.com",
                        "from_name": "Sender Name",
                        "subject": "Scheduled Newsletter",
                        "recipients": [
                          "recipient@example.com"
                        ],
                        "num_recipients": 1,
                        "accepted": 1,
                        "rejected": 0,
                        "tag": null,
                        "failure_reason": null,
                        "events": [
                          {
                            "event_id": "evt-delivery-1",
                            "type": "delivery",
                            "timestamp": "2024-01-16T10:00:02.000Z",
                            "request_id": "12345678901234567890",
                            "rcpt_to": "recipient@example.com",
                            "raw_rcpt_to": "recipient@example.com",
                            "recipient_domain": "example.com",
                            "mailbox_provider": "Gmail",
                            "mailbox_provider_region": "Global",
                            "subject": "Scheduled Newsletter",
                            "friendly_from": "sender@example.com",
                            "queue_time": 500
                          }
                        ]
                      }
                    }
                  },
                  "cancelled": {
                    "summary": "Cancelled before injection",
                    "value": {
                      "message": "Scheduled transmission retrieved successfully.",
                      "data": {
                        "request_id": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE",
                        "transmission_id": null,
                        "state": "cancelled",
                        "scheduled_at": "2024-01-16T10:00:00Z",
                        "from": "sender@example.com",
                        "from_name": "Sender Name",
                        "subject": "Scheduled Newsletter",
                        "recipients": [
                          "recipient@example.com"
                        ],
                        "num_recipients": 1,
                        "accepted": 1,
                        "rejected": 0,
                        "tag": null,
                        "failure_reason": null,
                        "events": []
                      }
                    }
                  },
                  "legacy": {
                    "summary": "Legacy SparkPost transmission id (old response shape, from delivery events)",
                    "value": {
                      "message": "Scheduled transmission retrieved successfully.",
                      "data": {
                        "transmission_id": "12345678901234567890",
                        "state": "delivered",
                        "scheduled_at": null,
                        "from": "sender@example.com",
                        "from_name": null,
                        "subject": "Scheduled Newsletter",
                        "recipients": [
                          "recipient@example.com"
                        ],
                        "num_recipients": 1,
                        "events": [
                          {
                            "event_id": "evt-delivery-1",
                            "type": "delivery",
                            "timestamp": "2024-01-16T10:00:02.000Z",
                            "request_id": "12345678901234567890",
                            "rcpt_to": "recipient@example.com",
                            "raw_rcpt_to": "recipient@example.com",
                            "recipient_domain": "example.com",
                            "mailbox_provider": "Gmail",
                            "mailbox_provider_region": "Global",
                            "subject": "Scheduled Newsletter",
                            "friendly_from": "sender@example.com",
                            "queue_time": 500
                          },
                          {
                            "event_id": "evt-injection-1",
                            "type": "injection",
                            "timestamp": "2024-01-16T10:00:00.000Z",
                            "request_id": "12345678901234567890",
                            "rcpt_to": "recipient@example.com",
                            "raw_rcpt_to": "recipient@example.com",
                            "recipient_domain": "example.com",
                            "mailbox_provider": "Gmail",
                            "mailbox_provider_region": "Global",
                            "subject": "Scheduled Newsletter",
                            "friendly_from": "sender@example.com"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Scheduled transmission not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Scheduled transmission not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "cancelScheduledEmail",
        "summary": "Cancel Scheduled Email",
        "description": "Cancel a scheduled email before it is injected into SparkPost, and return the cancelled email.\n\n**Breaking change.** Cancellation used to be delegated to SparkPost's per-transmission DELETE endpoint, which SparkPost retired — the call failed every time. Lettr now owns the schedule, so a cancellation either genuinely stops the send or says truthfully that it could not.\n\nOnly an email in state `scheduled` can be cancelled. Once the dispatcher has claimed it (`sending`), or it has already been injected (`sent`) or cancelled (`cancelled`), the request fails with `409 schedule_cancellation_failed` — SparkPost offers no per-message recall after injection.\n\nA sandbox key can only cancel the emails it scheduled itself.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "transmissionId",
            "in": "path",
            "required": true,
            "description": "The `request_id` returned when the email was scheduled (`sch_...`). A bare SparkPost transmission id is also accepted, for emails scheduled before Lettr owned the schedule.",
            "schema": {
              "type": "string",
              "example": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Scheduled transmission cancelled successfully. The email was never handed to SparkPost.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Scheduled transmission cancelled successfully."
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduledEmailResponse"
                    }
                  }
                },
                "example": {
                  "message": "Scheduled transmission cancelled successfully.",
                  "data": {
                    "request_id": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE",
                    "transmission_id": null,
                    "state": "cancelled",
                    "scheduled_at": "2024-01-16T10:00:00Z",
                    "from": "sender@example.com",
                    "from_name": "Sender Name",
                    "subject": "Scheduled Newsletter",
                    "recipients": [
                      "recipient@example.com"
                    ],
                    "num_recipients": 1,
                    "accepted": 1,
                    "rejected": 0,
                    "tag": null,
                    "failure_reason": null,
                    "events": []
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Scheduled transmission not found. The id is unknown, or it belongs to another team or another sandbox key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Scheduled transmission not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "409": {
            "description": "The email can no longer be cancelled: it has already been sent, was already cancelled, or is being injected right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "This email has already been sent and can no longer be cancelled.",
                  "error_code": "schedule_cancellation_failed"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/domains": {
      "get": {
        "operationId": "listDomains",
        "summary": "List Domains",
        "description": "Retrieve all sending domains registered with your account. Returns domains with their current status, verification state, and timestamps.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of domains retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListDomainsResponse"
                },
                "example": {
                  "message": "Domains retrieved successfully.",
                  "data": {
                    "domains": [
                      {
                        "domain": "example.com",
                        "status": "approved",
                        "status_label": "Approved",
                        "can_send": true,
                        "cname_status": "valid",
                        "dkim_status": "valid",
                        "created_at": "2024-01-15T10:30:00+00:00",
                        "updated_at": "2024-01-16T14:45:00+00:00"
                      },
                      {
                        "domain": "pending.example.com",
                        "status": "pending",
                        "status_label": "Pending Review",
                        "can_send": false,
                        "cname_status": null,
                        "dkim_status": null,
                        "created_at": "2024-01-17T09:00:00+00:00",
                        "updated_at": "2024-01-17T09:00:00+00:00"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "500": {
            "description": "Server error - Failed to retrieve domains",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve domains. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createDomain",
        "summary": "Create Domain",
        "description": "Register a new sending domain with your account. The domain will be created with SparkPost and stored as approved by default, unless global domain reputation marks it for review or blacklist. Adding a domain your team already has returns `409` and leaves its DNS records and verification status unchanged.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreDomainRequest"
              },
              "example": {
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreDomainResponse"
                },
                "example": {
                  "message": "Domain created successfully.",
                  "data": {
                    "domain": "example.com",
                    "status": "approved",
                    "status_label": "Approved",
                    "dkim": {
                      "public": "MIGfMA0GCSqGSIb3DQEBA...",
                      "selector": "scph0123",
                      "headers": "from:to:subject:date",
                      "signing_domain": "example.com"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "409": {
            "description": "Conflict - Domain already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "This domain is already registered.",
                  "error_code": "resource_already_exists"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "domain": [
                      "The domain must be a valid domain name (e.g., example.com)."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error - Failed to create domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "We could not register your domain. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/domains/{domain}": {
      "get": {
        "operationId": "showDomain",
        "summary": "Get Domain",
        "description": "Retrieve details of a single sending domain including DNS records and tracking domain configuration.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "The domain name to retrieve",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowDomainResponse"
                },
                "example": {
                  "message": "Domain retrieved successfully.",
                  "data": {
                    "domain": "example.com",
                    "status": "approved",
                    "status_label": "Approved",
                    "can_send": true,
                    "cname_status": "valid",
                    "dkim_status": "valid",
                    "dmarc_status": "valid",
                    "spf_status": "valid",
                    "is_primary_domain": false,
                    "tracking_domain": "tracking.example.com",
                    "dns": {
                      "dkim": {
                        "selector": "scph0123",
                        "public": "MIGfMA0GCSqGSIb3DQEBA...",
                        "headers": "from:to:subject:date"
                      }
                    },
                    "dns_provider": null,
                    "created_at": "2024-01-15T10:30:00+00:00",
                    "updated_at": "2024-01-16T14:45:00+00:00"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Domain not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "description": "Server error - Failed to retrieve domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve domain. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteDomain",
        "summary": "Delete Domain",
        "description": "Delete a sending domain. This removes the domain from both SparkPost and the Lettr system. The domain will no longer be available for sending emails.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "The domain name to delete",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Domain deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Domain not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error - Invalid domain format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "domain": [
                      "The domain must be a valid domain name (e.g., example.com)."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error - Failed to delete domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to delete domain. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List Webhooks",
        "description": "Retrieve all webhooks configured for your account. Returns webhooks with their current status, event types, and delivery information.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhooks retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListWebhooksResponse"
                },
                "example": {
                  "message": "Webhooks retrieved successfully.",
                  "data": {
                    "webhooks": [
                      {
                        "id": "webhook-abc123",
                        "name": "Order Notifications",
                        "url": "https://example.com/webhook",
                        "enabled": true,
                        "event_types": [
                          "message.delivery",
                          "message.bounce"
                        ],
                        "auth_type": "basic",
                        "has_auth_credentials": true,
                        "last_successful_at": "2024-01-15T10:30:00+00:00",
                        "last_failure_at": null,
                        "last_status": "success"
                      },
                      {
                        "id": "webhook-def456",
                        "name": "Support Notifications",
                        "url": "https://example.com/support-webhook",
                        "enabled": false,
                        "event_types": null,
                        "auth_type": "none",
                        "has_auth_credentials": false,
                        "last_successful_at": null,
                        "last_failure_at": "2024-01-14T08:00:00+00:00",
                        "last_status": "failure"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "500": {
            "description": "Server error - Failed to retrieve webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve webhooks. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "storeWebhook",
        "summary": "Create Webhook",
        "description": "Create a new webhook to receive event notifications at the specified URL.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreWebhookRequest"
              },
              "example": {
                "name": "Order Notifications",
                "url": "https://example.com/webhook",
                "auth_type": "basic",
                "auth_username": "user",
                "auth_password": "secret",
                "events_mode": "selected",
                "events": [
                  "message.delivery",
                  "message.bounce"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreWebhookResponse"
                },
                "example": {
                  "message": "Webhook created successfully.",
                  "data": {
                    "id": "webhook-abc123",
                    "name": "Order Notifications",
                    "url": "https://example.com/webhook",
                    "enabled": true,
                    "event_types": [
                      "message.delivery",
                      "message.bounce"
                    ],
                    "auth_type": "basic",
                    "has_auth_credentials": true,
                    "last_successful_at": null,
                    "last_failure_at": null,
                    "last_status": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - SparkPost rejected the webhook configuration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Invalid webhook configuration.",
                  "error_code": "send_error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "409": {
            "description": "Conflict - A webhook with this target URL already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "A webhook with this target URL already exists.",
                  "error_code": "resource_already_exists"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "description": "Server error - Failed to create webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to create webhook. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{webhookId}": {
      "get": {
        "operationId": "showWebhook",
        "summary": "Get Webhook",
        "description": "Retrieve details of a single webhook including its status, event types, and delivery information.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "The webhook ID to retrieve",
            "schema": {
              "type": "string",
              "example": "webhook-abc123"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowWebhookResponse"
                },
                "example": {
                  "message": "Webhook retrieved successfully.",
                  "data": {
                    "id": "webhook-abc123",
                    "name": "Order Notifications",
                    "url": "https://example.com/webhook",
                    "enabled": true,
                    "event_types": [
                      "message.delivery",
                      "message.bounce"
                    ],
                    "auth_type": "basic",
                    "has_auth_credentials": true,
                    "last_successful_at": "2024-01-15T10:30:00+00:00",
                    "last_failure_at": null,
                    "last_status": "success"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Webhook not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "description": "Server error - Failed to retrieve webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve webhook. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateWebhook",
        "summary": "Update Webhook",
        "description": "Update an existing webhook. Only the fields provided will be updated (partial update). You can change the name, target URL, authentication, events, or active status.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "The webhook ID to update",
            "schema": {
              "type": "string",
              "example": "webhook-abc123"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              },
              "example": {
                "name": "Updated Webhook Name",
                "active": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowWebhookResponse"
                },
                "example": {
                  "message": "Webhook updated successfully.",
                  "data": {
                    "id": "webhook-abc123",
                    "name": "Updated Webhook Name",
                    "url": "https://example.com/webhook",
                    "enabled": false,
                    "event_types": [
                      "message.delivery",
                      "message.bounce"
                    ],
                    "auth_type": "basic",
                    "has_auth_credentials": true,
                    "last_successful_at": "2024-01-15T10:30:00+00:00",
                    "last_failure_at": null,
                    "last_status": "success"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - Invalid webhook configuration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Invalid webhook configuration",
                  "error_code": "send_error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Webhook not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "description": "Server error - Failed to update webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to update webhook. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete Webhook",
        "description": "Delete a webhook. This removes the webhook from SparkPost and it will no longer receive event notifications.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "description": "The webhook ID to delete",
            "schema": {
              "type": "string",
              "example": "webhook-abc123"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Webhook deleted successfully."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Webhook not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error - Invalid webhook ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "webhookId": [
                      "The webhook ID is required."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error - Failed to delete webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to delete webhook. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/templates": {
      "get": {
        "operationId": "listTemplates",
        "summary": "List Templates",
        "description": "Retrieve a paginated list of email templates for a project. If `project_id` is not provided, templates from the team's default project will be returned.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "project_id",
            "in": "query",
            "description": "Project ID to retrieve templates from. If not provided, uses the team's default project.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "folder_id",
            "in": "query",
            "description": "Return only the templates in one folder of the resolved project. Discover folder ids with `GET /folders`. A folder that does not exist in that project answers 404 rather than an empty list, so a typo cannot be mistaken for \"nothing is there yet\".",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "example": 10
            }
          },
          {
            "name": "purpose",
            "in": "query",
            "description": "Return only the templates of one module. If not provided, templates of both modules are returned.",
            "schema": {
              "type": "string",
              "enum": [
                "transactional",
                "campaign"
              ],
              "example": "campaign"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Number of results per page (1-100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of templates retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListTemplatesResponse"
                },
                "example": {
                  "message": "Templates retrieved successfully.",
                  "data": {
                    "templates": [
                      {
                        "id": 1,
                        "name": "Welcome Email",
                        "slug": "welcome-email",
                        "project_id": 5,
                        "folder_id": 10,
                        "purpose": "transactional",
                        "preparation_status": "ready",
                        "created_at": "2025-01-15T10:00:00+00:00",
                        "updated_at": "2025-01-20T14:30:00+00:00"
                      }
                    ],
                    "pagination": {
                      "total": 42,
                      "per_page": 25,
                      "current_page": 1,
                      "last_page": 2
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Project not found or no default project configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  },
                  "folder_not_found": {
                    "summary": "Folder not in this project",
                    "value": {
                      "message": "Folder with ID '10' was not found in the specified project.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "project_id": [
                      "The project_id parameter must be an integer."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve templates. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createTemplate",
        "summary": "Create Template",
        "description": "Create a new email template with HTML or Topol editor JSON content. Automatically creates and publishes a template version with extracted merge tags.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTemplateRequest"
              },
              "examples": {
                "with_json": {
                  "summary": "Create with Topol JSON",
                  "value": {
                    "name": "Welcome Email",
                    "json": "{\"tagName\":\"mj-container\",\"children\":[{\"tagName\":\"mj-text\",\"content\":\"Hello {{FIRST_NAME}}!\"}]}"
                  }
                },
                "with_html": {
                  "summary": "Create with custom HTML",
                  "value": {
                    "name": "Newsletter",
                    "html": "<html><body><p>Hello {{NAME}}, your order {{ORDER_ID}} is ready!</p></body></html>"
                  }
                },
                "with_project_and_folder": {
                  "summary": "Create in specific project and folder",
                  "value": {
                    "name": "Invoice Email",
                    "project_id": 5,
                    "folder_id": 10,
                    "html": "<html><body><p>Invoice for {{CUSTOMER_NAME}}</p></body></html>"
                  }
                },
                "marketing_template": {
                  "summary": "Create a marketing template for campaigns",
                  "value": {
                    "name": "October Newsletter",
                    "purpose": "campaign",
                    "html": "<html><body><p>Hi {{FIRST_NAME}}, here is what shipped this month.</p></body></html>"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateTemplateResponse"
                },
                "example": {
                  "message": "Template created successfully.",
                  "data": {
                    "id": 123,
                    "name": "Welcome Email",
                    "slug": "welcome-email",
                    "project_id": 5,
                    "folder_id": 10,
                    "purpose": "transactional",
                    "preparation_status": "pending",
                    "active_version": 1,
                    "merge_tags": [
                      {
                        "key": "FIRST_NAME",
                        "required": true
                      }
                    ],
                    "created_at": "2026-01-28T12:00:00+00:00"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Project or folder not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  },
                  "folder_not_found": {
                    "summary": "Folder not found",
                    "value": {
                      "message": "Folder with ID '456' was not found in the specified project.",
                      "error_code": "not_found"
                    }
                  },
                  "no_folders": {
                    "summary": "No folders in project",
                    "value": {
                      "message": "Project with ID '123' has no folders. Please create a folder first.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "name_required": {
                    "summary": "Name is required",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "name": [
                          "The name field is required."
                        ]
                      }
                    }
                  },
                  "no_content": {
                    "summary": "No content provided",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "html": [
                          "Either html or json content is required."
                        ]
                      }
                    }
                  },
                  "both_content": {
                    "summary": "Both html and json provided",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "json": [
                          "The json and html fields are mutually exclusive. Provide only one."
                        ]
                      }
                    }
                  },
                  "invalid_json": {
                    "summary": "Invalid JSON syntax",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "json": [
                          "The provided JSON is not valid."
                        ]
                      }
                    }
                  },
                  "invalid_purpose": {
                    "summary": "Unknown purpose",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "purpose": [
                          "The purpose must be either transactional or campaign."
                        ]
                      }
                    }
                  },
                  "folder_purpose_mismatch": {
                    "summary": "Folder belongs to the other module",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "folder_id": [
                          "Folder 10 is a transactional folder and cannot hold a campaign template."
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to create template. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/templates/{slug}": {
      "get": {
        "operationId": "getTemplate",
        "summary": "Get Template",
        "description": "Retrieve a single email template by its slug. If `project_id` is not provided, the template will be looked up in the team's default project.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The template slug (URL-friendly identifier)",
            "schema": {
              "type": "string",
              "example": "welcome-email"
            }
          },
          {
            "name": "project_id",
            "in": "query",
            "description": "Project ID to retrieve the template from. If not provided, uses the team's default project.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowTemplateResponse"
                },
                "example": {
                  "message": "Template retrieved successfully.",
                  "data": {
                    "id": 1,
                    "name": "Welcome Email",
                    "slug": "welcome-email",
                    "project_id": 5,
                    "folder_id": 10,
                    "purpose": "transactional",
                    "preparation_status": "ready",
                    "active_version": 2,
                    "versions_count": 3,
                    "created_at": "2025-01-15T10:00:00+00:00",
                    "updated_at": "2025-01-20T14:30:00+00:00"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Template or project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "template_not_found": {
                    "summary": "Template not found",
                    "value": {
                      "message": "Template with slug 'welcome-email' was not found.",
                      "error_code": "not_found"
                    }
                  },
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "project_id": [
                      "The project_id parameter must be an integer."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve template. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteTemplate",
        "summary": "Delete Template",
        "description": "Permanently delete an email template and all its versions. If `project_id` is not provided, the template will be looked up in the team's default project.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The template slug (URL-friendly identifier)",
            "schema": {
              "type": "string",
              "example": "welcome-email"
            }
          },
          {
            "name": "project_id",
            "in": "query",
            "description": "Project ID to delete the template from. If not provided, uses the team's default project.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteTemplateResponse"
                },
                "example": {
                  "message": "Template deleted successfully."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Template or project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "template_not_found": {
                    "summary": "Template not found",
                    "value": {
                      "message": "Template with slug 'welcome-email' was not found.",
                      "error_code": "not_found"
                    }
                  },
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "project_id": [
                      "The project_id parameter must be an integer."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to delete template. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateTemplate",
        "summary": "Update Template",
        "description": "Update an existing email template's name and/or content. If content (html or json) is provided, a new active version will be created with extracted merge tags. If `project_id` is not provided, the template will be looked up in the team's default project.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The template slug (URL-friendly identifier)",
            "schema": {
              "type": "string",
              "example": "welcome-email"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTemplateRequest"
              },
              "examples": {
                "update_name": {
                  "summary": "Update template name only",
                  "value": {
                    "name": "Updated Welcome Email"
                  }
                },
                "update_html": {
                  "summary": "Update with new HTML content",
                  "value": {
                    "html": "<html><body><p>Hello {{NAME}}, welcome aboard!</p></body></html>"
                  }
                },
                "update_json": {
                  "summary": "Update with new Topol JSON content",
                  "value": {
                    "json": "{\"tagName\":\"mj-container\",\"children\":[{\"tagName\":\"mj-text\",\"content\":\"Hello {{FIRST_NAME}}!\"}]}"
                  }
                },
                "update_name_and_content": {
                  "summary": "Update name and content together",
                  "value": {
                    "name": "New Newsletter",
                    "html": "<html><body><p>Welcome {{SUBSCRIBER_NAME}}!</p></body></html>"
                  }
                },
                "update_with_project": {
                  "summary": "Update template in specific project",
                  "value": {
                    "project_id": 5,
                    "name": "Renamed Template"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateTemplateResponse"
                },
                "example": {
                  "message": "Template updated successfully.",
                  "data": {
                    "id": 123,
                    "name": "Updated Welcome Email",
                    "slug": "welcome-email",
                    "project_id": 5,
                    "folder_id": 10,
                    "purpose": "transactional",
                    "preparation_status": "pending",
                    "active_version": 2,
                    "merge_tags": [
                      {
                        "key": "NAME",
                        "required": true
                      }
                    ],
                    "created_at": "2026-01-15T10:00:00+00:00",
                    "updated_at": "2026-01-28T14:30:00+00:00"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Template or project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "template_not_found": {
                    "summary": "Template not found",
                    "value": {
                      "message": "Template with slug 'welcome-email' was not found.",
                      "error_code": "not_found"
                    }
                  },
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "both_content": {
                    "summary": "Both html and json provided",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "json": [
                          "The json field prohibits html from being present."
                        ]
                      }
                    }
                  },
                  "invalid_json": {
                    "summary": "Invalid JSON syntax",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "json": [
                          "The provided JSON is not valid."
                        ]
                      }
                    }
                  },
                  "name_too_long": {
                    "summary": "Name exceeds max length",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "name": [
                          "The name must not be greater than 255 characters."
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to update template. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/templates/{slug}/merge-tags": {
      "get": {
        "operationId": "getTemplateMergeTags",
        "summary": "Get Template Merge Tags",
        "description": "Retrieve the merge tags (variables) for a template version. By default, returns merge tags for the active version. Use the `version` parameter to get merge tags for a specific version.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The template slug (URL-friendly identifier)",
            "schema": {
              "type": "string",
              "example": "welcome-email"
            }
          },
          {
            "name": "project_id",
            "in": "query",
            "description": "Project ID to retrieve the template from. If not provided, uses the team's default project.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "version",
            "in": "query",
            "description": "Template version number. If not provided, uses the active version.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Merge tags retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetMergeTagsResponse"
                },
                "example": {
                  "message": "Merge tags retrieved successfully.",
                  "data": {
                    "project_id": 13,
                    "template_slug": "welcome-email",
                    "version": 2,
                    "merge_tags": [
                      {
                        "key": "first_name",
                        "required": true
                      },
                      {
                        "key": "company_name",
                        "required": false
                      },
                      {
                        "key": "order_items",
                        "required": false,
                        "children": [
                          {
                            "key": "item_name",
                            "type": "text"
                          },
                          {
                            "key": "item_quantity",
                            "type": "number"
                          },
                          {
                            "key": "item_price",
                            "type": "number"
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Template, version, or project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "template_not_found": {
                    "summary": "Template not found",
                    "value": {
                      "message": "Template with slug 'welcome-email' was not found.",
                      "error_code": "not_found"
                    }
                  },
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "version": [
                      "The version parameter must be an integer."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to retrieve merge tags. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/domains/{domain}/verify": {
      "post": {
        "operationId": "verifyDomain",
        "summary": "Verify Domain",
        "description": "Verify a domain's DNS records (DKIM and CNAME) with SparkPost. This triggers a verification check and returns the current status of DNS records.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "The domain name to verify",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain verification completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyDomainResponse"
                },
                "examples": {
                  "valid": {
                    "summary": "All DNS records valid",
                    "value": {
                      "message": "Domain verification completed.",
                      "data": {
                        "domain": "example.com",
                        "dkim_status": "valid",
                        "cname_status": "valid",
                        "dmarc_status": "valid",
                        "spf_status": "unverified",
                        "ownership_verified": "true",
                        "is_primary_domain": false
                      }
                    }
                  },
                  "unverified": {
                    "summary": "DNS records not configured",
                    "value": {
                      "message": "Domain verification completed.",
                      "data": {
                        "domain": "example.com",
                        "dkim_status": "invalid",
                        "cname_status": "invalid",
                        "dmarc_status": "missing",
                        "spf_status": "unverified",
                        "ownership_verified": null,
                        "is_primary_domain": false,
                        "dns": {
                          "dkim_record": null,
                          "cname_record": null,
                          "dkim_error": "DNS DKIM query error: dns lookup failed for scph0226._domainkey.example.com: no TXT records found",
                          "cname_error": "DNS CNAME query error: No CNAME records retrieved",
                          "dmarc_record": null,
                          "dmarc_error": "No DMARC record found for example.com or its parent domain.",
                          "spf_record": null,
                          "spf_error": null
                        },
                        "dmarc": {
                          "is_valid": false,
                          "status": "missing",
                          "found_at_domain": null,
                          "record": null,
                          "policy": null,
                          "subdomain_policy": null,
                          "error": "No DMARC record found for example.com or its parent domain.",
                          "covered_by_parent_policy": false
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Domain not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error - Invalid domain format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "domain": [
                      "The domain must be a valid domain name (e.g., example.com)."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error - Failed to verify domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Failed to verify domain. Please try again later.",
                  "error_code": "send_error"
                }
              }
            }
          }
        }
      }
    },
    "/templates/html": {
      "get": {
        "operationId": "getTemplateHtml",
        "summary": "Get Template HTML",
        "description": "Retrieve the HTML content and merge tags for a template's active version. Requires `project_id` and template `slug` as query parameters.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "project_id",
            "in": "query",
            "description": "The project ID the template belongs to.",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "slug",
            "in": "query",
            "description": "The template slug identifier.",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template HTML retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetTemplateHtmlResponse"
                },
                "example": {
                  "success": true,
                  "data": {
                    "html": "<h1>Hello {{name}}</h1><p>Welcome!</p>",
                    "merge_tags": [
                      {
                        "key": "name",
                        "name": "name",
                        "required": true
                      },
                      {
                        "key": "company",
                        "name": "company",
                        "required": false
                      }
                    ],
                    "subject": "Welcome Email"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Template not found or project does not belong to team",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "message": "Template not found."
                }
              }
            }
          }
        }
      }
    },
    "/folders": {
      "get": {
        "operationId": "listFolders",
        "summary": "List Folders",
        "description": "Retrieve a paginated list of the folders in a project, so a template can be filed into the right one.\n\nFolder IDs are what `folder_id` on `POST /templates` expects. Folders belong to a module: a `transactional` folder holds the templates you send single emails with, a `campaign` folder holds the ones the campaign builder can pick. A template's folder must belong to the same module as its `purpose`.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "project_id",
            "in": "query",
            "description": "Project ID to retrieve folders from. If not provided, uses the team's default project.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "purpose",
            "in": "query",
            "description": "Return only the folders of one module. If not provided, folders of both modules are returned.",
            "schema": {
              "type": "string",
              "enum": [
                "transactional",
                "campaign"
              ],
              "example": "campaign"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Number of results per page (1-100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Folders retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListFoldersResponse"
                },
                "example": {
                  "message": "Folders retrieved successfully.",
                  "data": {
                    "folders": [
                      {
                        "id": 10,
                        "name": "Emails",
                        "project_id": 5,
                        "purpose": "transactional",
                        "templates_count": 8,
                        "created_at": "2025-01-15T10:00:00+00:00",
                        "updated_at": "2025-01-20T14:30:00+00:00"
                      },
                      {
                        "id": 11,
                        "name": "Campaigns",
                        "project_id": 5,
                        "purpose": "campaign",
                        "templates_count": 12,
                        "created_at": "2025-01-15T10:00:00+00:00",
                        "updated_at": "2025-02-02T09:12:00+00:00"
                      }
                    ],
                    "pagination": {
                      "total": 2,
                      "per_page": 25,
                      "current_page": 1,
                      "last_page": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "404": {
            "description": "Project not found or no default project configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "project_not_found": {
                    "summary": "Project not found",
                    "value": {
                      "message": "Project with ID '123' was not found or you don't have access to it.",
                      "error_code": "not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "purpose": [
                      "The purpose must be either transactional or campaign."
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List Projects",
        "description": "Retrieve a paginated list of projects for the authenticated team.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "description": "Number of results per page (1-100). Defaults to 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number. Defaults to 1.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Projects retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListProjectsResponse"
                },
                "example": {
                  "message": "Projects retrieved successfully.",
                  "data": {
                    "projects": [
                      {
                        "id": 1,
                        "name": "Default Project",
                        "emoji": null,
                        "team_id": 123,
                        "created_at": "2024-01-15T10:30:00+00:00",
                        "updated_at": "2024-01-15T10:30:00+00:00"
                      }
                    ],
                    "pagination": {
                      "total": 1,
                      "per_page": 25,
                      "current_page": 1,
                      "last_page": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedResponse"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "example": {
                  "message": "Validation failed.",
                  "error_code": "validation_error",
                  "errors": {
                    "per_page": [
                      "The per_page parameter must not exceed 100."
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/audience/lists": {
      "get": {
        "operationId": "listAudienceLists",
        "summary": "List audience lists",
        "description": "Returns all audience lists for the authenticated team. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)"
          }
        ],
        "responses": {
          "200": {
            "description": "Lists retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAudienceListsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createAudienceList",
        "summary": "Create an audience list",
        "description": "Create a new audience list. The name must be unique within the team. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreAudienceListRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "List created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/lists/bulk": {
      "delete": {
        "operationId": "bulkDestroyAudienceLists",
        "summary": "Bulk delete audience lists",
        "description": "Delete up to 50 lists in a single request. All `list_ids` must belong to the authenticated team. If any list has segments restricted to it, nothing is deleted and the response is `409` `list_in_use`. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkDestroyAudienceListsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkDestroyAudienceListsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "description": "The list is used by segments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "The list cannot be deleted: \"VIP\" is used by segment \"VIP openers\". Remove the list restriction from those segments or delete them first.",
                  "error_code": "list_in_use"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/lists/{listId}": {
      "get": {
        "operationId": "showAudienceList",
        "summary": "Show an audience list",
        "description": "Retrieve a single audience list. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "List ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "200": {
            "description": "List retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "List not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateAudienceList",
        "summary": "Update an audience list",
        "description": "Partially update an audience list. If no fields are provided the existing list is returned unchanged. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "List ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudienceListRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "List not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "destroyAudienceList",
        "summary": "Delete an audience list",
        "description": "Permanently delete an audience list. A list that segments are restricted to cannot be deleted (`409` `list_in_use`): remove the restriction from those segments or delete them first. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "List ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "204": {
            "description": "List deleted"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "List not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "409": {
            "description": "The list is used by segments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "The list cannot be deleted: \"VIP\" is used by segment \"VIP openers\". Remove the list restriction from those segments or delete them first.",
                  "error_code": "list_in_use"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/contacts": {
      "get": {
        "operationId": "listAudienceContacts",
        "summary": "List audience contacts",
        "description": "List contacts with pagination and filtering. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Search by email or contact name"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "subscribed",
                "unsubscribed",
                "bounced",
                "complained",
                "unverified"
              ]
            },
            "description": "Filter by contact status"
          },
          {
            "name": "list_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to contacts in a specific list (must belong to the team)"
          },
          {
            "name": "segment_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to contacts matching a specific segment (must belong to the team)"
          }
        ],
        "responses": {
          "200": {
            "description": "Contacts retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAudienceContactsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createAudienceContact",
        "summary": "Create a contact",
        "description": "Create a single contact. If `double_opt_in` is provided the contact is created in `unverified` status and receives a confirmation email — they become `subscribed` only after clicking the confirmation link. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreAudienceContactRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Contact created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceContactResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Double opt-in confirmation template not found. Returned only when `double_opt_in` is supplied and its `template_slug` does not exist, has no active (published) version, or no default project is configured for the team. No contact is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "template_not_found": {
                    "summary": "Template slug not found",
                    "value": {
                      "message": "Template with slug 'confirm-subscription' was not found.",
                      "error_code": "template_not_found"
                    }
                  },
                  "no_active_version": {
                    "summary": "Template has no active version",
                    "value": {
                      "message": "Template 'confirm-subscription' has no active version. Publish a version of this template before using it.",
                      "error_code": "template_not_found"
                    }
                  },
                  "no_default_project": {
                    "summary": "No default project configured",
                    "value": {
                      "message": "No default project is configured for this team.",
                      "error_code": "template_not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "A contact with this email already exists for the team. No contact is created and the existing one is left untouched — update it with `PATCH /audience/contacts/{contactId}`, or use `POST /audience/contacts/bulk` with `update_existing` enabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "contact_already_exists": {
                    "summary": "Email already used by a contact in this team",
                    "value": {
                      "message": "A contact with the email existing@demo.test already exists. Use PATCH /audience/contacts/{contactId} to update it, or POST /audience/contacts/bulk with update_existing enabled.",
                      "error_code": "resource_already_exists"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "Confirmation email transmission failed (upstream provider error). Returned only when `double_opt_in` is supplied and the confirmation email could not be sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Unconfigured Sending Domain <sender.example.com>",
                  "error_code": "transmission_failed"
                }
              }
            }
          }
        }
      }
    },
    "/audience/contacts/bulk": {
      "post": {
        "operationId": "bulkCreateAudienceContacts",
        "summary": "Bulk create contacts",
        "description": "Create up to 1000 contacts in a single request. Send `contacts` to give each row its own properties, lists and topics, or the legacy `emails` array when the whole batch shares one property map. Emails are normalized and deduplicated; addresses that already exist are reported in `already_existed`, are always attached to the requested lists and topics and always have a row-level `opt_out` applied, and have their properties merged only when `update_existing` is set. Rows that fail validation are skipped and returned in `errors` — the request only fails with 422 when nothing could be written. The response carries the contact ids, so a follow-up call to the bulk list or topic endpoints needs no lookup. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkStoreAudienceContactsRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Contacts created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkStoreAudienceContactsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/contacts/lists/bulk": {
      "post": {
        "operationId": "bulkAttachContactsToLists",
        "summary": "Bulk attach contacts to lists",
        "description": "Attach every combination of `contact_ids × list_ids` (up to 1000 contacts × 50 lists). Existing pairs are reported in `already_attached`. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkAudienceContactListsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkAttachContactsToListsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "bulkDetachContactsFromLists",
        "summary": "Bulk detach contacts from lists",
        "description": "Detach every combination of `contact_ids × list_ids` (up to 1000 contacts × 50 lists). Pairs that were not attached are reported in `not_present`. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkAudienceContactListsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkDetachContactsFromListsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/contacts/topics/bulk": {
      "post": {
        "operationId": "bulkSubscribeContactsToTopics",
        "summary": "Bulk subscribe contacts to topics",
        "description": "Subscribe every combination of `contact_ids × topic_ids` (up to 1000 contacts × 50 topics). Pairs that already exist are reported in `already_subscribed`. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkAudienceContactTopicsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkSubscribeContactsToTopicsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "bulkUnsubscribeContactsFromTopics",
        "summary": "Bulk unsubscribe contacts from topics",
        "description": "Remove every combination of `contact_ids × topic_ids`. Pairs that did not exist are ignored. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkAudienceContactTopicsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkUnsubscribeContactsFromTopicsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/contacts/{contactId}": {
      "get": {
        "operationId": "showAudienceContact",
        "summary": "Show a contact",
        "description": "Retrieve a single contact. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Contact retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceContactResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateAudienceContact",
        "summary": "Update a contact",
        "description": "Partially update a contact. If no fields are provided the contact is returned unchanged. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudienceContactRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceContactResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "destroyAudienceContact",
        "summary": "Delete a contact",
        "description": "Permanently delete a contact. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Contact deleted"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/contacts/{contactId}/lists/{listId}": {
      "post": {
        "operationId": "attachAudienceContactToList",
        "summary": "Attach contact to list",
        "description": "Add a contact to a list. Returns `201` if the contact was newly attached, or `200` if the contact was already in the list. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          },
          {
            "name": "listId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "List ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "200": {
            "description": "Contact was already in the list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachContactToListResponse"
                }
              }
            }
          },
          "201": {
            "description": "Contact attached to list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachContactToListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact or list not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "detachAudienceContactFromList",
        "summary": "Detach contact from list",
        "description": "Remove a contact from a list. Idempotent — returns `204` whether the pair existed or not. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          },
          {
            "name": "listId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "List ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "204": {
            "description": "Detached (or pair did not exist)"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact or list not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/contacts/{contactId}/topics/{topicId}": {
      "post": {
        "operationId": "subscribeAudienceContactToTopic",
        "summary": "Subscribe contact to topic",
        "description": "Subscribe a contact to a topic. Returns `201` if the subscription is new, or `200` if the contact was already subscribed. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          },
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Topic ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Contact was already subscribed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachContactToTopicResponse"
                }
              }
            }
          },
          "201": {
            "description": "Contact subscribed to topic",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachContactToTopicResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact or topic not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "unsubscribeAudienceContactFromTopic",
        "summary": "Unsubscribe contact from topic",
        "description": "Unsubscribe a contact from a topic. Idempotent — returns `204` whether the subscription existed or not. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Contact ID"
          },
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Topic ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Unsubscribed (or no subscription existed)"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Contact or topic not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/topics": {
      "get": {
        "operationId": "listAudienceTopics",
        "summary": "List audience topics",
        "description": "List topics with pagination. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)"
          }
        ],
        "responses": {
          "200": {
            "description": "Topics retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAudienceTopicsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createAudienceTopic",
        "summary": "Create a topic",
        "description": "Create a topic. The `default_subscription` field is set at creation and cannot be changed later. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreAudienceTopicRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Topic created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceTopicResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/topics/{topicId}": {
      "get": {
        "operationId": "showAudienceTopic",
        "summary": "Show a topic",
        "description": "Retrieve a single topic. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Topic ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Topic retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceTopicResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Topic not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateAudienceTopic",
        "summary": "Update a topic",
        "description": "Partially update a topic. The `default_subscription` field is immutable. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Topic ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudienceTopicRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceTopicResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Topic not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "destroyAudienceTopic",
        "summary": "Delete a topic",
        "description": "Permanently delete a topic. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Topic ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Topic deleted"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Topic not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/properties": {
      "get": {
        "operationId": "listAudienceProperties",
        "summary": "List audience properties",
        "description": "List the team's custom contact properties. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)"
          }
        ],
        "responses": {
          "200": {
            "description": "Properties retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAudiencePropertiesResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createAudienceProperty",
        "summary": "Create a property",
        "description": "Create a new property that contacts can store. The `name` and `type` fields are immutable after creation — to change them, delete the property and create a new one. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreAudiencePropertyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Property created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudiencePropertyResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "A property with this name already exists.",
                  "error_code": "resource_already_exists"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/properties/{propertyId}": {
      "get": {
        "operationId": "showAudienceProperty",
        "summary": "Show a property",
        "description": "Retrieve a single property. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "propertyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Property ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Property retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudiencePropertyResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Property not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateAudienceProperty",
        "summary": "Update a property",
        "description": "Update the property's fallback value. The `name` and `type` fields cannot be changed (they would orphan data on existing contacts). If the request body contains no recognized fields, the property is returned unchanged with a `200` response. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "propertyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Property ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudiencePropertyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudiencePropertyResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Property not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "destroyAudienceProperty",
        "summary": "Delete a property",
        "description": "Permanently delete a property. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "propertyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Property ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Property deleted"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Property not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/segments": {
      "get": {
        "operationId": "listAudienceSegments",
        "summary": "List audience segments",
        "description": "List segments with pagination. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)"
          },
          {
            "name": "list_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to segments restricted to a specific list (must belong to the team)"
          }
        ],
        "responses": {
          "200": {
            "description": "Segments retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAudienceSegmentsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createAudienceSegment",
        "summary": "Create a segment",
        "description": "Create a segment defined by condition groups (conditions within a group are joined by OR; groups are joined by AND). Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreAudienceSegmentRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Segment created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceSegmentResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audience/segments/{segmentId}": {
      "get": {
        "operationId": "showAudienceSegment",
        "summary": "Show a segment",
        "description": "Retrieve a single segment. Requires the `audience:read` scope.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "segmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Segment ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Segment retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceSegmentResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Segment not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateAudienceSegment",
        "summary": "Update a segment",
        "description": "Partially update a segment. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "segmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Segment ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudienceSegmentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowAudienceSegmentResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Segment not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "destroyAudienceSegment",
        "summary": "Delete a segment",
        "description": "Permanently delete a segment. Requires the `audience:write` scope and is blocked for sandbox API keys.",
        "tags": [
          "Audience"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "segmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Segment ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Segment deleted"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Segment not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/campaigns": {
      "get": {
        "operationId": "listCampaigns",
        "summary": "List campaigns",
        "description": "Returns a paginated list of campaigns for the authenticated team, each with embedded engagement stats. Requires the `campaigns:read` scope.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1
            },
            "description": "Page number"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "scheduled",
                "preparing",
                "in_review",
                "sending",
                "sent",
                "failed"
              ]
            },
            "description": "Filter by campaign status"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaigns retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListCampaignsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createCampaign",
        "summary": "Create a campaign",
        "description": "Creates a draft campaign. Give the content as `html_content` (optionally with the editor's `json_content`) or as a `template_id`, whose HTML is copied onto the campaign. Every list, segment, topic and template must belong to your team. The sender domain is checked when the campaign is sent, not here; language override senders are checked here and must use a verified sending domain. Send or schedule the draft with the send and schedule endpoints. Requires the `campaigns:write` scope. Not available to sandbox keys.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreCampaignRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Campaign created successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateCampaignResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "422": {
            "description": "Validation error. Also returned when a list, segment, topic or template is not in your team, when both `html_content` and `template_id` are given, or when a language override sender uses an unverified domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/campaigns/{campaignId}": {
      "get": {
        "operationId": "showCampaign",
        "summary": "Show a campaign",
        "description": "Retrieve a single campaign with embedded stats and rendered HTML content. Requires the `campaigns:read` scope.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "campaignId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Campaign ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShowCampaignResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Campaign not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/campaigns/{campaignId}/events": {
      "get": {
        "operationId": "listCampaignEvents",
        "summary": "List campaign engagement events",
        "description": "Returns engagement events (opens, clicks, bounces, etc.) for a campaign, with optional filtering by type, recipient email, and date range. Uses cursor-based pagination: keep requesting with the returned `next_cursor` until it is `null`. When a filter is applied, a page may come back with an empty `events` array **and** a non-null `next_cursor` — that means more pages remain, not that there are no matching events, so continue paginating until `next_cursor` is `null`. Requires the `campaigns:read` scope.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "campaignId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Campaign ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          },
          {
            "name": "event_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "injection",
                "delivery",
                "bounce",
                "spam_complaint",
                "open",
                "click",
                "list_unsubscribe"
              ]
            },
            "description": "Filter by event type"
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "email"
            },
            "description": "Filter by recipient email"
          },
          {
            "name": "start_date",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only events at or after this time (ISO 8601). A date-only value (e.g. `2026-05-01`) is treated as the start of that day in UTC."
          },
          {
            "name": "end_date",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only events at or before this time (ISO 8601), inclusive. A date-only value (e.g. `2026-05-01`) covers the whole of that day in UTC (through 23:59:59)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "description": "Max events per page (max 100)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Pagination cursor from a previous response"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign events retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListCampaignEventsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Campaign not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/campaigns/{campaignId}/send": {
      "post": {
        "operationId": "sendCampaign",
        "summary": "Send a campaign now",
        "description": "Immediately dispatches a draft campaign. The campaign must be a draft with a subject, sender email, and content. Sending is asynchronous; the campaign transitions to `preparing`. Requires the `campaigns:write` scope. Not available to sandbox keys.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "campaignId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Campaign ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "202": {
            "description": "Campaign sending started.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignActionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Campaign not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Precondition failed. `campaign_not_sendable` when the campaign is not a draft or is missing a subject, sender, or content; `campaign_has_pending_schedule` when the campaign already has a future scheduled delivery time (unschedule it first to send now — this also clears a time staged on a draft — or use the schedule endpoint to confirm it).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_sendable": {
                    "summary": "Campaign is not in a sendable state",
                    "value": {
                      "message": "Campaign can only be sent from draft status.",
                      "error_code": "campaign_not_sendable"
                    }
                  },
                  "pending_schedule": {
                    "summary": "Campaign has a pending scheduled time",
                    "value": {
                      "message": "This campaign is staged to send at 2026-06-01T09:00:00+00:00. Unschedule it first to send immediately, or use the schedule endpoint to confirm the delivery time.",
                      "error_code": "campaign_has_pending_schedule"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/campaigns/{campaignId}/schedule": {
      "post": {
        "operationId": "scheduleCampaign",
        "summary": "Schedule a campaign",
        "description": "Schedules a campaign for future delivery, or reschedules an already-scheduled campaign to a new time. The campaign transitions to (or stays) `scheduled` and is dispatched automatically at the given time. Requires the `campaigns:write` scope. Not available to sandbox keys.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "campaignId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Campaign ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleCampaignRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign scheduled for delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignActionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Campaign not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Validation error (invalid or missing `scheduled_at`), or `campaign_not_sendable` when the campaign is not a draft or scheduled campaign, or is missing a subject, sender, or content.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ValidationErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "validation_error": {
                    "summary": "Invalid or missing scheduled_at",
                    "value": {
                      "message": "Validation failed.",
                      "error_code": "validation_error",
                      "errors": {
                        "scheduled_at": [
                          "The scheduled delivery time must be in the future."
                        ]
                      }
                    }
                  },
                  "not_sendable": {
                    "summary": "Campaign is not in a sendable state",
                    "value": {
                      "message": "Campaign can only be sent from draft status.",
                      "error_code": "campaign_not_sendable"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/campaigns/{campaignId}/unschedule": {
      "post": {
        "operationId": "unscheduleCampaign",
        "summary": "Unschedule a campaign",
        "description": "Cancels a scheduled send, returning the campaign to `draft`. Also clears a delivery time staged on a `draft` in the web editor, so the draft can then be sent with the send endpoint. The campaign must be `scheduled`, or a `draft` with a staged delivery time. Requires the `campaigns:write` scope. Not available to sandbox keys.",
        "tags": [
          "Campaigns"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "campaignId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Campaign ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign unscheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignActionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Campaign not found.",
                  "error_code": "not_found"
                }
              }
            }
          },
          "422": {
            "description": "Precondition failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "message": "Only scheduled campaigns, or drafts with a staged delivery time, can be unscheduled.",
                  "error_code": "campaign_not_scheduled"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key for authentication"
      }
    },
    "responses": {
      "UnauthorizedError": {
        "description": "Unauthorized - Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnauthorizedResponse"
            },
            "examples": {
              "missing_key": {
                "summary": "Missing API key",
                "value": {
                  "message": "API key is required."
                }
              },
              "invalid_key": {
                "summary": "Invalid API key",
                "value": {
                  "message": "Invalid API key."
                }
              }
            }
          }
        }
      },
      "ServiceUnavailableError": {
        "description": "Service unavailable - the API key could not be verified, so the request was not processed. This does not mean the key is invalid; retry after the delay given in the Retry-After header.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer",
              "example": 5
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Unable to verify your API key right now. Please retry shortly.",
              "error_code": "auth_unavailable"
            }
          }
        }
      },
      "ForbiddenError": {
        "description": "Forbidden - API key does not have the required scope",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Your API key does not have the required permissions for this action.",
              "error_code": "insufficient_scope"
            }
          }
        }
      },
      "ServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "An unexpected error occurred. Please try again later.",
              "error_code": "send_error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "SendEmailRequest": {
        "type": "object",
        "description": "Email sending request. **Required:** `from`, `to`, and at least one of `html`, `text`, or `template_slug`. The `subject` is required unless `template_slug` is provided — when using a template, the subject defaults to the template's subject (or template name as fallback), but can be overridden. When using `template_slug`, if `project_id` is not provided, the team's default project will be used.",
        "required": [
          "from",
          "to"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "description": "Sender email address",
            "example": "sender@example.com"
          },
          "from_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "Sender display name",
            "example": "Sender Name"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 998,
            "description": "Email subject line. Required when not using a template. When using `template_slug`, defaults to the template's subject (or template name as fallback). If provided alongside a template, overrides the template subject.",
            "example": "Welcome to Lettr"
          },
          "to": {
            "type": "array",
            "description": "Recipient email addresses",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "type": "string",
              "format": "email",
              "maxLength": 255
            },
            "example": [
              "recipient@example.com"
            ]
          },
          "cc": {
            "type": "array",
            "description": "Carbon copy recipient email addresses",
            "items": {
              "type": "string",
              "format": "email",
              "maxLength": 255
            },
            "example": [
              "cc@example.com"
            ]
          },
          "bcc": {
            "type": "array",
            "description": "Blind carbon copy recipient email addresses",
            "items": {
              "type": "string",
              "format": "email",
              "maxLength": 255
            },
            "example": [
              "bcc@example.com"
            ]
          },
          "reply_to": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "maxLength": 255,
            "description": "Reply-To email address",
            "example": "reply@example.com"
          },
          "reply_to_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "Reply-To display name",
            "example": "Reply Name"
          },
          "html": {
            "type": [
              "string",
              "null"
            ],
            "description": "HTML content of the email. At least one of `html` or `text` is required, but providing both is recommended for best compatibility across email clients.",
            "example": "<h1>Hello</h1><p>Welcome!</p>"
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "Plain text content of the email. At least one of `html` or `text` is required, but providing both is recommended for best compatibility across email clients.",
            "example": "Hello\n\nWelcome!"
          },
          "amp_html": {
            "type": [
              "string",
              "null"
            ],
            "description": "AMP HTML content for supported email clients"
          },
          "project_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Project ID containing the template. If not provided when using template_slug, the team's default project will be used.",
            "example": 123
          },
          "template_slug": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "Template slug to use for email content. When provided, the template's HTML will be used instead of the html field.",
            "example": "welcome-email"
          },
          "template_version": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "description": "Specific template version to use. If not provided, the active version will be used.",
            "example": 1
          },
          "tag": {
            "type": "string",
            "maxLength": 64,
            "description": "Tag for tracking and analytics. Automatically set from template_slug if not provided.",
            "example": "welcome-series-2024"
          },
          "metadata": {
            "type": "object",
            "description": "Custom metadata attached to the email for tracking purposes",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "user_id": "12345",
              "campaign": "onboarding"
            }
          },
          "headers": {
            "type": "object",
            "description": "Custom email headers. Up to 10 headers allowed. Standard envelope headers (From, To, Subject, etc.), SparkPost internal headers (X-MSYS-API), and List-Unsubscribe and List-Unsubscribe-Post headers are managed by the system and cannot be set manually.",
            "maxProperties": 10,
            "additionalProperties": {
              "type": "string",
              "maxLength": 998
            },
            "example": {
              "X-Mailer": "MyApp/1.0",
              "X-Custom-ID": "abc-123"
            }
          },
          "substitution_data": {
            "type": "object",
            "description": "Variables for template substitution in email content",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "first_name": "John",
              "company": "Acme Inc"
            }
          },
          "options": {
            "type": "object",
            "description": "Email delivery options",
            "properties": {
              "click_tracking": {
                "type": "boolean",
                "description": "Enable click tracking for links in the email"
              },
              "open_tracking": {
                "type": "boolean",
                "description": "Enable open tracking via tracking pixel"
              },
              "transactional": {
                "type": "boolean",
                "default": true,
                "description": "Mark email as transactional (not marketing). **Defaults to `true`.** Transactional mail bypasses unsubscribe suppression, so any send a recipient can opt out of must explicitly set this to `false`."
              },
              "inline_css": {
                "type": "boolean",
                "description": "Inline CSS styles in HTML content"
              },
              "perform_substitutions": {
                "type": "boolean",
                "description": "Perform variable substitutions in content"
              }
            }
          },
          "attachments": {
            "type": "array",
            "description": "File attachments. When provided, each attachment must include name, type, and data.",
            "items": {
              "$ref": "#/components/schemas/Attachment"
            }
          }
        }
      },
      "Attachment": {
        "type": "object",
        "description": "Email attachment",
        "required": [
          "name",
          "type",
          "data"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Filename of the attachment",
            "example": "invoice.pdf"
          },
          "type": {
            "type": "string",
            "maxLength": 255,
            "description": "MIME type of the attachment",
            "example": "application/pdf"
          },
          "data": {
            "type": "string",
            "pattern": "^[A-Za-z0-9+/=]+$",
            "description": "Base64 encoded file content (no line breaks)",
            "example": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlL1BhZ2U="
          }
        }
      },
      "SendEmailSuccessResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "Email queued for delivery."
          },
          "data": {
            "type": "object",
            "required": [
              "request_id",
              "accepted",
              "rejected"
            ],
            "properties": {
              "request_id": {
                "type": "string",
                "description": "Unique identifier for this email transmission",
                "example": "12345678901234567890"
              },
              "accepted": {
                "type": "integer",
                "minimum": 0,
                "description": "Number of recipients accepted for delivery",
                "example": 1
              },
              "rejected": {
                "type": "integer",
                "minimum": 0,
                "description": "Number of recipients rejected",
                "example": 0
              }
            }
          }
        }
      },
      "ValidationErrorResponse": {
        "type": "object",
        "required": [
          "message",
          "error_code",
          "errors"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "Validation failed."
          },
          "error_code": {
            "type": "string",
            "description": "Error code (always `validation_error` for 422 responses)",
            "const": "validation_error",
            "example": "validation_error"
          },
          "errors": {
            "type": "object",
            "description": "Field-specific validation errors",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": {
              "from": [
                "The sender email address is required."
              ],
              "to": [
                "At least one recipient email address is required."
              ]
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "message",
          "error_code"
        ],
        "description": "Error response for non-validation errors (400, 409, 500, 502).",
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "The sender domain could not be determined from the email address."
          },
          "error_code": {
            "$ref": "#/components/schemas/ErrorCode"
          }
        }
      },
      "UnauthorizedResponse": {
        "type": "object",
        "required": [
          "message"
        ],
        "description": "Error response for authentication failures (401).",
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "API key is required."
          }
        }
      },
      "ErrorCode": {
        "type": "string",
        "description": "Error codes returned by the API.\n\n| Code | HTTP Status | Description |\n|------|-------------|-------------|\n| `validation_error` | 422 | Request validation failed. Check the `errors` object for field-specific messages. |\n| `invalid_domain` | 400 | The sender domain could not be determined from the email address. |\n| `unconfigured_domain` | 400 | The sender domain is not configured or approved for sending. |\n| `send_error` | 400, 500 | General error during email send preparation or domain registration. |\n| `retrieval_error` | 400, 500 | Failed to retrieve resources (e.g., sandbox key without associated user, upstream error). |\n| `transmission_failed` | 502 | Email transmission to the upstream provider failed. |\n| `resource_already_exists` | 409 | The resource (e.g., domain) already exists. |\n| `not_found` | 404 | The specified resource was not found. |\n| `template_not_found` | 404 | The specified template, project, or template version was not found. |\n| `insufficient_scope` | 403 | The API key does not have the required scope for this endpoint. |\n| `schedule_cancellation_failed` | 409, 500 | The scheduled email can no longer be cancelled (already sent, already cancelled, or being injected right now), or the cancellation itself failed. |\n| `quota_exceeded` | 429 | Monthly sending quota exceeded. Upgrade your plan to continue sending. |\n| `daily_quota_exceeded` | 429 | Daily sending quota exceeded. Try again tomorrow. |\n| `campaign_not_sendable` | 422 | The campaign cannot be sent in its current state (not a draft, or missing subject/sender/content). |\n| `campaign_not_scheduled` | 422 | The campaign is not scheduled, so it cannot be unscheduled. |",
        "enum": [
          "validation_error",
          "idempotency_key_conflict",
          "idempotency_in_progress",
          "invalid_domain",
          "unconfigured_domain",
          "send_error",
          "retrieval_error",
          "transmission_failed",
          "resource_already_exists",
          "not_found",
          "template_not_found",
          "insufficient_scope",
          "schedule_cancellation_failed",
          "quota_exceeded",
          "daily_quota_exceeded",
          "campaign_not_sendable",
          "campaign_not_scheduled"
        ],
        "example": "invalid_domain"
      },
      "StoreDomainRequest": {
        "type": "object",
        "description": "Request to create a new sending domain",
        "required": [
          "domain"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "maxLength": 255,
            "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$",
            "description": "The domain name to register (e.g., example.com)",
            "example": "example.com"
          }
        }
      },
      "StoreDomainResponse": {
        "type": "object",
        "description": "Response after successfully creating a domain",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "Domain created successfully."
          },
          "data": {
            "$ref": "#/components/schemas/DomainView"
          }
        }
      },
      "DomainView": {
        "type": "object",
        "description": "View of a sending domain",
        "required": [
          "domain",
          "status",
          "status_label"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "The domain name",
            "example": "example.com"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "blocked"
            ],
            "description": "Current status of the domain",
            "example": "pending"
          },
          "status_label": {
            "type": "string",
            "description": "Human-readable status label",
            "example": "Pending Review"
          },
          "dkim": {
            "type": [
              "object",
              "null"
            ],
            "description": "DKIM configuration for the domain",
            "properties": {
              "public": {
                "type": "string",
                "description": "Public DKIM key"
              },
              "selector": {
                "type": "string",
                "description": "DKIM selector"
              },
              "headers": {
                "type": "string",
                "description": "Headers to sign"
              },
              "signing_domain": {
                "type": "string",
                "description": "Domain used for DKIM signing. Normally matches the top-level `domain` field."
              }
            }
          }
        }
      },
      "ListDomainsResponse": {
        "type": "object",
        "description": "Response containing a list of domains",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Domains retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "domains"
            ],
            "properties": {
              "domains": {
                "type": "array",
                "description": "List of domains",
                "items": {
                  "$ref": "#/components/schemas/DomainListItemView"
                }
              }
            }
          }
        }
      },
      "DomainListItemView": {
        "type": "object",
        "description": "View of a domain in the list response",
        "required": [
          "domain",
          "status",
          "status_label",
          "can_send",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "The domain name",
            "example": "example.com"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "blocked"
            ],
            "description": "Current status of the domain",
            "example": "approved"
          },
          "status_label": {
            "type": "string",
            "description": "Human-readable status label",
            "example": "Approved"
          },
          "can_send": {
            "type": "boolean",
            "description": "Whether the domain can be used for sending emails",
            "example": true
          },
          "cname_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "CNAME verification status",
            "example": "valid"
          },
          "dkim_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "DKIM verification status",
            "example": "valid"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the domain was created. Null for legacy records stored without a creation timestamp.",
            "example": "2024-01-15T10:30:00+00:00"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the domain was last updated. Falls back to the creation timestamp, and is null when neither is stored.",
            "example": "2024-01-16T14:45:00+00:00"
          }
        }
      },
      "ShowDomainResponse": {
        "type": "object",
        "description": "Response containing a single domain with full details",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Domain retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/DomainDetailView"
          }
        }
      },
      "DomainDetailView": {
        "type": "object",
        "description": "Detailed view of a single domain",
        "required": [
          "domain",
          "status",
          "status_label",
          "can_send",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "The domain name",
            "example": "example.com"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "blocked"
            ],
            "description": "Current status of the domain",
            "example": "approved"
          },
          "status_label": {
            "type": "string",
            "description": "Human-readable status label",
            "example": "Approved"
          },
          "can_send": {
            "type": "boolean",
            "description": "Whether the domain can be used for sending emails",
            "example": true
          },
          "cname_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "CNAME verification status",
            "example": "valid"
          },
          "dkim_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "DKIM verification status. `null` until the domain has been verified at least once via `POST /domains/{domain}/verify`.",
            "example": "valid"
          },
          "dmarc_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "DMARC verification status. `null` until the domain has been verified at least once.",
            "enum": [
              "valid",
              "invalid",
              "missing",
              "unverified",
              null
            ],
            "example": "valid"
          },
          "spf_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "SPF verification status. `null` until the domain has been verified at least once.",
            "enum": [
              "valid",
              "invalid",
              "missing",
              "unverified",
              null
            ],
            "example": "valid"
          },
          "is_primary_domain": {
            "type": "boolean",
            "description": "True when this is a root/apex sending domain (not a subdomain). Primary domains require SPF instead of CNAME delegation.",
            "example": false
          },
          "tracking_domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "Associated tracking domain for click/open tracking",
            "example": "tracking.example.com"
          },
          "dns": {
            "type": [
              "object",
              "null"
            ],
            "description": "DNS records for domain verification",
            "properties": {
              "dkim": {
                "type": "object",
                "description": "DKIM DNS record details",
                "properties": {
                  "selector": {
                    "type": "string",
                    "description": "DKIM selector",
                    "example": "scph0123"
                  },
                  "public": {
                    "type": "string",
                    "description": "DKIM public key",
                    "example": "MIGfMA0GCSqGSIb3DQEBA..."
                  },
                  "headers": {
                    "type": "string",
                    "description": "Headers included in DKIM signature",
                    "example": "from:to:subject:date"
                  }
                }
              }
            }
          },
          "dns_provider": {
            "type": [
              "object",
              "null"
            ],
            "description": "Detected DNS provider for this domain, or `null` if detection hasn't run.",
            "required": [
              "provider",
              "provider_label",
              "nameservers",
              "error"
            ],
            "properties": {
              "provider": {
                "type": "string",
                "description": "Machine-readable DNS provider identifier.",
                "example": "cloudflare"
              },
              "provider_label": {
                "type": "string",
                "description": "Human-readable DNS provider name.",
                "example": "Cloudflare"
              },
              "nameservers": {
                "type": "array",
                "description": "Nameservers detected for the domain.",
                "items": {
                  "type": "string"
                },
                "example": [
                  "ns1.example.com",
                  "ns2.example.com"
                ]
              },
              "error": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Error message if DNS provider detection failed.",
                "example": null
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the domain was created. Null for legacy records stored without a creation timestamp.",
            "example": "2024-01-15T10:30:00+00:00"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the domain was last updated. Falls back to the creation timestamp, and is null when neither is stored.",
            "example": "2024-01-16T14:45:00+00:00"
          }
        }
      },
      "VerifyDomainResponse": {
        "type": "object",
        "description": "Response containing domain verification results",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Domain verification completed."
          },
          "data": {
            "$ref": "#/components/schemas/DomainVerificationView"
          }
        }
      },
      "DomainVerificationView": {
        "type": "object",
        "description": "Domain verification status and DNS details",
        "required": [
          "domain",
          "dkim_status",
          "cname_status",
          "dmarc_status",
          "spf_status",
          "is_primary_domain"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "The domain name",
            "example": "example.com"
          },
          "dkim_status": {
            "type": "string",
            "description": "DKIM verification status",
            "enum": [
              "valid",
              "unverified",
              "invalid"
            ],
            "example": "valid"
          },
          "cname_status": {
            "type": "string",
            "description": "CNAME verification status. `not_applicable` is returned for primary (apex) sending domains, which require SPF instead of CNAME delegation.",
            "enum": [
              "valid",
              "unverified",
              "invalid",
              "not_applicable"
            ],
            "example": "valid"
          },
          "dmarc_status": {
            "type": "string",
            "description": "DMARC verification status.",
            "enum": [
              "valid",
              "invalid",
              "missing",
              "unverified"
            ],
            "example": "valid"
          },
          "spf_status": {
            "type": "string",
            "description": "SPF verification status.",
            "enum": [
              "valid",
              "invalid",
              "missing",
              "unverified"
            ],
            "example": "valid"
          },
          "is_primary_domain": {
            "type": "boolean",
            "description": "True when this is a root/apex sending domain (not a subdomain). Primary domains require SPF instead of CNAME delegation.",
            "example": false
          },
          "ownership_verified": {
            "type": [
              "string",
              "null"
            ],
            "description": "Whether domain ownership has been verified",
            "example": "true"
          },
          "dns": {
            "$ref": "#/components/schemas/DomainDnsVerificationView"
          },
          "dmarc": {
            "$ref": "#/components/schemas/DmarcValidationResult"
          },
          "spf": {
            "$ref": "#/components/schemas/SpfValidationResult"
          }
        }
      },
      "DomainDnsVerificationView": {
        "type": "object",
        "description": "DNS verification error details",
        "properties": {
          "dkim_record": {
            "type": [
              "string",
              "null"
            ],
            "description": "Found DKIM record value",
            "example": null
          },
          "cname_record": {
            "type": [
              "string",
              "null"
            ],
            "description": "Found CNAME record value",
            "example": null
          },
          "dkim_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "DKIM verification error message",
            "example": "DKIM record not found"
          },
          "cname_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "CNAME verification error message",
            "example": "CNAME record not found"
          },
          "dmarc_record": {
            "type": [
              "string",
              "null"
            ],
            "description": "Found DMARC record value.",
            "example": null
          },
          "dmarc_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "DMARC verification error message.",
            "example": "No DMARC record found for example.com or its parent domain."
          },
          "spf_record": {
            "type": [
              "string",
              "null"
            ],
            "description": "Found SPF record value.",
            "example": null
          },
          "spf_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "SPF verification error message.",
            "example": null
          }
        }
      },
      "DmarcValidationResult": {
        "type": "object",
        "description": "DMARC validation result details.",
        "required": [
          "is_valid",
          "status",
          "found_at_domain",
          "record",
          "policy",
          "subdomain_policy",
          "error",
          "covered_by_parent_policy"
        ],
        "properties": {
          "is_valid": {
            "type": "boolean",
            "description": "Whether a valid DMARC record was found.",
            "example": false
          },
          "status": {
            "type": "string",
            "description": "DMARC validation status.",
            "enum": [
              "valid",
              "invalid",
              "missing",
              "unverified"
            ],
            "example": "missing"
          },
          "found_at_domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "Domain where the DMARC record was located (may be a parent domain for subdomains).",
            "example": null
          },
          "record": {
            "type": [
              "string",
              "null"
            ],
            "description": "Raw DMARC record value.",
            "example": null
          },
          "policy": {
            "type": [
              "string",
              "null"
            ],
            "description": "DMARC policy tag (`p=`).",
            "enum": [
              "none",
              "quarantine",
              "reject",
              null
            ],
            "example": null
          },
          "subdomain_policy": {
            "type": [
              "string",
              "null"
            ],
            "description": "DMARC subdomain policy tag (`sp=`), if present.",
            "enum": [
              "none",
              "quarantine",
              "reject",
              null
            ],
            "example": null
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Validation error message, if any.",
            "example": "No DMARC record found for example.com or its parent domain."
          },
          "covered_by_parent_policy": {
            "type": "boolean",
            "description": "Whether this domain is covered by the parent domain's subdomain policy.",
            "example": false
          }
        }
      },
      "SpfValidationResult": {
        "type": "object",
        "description": "SPF validation result details.",
        "required": [
          "is_valid",
          "status",
          "record",
          "error",
          "includes_sparkpost"
        ],
        "properties": {
          "is_valid": {
            "type": "boolean",
            "description": "Whether a valid SPF record was found that authorises SparkPost.",
            "example": false
          },
          "status": {
            "type": "string",
            "description": "SPF validation status.",
            "enum": [
              "valid",
              "invalid",
              "missing",
              "unverified"
            ],
            "example": "unverified"
          },
          "record": {
            "type": [
              "string",
              "null"
            ],
            "description": "Raw SPF record value.",
            "example": null
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Validation error message, if any.",
            "example": null
          },
          "includes_sparkpost": {
            "type": "boolean",
            "description": "Whether the SPF record authorises `_spf.sparkpostmail.com`.",
            "example": false
          }
        }
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "description": "Request body for updating a webhook. Only provided fields will be updated. At least one of `name`, `url`, `auth_type`, `events` or `active` is required. Credentials are saved only together with `auth_type`: `basic` requires `auth_username` and `auth_password`; `oauth2` requires `oauth_client_id`, `oauth_client_secret` and `oauth_token_url`.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the webhook",
            "maxLength": 24,
            "example": "Updated Webhook Name"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL where webhook events will be sent",
            "maxLength": 2048,
            "example": "https://example.com/webhook"
          },
          "target": {
            "type": "string",
            "format": "uri",
            "description": "Deprecated alias for `url`. Accepted for backwards compatibility.",
            "deprecated": true,
            "maxLength": 2048,
            "example": "https://example.com/webhook"
          },
          "auth_type": {
            "type": "string",
            "description": "Authentication type for the webhook",
            "enum": [
              "none",
              "basic",
              "oauth2"
            ],
            "example": "none"
          },
          "auth_username": {
            "type": "string",
            "description": "Username for basic authentication",
            "maxLength": 255
          },
          "auth_password": {
            "type": "string",
            "description": "Password for basic authentication",
            "maxLength": 255
          },
          "oauth_token_url": {
            "type": "string",
            "format": "uri",
            "description": "OAuth2 token URL",
            "maxLength": 2048
          },
          "oauth_client_id": {
            "type": "string",
            "description": "OAuth2 client ID",
            "maxLength": 255
          },
          "oauth_client_secret": {
            "type": "string",
            "description": "OAuth2 client secret",
            "maxLength": 255
          },
          "events": {
            "type": "array",
            "description": "Event types that trigger the webhook. Fully-prefixed names such as `message.delivery` are canonical; short names (`delivery`) and the legacy `engagament.*` prefix are accepted for backwards compatibility and are normalised to the fully-prefixed form.",
            "minItems": 1,
            "items": {
              "type": "string",
              "enum": [
                "message.injection",
                "message.delivery",
                "message.bounce",
                "message.delay",
                "message.out_of_band",
                "message.spam_complaint",
                "message.policy_rejection",
                "engagement.click",
                "engagement.open",
                "engagement.initial_open",
                "engagement.amp_click",
                "engagement.amp_open",
                "engagement.amp_initial_open",
                "generation.generation_failure",
                "generation.generation_rejection",
                "unsubscribe.list_unsubscribe",
                "unsubscribe.link_unsubscribe",
                "relay.relay_injection",
                "relay.relay_rejection",
                "relay.relay_delivery",
                "relay.relay_tempfail",
                "relay.relay_permfail"
              ]
            },
            "example": [
              "message.delivery",
              "message.bounce"
            ]
          },
          "active": {
            "type": "boolean",
            "description": "Whether the webhook is enabled",
            "example": true
          }
        }
      },
      "ListWebhooksResponse": {
        "type": "object",
        "description": "Response containing a list of webhooks",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Webhooks retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "webhooks"
            ],
            "properties": {
              "webhooks": {
                "type": "array",
                "description": "List of webhooks",
                "items": {
                  "$ref": "#/components/schemas/WebhookView"
                }
              }
            }
          }
        }
      },
      "ShowWebhookResponse": {
        "type": "object",
        "description": "Response containing a single webhook",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Webhook retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/WebhookView"
          }
        }
      },
      "StoreWebhookRequest": {
        "type": "object",
        "description": "Request body for creating a webhook",
        "required": [
          "name",
          "url",
          "auth_type",
          "events_mode"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the webhook",
            "maxLength": 24,
            "example": "Order Notifications"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL where webhook events will be sent",
            "maxLength": 2048,
            "example": "https://example.com/webhook"
          },
          "auth_type": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "oauth2"
            ],
            "description": "Authentication type for the webhook",
            "example": "basic"
          },
          "auth_username": {
            "type": "string",
            "description": "Username for basic authentication (required when auth_type is 'basic')",
            "maxLength": 255,
            "example": "user"
          },
          "auth_password": {
            "type": "string",
            "description": "Password for basic authentication (required when auth_type is 'basic')",
            "maxLength": 255,
            "example": "secret"
          },
          "oauth_client_id": {
            "type": "string",
            "description": "OAuth2 client ID (required when auth_type is 'oauth2')",
            "maxLength": 255
          },
          "oauth_client_secret": {
            "type": "string",
            "description": "OAuth2 client secret (required when auth_type is 'oauth2')",
            "maxLength": 255
          },
          "oauth_token_url": {
            "type": "string",
            "format": "uri",
            "description": "OAuth2 token URL (required when auth_type is 'oauth2')",
            "maxLength": 2048
          },
          "events_mode": {
            "type": "string",
            "enum": [
              "all",
              "selected"
            ],
            "description": "Whether to receive all events or only selected ones",
            "example": "selected"
          },
          "events": {
            "type": "array",
            "description": "List of event types to receive (required when events_mode is 'selected'). Fully-prefixed names such as `message.delivery` are canonical; short names (`delivery`) and the legacy `engagament.*` prefix are accepted for backwards compatibility and are normalised to the fully-prefixed form.",
            "items": {
              "type": "string",
              "enum": [
                "message.injection",
                "message.delivery",
                "message.bounce",
                "message.delay",
                "message.out_of_band",
                "message.spam_complaint",
                "message.policy_rejection",
                "engagement.click",
                "engagement.open",
                "engagement.initial_open",
                "engagement.amp_click",
                "engagement.amp_open",
                "engagement.amp_initial_open",
                "generation.generation_failure",
                "generation.generation_rejection",
                "unsubscribe.list_unsubscribe",
                "unsubscribe.link_unsubscribe",
                "relay.relay_injection",
                "relay.relay_rejection",
                "relay.relay_delivery",
                "relay.relay_tempfail",
                "relay.relay_permfail"
              ]
            },
            "example": [
              "message.delivery",
              "message.bounce"
            ]
          }
        }
      },
      "StoreWebhookResponse": {
        "type": "object",
        "description": "Response after creating a webhook",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Webhook created successfully."
          },
          "data": {
            "$ref": "#/components/schemas/WebhookView"
          }
        }
      },
      "ListFoldersResponse": {
        "type": "object",
        "description": "Response containing a paginated list of folders",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Folders retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "folders",
              "pagination"
            ],
            "properties": {
              "folders": {
                "type": "array",
                "description": "List of folders",
                "items": {
                  "$ref": "#/components/schemas/FolderView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/FoldersPagination"
              }
            }
          }
        }
      },
      "FolderView": {
        "type": "object",
        "description": "View of a folder templates are filed into",
        "required": [
          "id",
          "name",
          "project_id",
          "purpose",
          "templates_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique identifier for the folder. This is what `folder_id` on `POST /templates` expects.",
            "example": 10
          },
          "name": {
            "type": "string",
            "description": "Name of the folder",
            "example": "Campaigns"
          },
          "project_id": {
            "type": "integer",
            "description": "ID of the project containing this folder",
            "example": 5
          },
          "purpose": {
            "type": "string",
            "enum": [
              "transactional",
              "campaign"
            ],
            "description": "Module the folder belongs to. A template can only be filed into a folder of its own module.",
            "example": "campaign"
          },
          "templates_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of templates in this folder",
            "example": 12
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the folder was created",
            "example": "2025-01-15T10:00:00+00:00"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the folder was last updated",
            "example": "2025-01-20T14:30:00+00:00"
          }
        }
      },
      "FoldersPagination": {
        "type": "object",
        "description": "Pagination information for folders list",
        "required": [
          "total",
          "per_page",
          "current_page",
          "last_page"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total number of folders",
            "example": 2
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "description": "Number of folders per page",
            "example": 25
          },
          "current_page": {
            "type": "integer",
            "minimum": 1,
            "description": "Current page number",
            "example": 1
          },
          "last_page": {
            "type": "integer",
            "minimum": 1,
            "description": "Last page number",
            "example": 1
          }
        }
      },
      "ListTemplatesResponse": {
        "type": "object",
        "description": "Response containing a paginated list of templates",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Templates retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "templates",
              "pagination"
            ],
            "properties": {
              "templates": {
                "type": "array",
                "description": "List of templates",
                "items": {
                  "$ref": "#/components/schemas/TemplateView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/TemplatesPagination"
              }
            }
          }
        }
      },
      "TemplateView": {
        "type": "object",
        "description": "View of an email template",
        "required": [
          "id",
          "name",
          "slug",
          "project_id",
          "folder_id",
          "purpose",
          "preparation_status",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique identifier for the template",
            "example": 1
          },
          "name": {
            "type": "string",
            "description": "Name of the template",
            "example": "Welcome Email"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the template",
            "example": "welcome-email"
          },
          "project_id": {
            "type": "integer",
            "description": "ID of the project containing this template",
            "example": 5
          },
          "folder_id": {
            "type": "integer",
            "description": "ID of the folder containing this template",
            "example": 10
          },
          "purpose": {
            "type": "string",
            "enum": [
              "transactional",
              "campaign"
            ],
            "description": "Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick.",
            "example": "campaign"
          },
          "preparation_status": {
            "type": "string",
            "enum": [
              "pending",
              "ready",
              "failed"
            ],
            "description": "How far the template has got through preparation. Creating or updating a template through the API defers image migration and HTML rendering to a background job, so the template is `pending` until that finishes. On a create with JSON there is no HTML at all yet - the editor works (it reads the JSON) but sending and the screenshot do not. On an update the previous render stays in place, so the template remains sendable, but it is still serving the *old* content until this reads `ready`. `failed` means preparation exhausted its retries and will not become ready on its own. A template created from raw HTML is `ready` immediately.",
            "example": "ready"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was created",
            "example": "2025-01-15T10:00:00+00:00"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was last updated",
            "example": "2025-01-20T14:30:00+00:00"
          }
        }
      },
      "TemplatesPagination": {
        "type": "object",
        "description": "Pagination information for templates list",
        "required": [
          "total",
          "per_page",
          "current_page",
          "last_page"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total number of templates",
            "example": 42
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "description": "Number of templates per page",
            "example": 25
          },
          "current_page": {
            "type": "integer",
            "minimum": 1,
            "description": "Current page number",
            "example": 1
          },
          "last_page": {
            "type": "integer",
            "minimum": 1,
            "description": "Last page number",
            "example": 2
          }
        }
      },
      "ShowTemplateResponse": {
        "type": "object",
        "description": "Response containing a single template with details",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Template retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/TemplateDetailView"
          }
        }
      },
      "TemplateDetailView": {
        "type": "object",
        "description": "Detailed view of an email template",
        "required": [
          "id",
          "name",
          "slug",
          "project_id",
          "folder_id",
          "purpose",
          "preparation_status",
          "active_version",
          "versions_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique identifier for the template",
            "example": 1
          },
          "name": {
            "type": "string",
            "description": "Name of the template",
            "example": "Welcome Email"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the template",
            "example": "welcome-email"
          },
          "project_id": {
            "type": "integer",
            "description": "ID of the project containing this template",
            "example": 5
          },
          "folder_id": {
            "type": "integer",
            "description": "ID of the folder containing this template",
            "example": 10
          },
          "purpose": {
            "type": "string",
            "enum": [
              "transactional",
              "campaign"
            ],
            "description": "Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick.",
            "example": "campaign"
          },
          "preparation_status": {
            "type": "string",
            "enum": [
              "pending",
              "ready",
              "failed"
            ],
            "description": "How far the template has got through preparation. Creating or updating a template through the API defers image migration and HTML rendering to a background job, so the template is `pending` until that finishes. On a create with JSON there is no HTML at all yet - the editor works (it reads the JSON) but sending and the screenshot do not. On an update the previous render stays in place, so the template remains sendable, but it is still serving the *old* content until this reads `ready`. `failed` means preparation exhausted its retries and will not become ready on its own. A template created from raw HTML is `ready` immediately.",
            "example": "ready"
          },
          "active_version": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Version number of the currently active template version, or null if no version is active",
            "example": 2
          },
          "versions_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Total number of versions for this template",
            "example": 3
          },
          "html": {
            "type": [
              "string",
              "null"
            ],
            "description": "The HTML content of the active template version, or null if no active version exists",
            "example": "<html><body><h1>Welcome!</h1></body></html>"
          },
          "json": {
            "type": [
              "string",
              "null"
            ],
            "description": "The JSON definition of the active template version (for visual editor templates), or null if no active version exists or it's a custom HTML template",
            "example": "{\"tagName\":\"mj-body\",\"children\":[...]}"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was created",
            "example": "2025-01-15T10:00:00+00:00"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was last updated",
            "example": "2025-01-20T14:30:00+00:00"
          }
        }
      },
      "CreateTemplateRequest": {
        "type": "object",
        "description": "Request to create a new email template. Provide either `html` for custom HTML templates or `json` for Topol visual editor templates.",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Name of the template",
            "example": "Welcome Email"
          },
          "project_id": {
            "type": "integer",
            "minimum": 1,
            "description": "Project ID to create the template in. If not provided, uses the team's default project.",
            "example": 5
          },
          "folder_id": {
            "type": "integer",
            "minimum": 1,
            "description": "Folder ID to create the template in. Must belong to the same module as `purpose`. If not provided, the first folder of that module is used, and one is created when the project has none.",
            "example": 10
          },
          "html": {
            "type": "string",
            "description": "HTML content for custom HTML templates. Required if `json` is not provided. Mutually exclusive with `json`.",
            "example": "<html><body><p>Hello {{NAME}}!</p></body></html>"
          },
          "json": {
            "type": "string",
            "description": "JSON content for Topol visual editor templates. Required if `html` is not provided. Mutually exclusive with `html`.",
            "example": "{\"tagName\":\"mj-container\",\"children\":[{\"tagName\":\"mj-text\",\"content\":\"Hello {{FIRST_NAME}}!\"}]}"
          },
          "purpose": {
            "type": "string",
            "enum": ["transactional", "campaign"],
            "default": "transactional",
            "description": "Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick. Defaults to `transactional`.",
            "example": "campaign"
          }
        }
      },
      "CreateTemplateResponse": {
        "type": "object",
        "description": "Response after successfully creating a template",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Template created successfully."
          },
          "data": {
            "$ref": "#/components/schemas/CreatedTemplateView"
          }
        }
      },
      "DeleteTemplateResponse": {
        "type": "object",
        "description": "Response after successfully deleting a template",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Template deleted successfully."
          }
        }
      },
      "UpdateTemplateRequest": {
        "type": "object",
        "description": "Request to update an existing email template. All fields are optional - provide only what you want to change. If `html` or `json` is provided, a new active version will be created.\n\n`purpose` is **not** updatable and is not listed below. Sending it here is silently ignored: the request returns `200` with `Template updated successfully.` and the template keeps the purpose it was created with. To move a template to the other module, copy it — a transactional template cannot become a campaign one in place.",
        "properties": {
          "project_id": {
            "type": "integer",
            "minimum": 1,
            "description": "Project ID to find the template in. If not provided, uses the team's default project.",
            "example": 5
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "New name for the template",
            "example": "Updated Welcome Email"
          },
          "html": {
            "type": "string",
            "description": "New HTML content for the template. Creates a new active version. Mutually exclusive with `json`.",
            "example": "<html><body><p>Hello {{NAME}}!</p></body></html>"
          },
          "json": {
            "type": "string",
            "description": "New JSON content for Topol visual editor templates. Creates a new active version. Mutually exclusive with `html`.",
            "example": "{\"tagName\":\"mj-container\",\"children\":[{\"tagName\":\"mj-text\",\"content\":\"Hello {{FIRST_NAME}}!\"}]}"
          }
        }
      },
      "UpdateTemplateResponse": {
        "type": "object",
        "description": "Response after successfully updating a template",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Template updated successfully."
          },
          "data": {
            "$ref": "#/components/schemas/UpdatedTemplateView"
          }
        }
      },
      "UpdatedTemplateView": {
        "type": "object",
        "description": "View of an updated template",
        "required": [
          "id",
          "name",
          "slug",
          "project_id",
          "folder_id",
          "purpose",
          "preparation_status",
          "active_version",
          "merge_tags",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique identifier for the template",
            "example": 123
          },
          "name": {
            "type": "string",
            "description": "Name of the template",
            "example": "Updated Welcome Email"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the template",
            "example": "welcome-email"
          },
          "project_id": {
            "type": "integer",
            "description": "ID of the project containing this template",
            "example": 5
          },
          "folder_id": {
            "type": "integer",
            "description": "ID of the folder containing this template",
            "example": 10
          },
          "purpose": {
            "type": "string",
            "enum": [
              "transactional",
              "campaign"
            ],
            "description": "Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick.",
            "example": "campaign"
          },
          "preparation_status": {
            "type": "string",
            "enum": [
              "pending",
              "ready",
              "failed"
            ],
            "description": "How far the template has got through preparation. Creating or updating a template through the API defers image migration and HTML rendering to a background job, so the template is `pending` until that finishes. On a create with JSON there is no HTML at all yet - the editor works (it reads the JSON) but sending and the screenshot do not. On an update the previous render stays in place, so the template remains sendable, but it is still serving the *old* content until this reads `ready`. `failed` means preparation exhausted its retries and will not become ready on its own. A template created from raw HTML is `ready` immediately.",
            "example": "ready"
          },
          "active_version": {
            "type": "integer",
            "description": "Version number of the active template version",
            "example": 2
          },
          "merge_tags": {
            "type": "array",
            "description": "List of merge tags extracted from the template content",
            "items": {
              "$ref": "#/components/schemas/MergeTagView"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was created",
            "example": "2026-01-15T10:00:00+00:00"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was last updated",
            "example": "2026-01-28T14:30:00+00:00"
          }
        }
      },
      "CreatedTemplateView": {
        "type": "object",
        "description": "View of a newly created template",
        "required": [
          "id",
          "name",
          "slug",
          "project_id",
          "folder_id",
          "purpose",
          "preparation_status",
          "active_version",
          "merge_tags",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique identifier for the template",
            "example": 123
          },
          "name": {
            "type": "string",
            "description": "Name of the template",
            "example": "Welcome Email"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the template",
            "example": "welcome-email"
          },
          "project_id": {
            "type": "integer",
            "description": "ID of the project containing this template",
            "example": 5
          },
          "folder_id": {
            "type": "integer",
            "description": "ID of the folder containing this template",
            "example": 10
          },
          "purpose": {
            "type": "string",
            "enum": [
              "transactional",
              "campaign"
            ],
            "description": "Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick.",
            "example": "campaign"
          },
          "preparation_status": {
            "type": "string",
            "enum": [
              "pending",
              "ready",
              "failed"
            ],
            "description": "How far the template has got through preparation. Creating or updating a template through the API defers image migration and HTML rendering to a background job, so the template is `pending` until that finishes. On a create with JSON there is no HTML at all yet - the editor works (it reads the JSON) but sending and the screenshot do not. On an update the previous render stays in place, so the template remains sendable, but it is still serving the *old* content until this reads `ready`. `failed` means preparation exhausted its retries and will not become ready on its own. A template created from raw HTML is `ready` immediately.",
            "example": "ready"
          },
          "active_version": {
            "type": "integer",
            "description": "Version number of the active template version",
            "example": 1
          },
          "merge_tags": {
            "type": "array",
            "description": "List of merge tags extracted from the template content",
            "items": {
              "$ref": "#/components/schemas/MergeTagView"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the template was created",
            "example": "2026-01-28T12:00:00+00:00"
          }
        }
      },
      "GetMergeTagsResponse": {
        "type": "object",
        "description": "Response containing merge tags for a template version",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable response message",
            "example": "Merge tags retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/MergeTagsListView"
          }
        }
      },
      "MergeTagsListView": {
        "type": "object",
        "description": "Merge tags for a template version",
        "required": [
          "project_id",
          "template_slug",
          "version",
          "merge_tags"
        ],
        "properties": {
          "project_id": {
            "type": "integer",
            "description": "Numeric ID of the project the template belongs to.",
            "example": 13
          },
          "template_slug": {
            "type": "string",
            "description": "The template slug",
            "example": "welcome-email"
          },
          "version": {
            "type": "integer",
            "description": "The template version number",
            "example": 2
          },
          "merge_tags": {
            "type": "array",
            "description": "List of merge tags in this template version",
            "items": {
              "$ref": "#/components/schemas/MergeTagView"
            }
          }
        }
      },
      "MergeTagView": {
        "type": "object",
        "description": "A single merge tag. Loop merge tags (for iterating over arrays) include a 'children' property with nested field definitions.",
        "required": [
          "key",
          "required"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "The merge tag key/name used in templates",
            "example": "first_name"
          },
          "required": {
            "type": "boolean",
            "description": "Whether this merge tag is required when sending emails",
            "example": true
          },
          "type": {
            "type": "string",
            "description": "The data type of the merge tag (only present for loop children)",
            "enum": [
              "text",
              "number",
              "image",
              "button"
            ],
            "example": "text"
          },
          "children": {
            "type": "array",
            "description": "Child merge tags for loop blocks. Each child represents a field available within the loop iteration.",
            "items": {
              "$ref": "#/components/schemas/MergeTagChild"
            }
          }
        }
      },
      "MergeTagChild": {
        "type": "object",
        "description": "A child merge tag within a loop block",
        "required": [
          "key"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "The child merge tag key/name",
            "example": "item_name"
          },
          "type": {
            "type": "string",
            "description": "The data type of the child merge tag",
            "enum": [
              "text",
              "number",
              "image",
              "button"
            ],
            "example": "text"
          }
        }
      },
      "WebhookView": {
        "type": "object",
        "description": "View of a webhook",
        "required": [
          "id",
          "name",
          "url",
          "enabled",
          "auth_type",
          "has_auth_credentials"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the webhook",
            "example": "webhook-abc123"
          },
          "name": {
            "type": "string",
            "description": "Name of the webhook",
            "example": "Order Notifications"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL where webhook events will be sent",
            "example": "https://example.com/webhook"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the webhook is enabled",
            "example": true
          },
          "event_types": {
            "type": [
              "array",
              "null"
            ],
            "description": "Specific event types the webhook receives (null if all events)",
            "items": {
              "type": "string"
            },
            "example": [
              "message.delivery",
              "message.bounce"
            ]
          },
          "auth_type": {
            "type": "string",
            "description": "Authentication type for the webhook (none, basic, oauth2)",
            "example": "basic"
          },
          "has_auth_credentials": {
            "type": "boolean",
            "description": "Whether authentication credentials are configured",
            "example": true
          },
          "last_successful_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Timestamp of the last successful webhook delivery",
            "example": "2024-01-15T10:30:00+00:00"
          },
          "last_failure_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Timestamp of the last failed webhook delivery",
            "example": null
          },
          "last_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Status of the last delivery attempt (success or failure)",
            "enum": [
              "success",
              "failure",
              null
            ],
            "example": "success"
          }
        }
      },
      "ScheduleEmailRequest": {
        "type": "object",
        "description": "Schedule email request. Extends the standard send email request with a required `scheduled_at` field.",
        "allOf": [
          {
            "$ref": "#/components/schemas/SendEmailRequest"
          },
          {
            "type": "object",
            "required": [
              "scheduled_at"
            ],
            "properties": {
              "scheduled_at": {
                "type": "string",
                "format": "date-time",
                "description": "The UTC date/time when the email should be sent. Must be at least 5 minutes in the future and within 30 days.",
                "example": "2024-01-16T10:00:00Z"
              }
            }
          }
        ]
      },
      "ScheduledEmailResponse": {
        "type": "object",
        "description": "A scheduled email held by Lettr. This is the `data` object of `POST /emails/scheduled`, `GET /emails/scheduled/{transmissionId}` and `DELETE /emails/scheduled/{transmissionId}`, and each entry of `scheduled_emails` in `GET /emails/scheduled`.\n\n**Breaking change.** Scheduled emails are no longer parked inside SparkPost with `options.start_time` — SparkPost retired its per-transmission GET and DELETE endpoints. Lettr now holds the email in its own store and injects it into SparkPost when it is due, so `request_id` is Lettr's own `sch_...` id, `transmission_id` is a separate field that stays `null` until injection, and `state` values are Lettr's own rather than SparkPost's pass-through states.",
        "required": [
          "request_id",
          "transmission_id",
          "state",
          "scheduled_at",
          "from",
          "from_name",
          "subject",
          "recipients",
          "num_recipients",
          "accepted",
          "rejected",
          "tag",
          "failure_reason",
          "events"
        ],
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Lettr's identifier for the scheduled email, prefixed `sch_`. Pass this value to `GET` and `DELETE /emails/scheduled/{transmissionId}`. Before this change the field held SparkPost's transmission id.",
            "example": "sch_01JQZ3N2K8XW9V6M4TBRC7YHDE"
          },
          "transmission_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SparkPost's transmission id. `null` until the email is injected into SparkPost at its delivery time. This is the value that appears as `transmission_id` on your webhook events, so correlate webhooks on this field — not on `request_id`.",
            "example": "12345678901234567890"
          },
          "state": {
            "type": "string",
            "description": "Current state of the scheduled email. `scheduled` — waiting for its delivery time, the only state that can be cancelled. `sending` — claimed by the dispatcher and being injected right now. `sent` — injected into SparkPost; delivery detail then comes from `events`. `cancelled` — cancelled before injection, never handed to SparkPost. `failed` — injection was attempted and gave up, see `failure_reason`.",
            "enum": [
              "scheduled",
              "sending",
              "sent",
              "cancelled",
              "failed"
            ],
            "example": "scheduled"
          },
          "scheduled_at": {
            "type": "string",
            "format": "date-time",
            "description": "The delivery time in ISO 8601 format (UTC).",
            "example": "2024-01-16T10:00:00Z"
          },
          "from": {
            "type": "string",
            "format": "email",
            "description": "Sender email address.",
            "example": "sender@example.com"
          },
          "from_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sender display name.",
            "example": "Sender Name"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ],
            "description": "Email subject line.",
            "example": "Scheduled Newsletter"
          },
          "recipients": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "List of recipient email addresses.",
            "example": [
              "recipient@example.com"
            ]
          },
          "num_recipients": {
            "type": "integer",
            "minimum": 0,
            "description": "Total number of recipients.",
            "example": 1
          },
          "accepted": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of recipients accepted for delivery. Before injection this is what Lettr accepted; afterwards it is SparkPost's own count.",
            "example": 1
          },
          "rejected": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of recipients rejected. `0` before injection.",
            "example": 0
          },
          "tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tag supplied when the email was scheduled, used for tracking and analytics.",
            "example": "welcome-series-2024"
          },
          "failure_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why injection gave up. Only set when `state` is `failed`.",
            "example": null
          },
          "events": {
            "type": "array",
            "description": "Delivery events for this email. Empty until the email has been sent; populated with injection, delivery, bounce, open, click and other events once it has been injected into SparkPost.",
            "items": {
              "$ref": "#/components/schemas/EmailEvent"
            }
          }
        }
      },
      "ShowScheduledTransmissionResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Scheduled transmission retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "transmission_id",
              "state",
              "from",
              "subject",
              "recipients",
              "num_recipients",
              "events"
            ],
            "properties": {
              "transmission_id": {
                "type": "string",
                "description": "The unique transmission ID.",
                "example": "12345678901234567890"
              },
              "state": {
                "type": "string",
                "description": "Current state of the transmission. `submitted`/`generating` — still pending in SparkPost. `scheduled` — injected but not yet delivered (has `injection` event only). `delivered` — successfully delivered. `bounced` — rejected by recipient server. `failed` — generation or policy failure.",
                "enum": [
                  "submitted",
                  "generating",
                  "scheduled",
                  "delivered",
                  "bounced",
                  "failed",
                  "unknown"
                ],
                "example": "submitted"
              },
              "scheduled_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "The scheduled delivery time in ISO 8601 format. Present when the transmission is still pending. May be `null` when the transmission has already been delivered.",
                "example": "2024-01-16T10:00:00+00:00"
              },
              "from": {
                "type": "string",
                "format": "email",
                "description": "Sender email address.",
                "example": "sender@example.com"
              },
              "from_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Sender display name.",
                "example": "Sender Name"
              },
              "subject": {
                "type": "string",
                "description": "Email subject line.",
                "example": "Scheduled Newsletter"
              },
              "recipients": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "description": "List of recipient email addresses.",
                "example": [
                  "recipient@example.com"
                ]
              },
              "num_recipients": {
                "type": "integer",
                "description": "Total number of recipients.",
                "example": 1
              },
              "events": {
                "type": "array",
                "description": "Delivery events for this transmission. Empty array when the email is still scheduled. Populated with delivery, bounce, open, click, and other events once the email has been processed.",
                "items": {
                  "$ref": "#/components/schemas/EmailEvent"
                }
              }
            }
          }
        }
      },
      "GetEmailDetailResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "description": "Email detail response. Uses the same data shape as the scheduled transmission detail — see `ShowScheduledTransmissionResponse` for field descriptions.",
        "properties": {
          "message": {
            "type": "string",
            "example": "Email retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "transmission_id",
              "state",
              "from",
              "subject",
              "recipients",
              "num_recipients",
              "events"
            ],
            "properties": {
              "transmission_id": {
                "type": "string",
                "description": "The unique transmission ID (same as the `requestId` returned when the email was sent).",
                "example": "12345678901234567890"
              },
              "state": {
                "type": "string",
                "description": "Derived delivery state based on events. `scheduled` — injected but not yet delivered. `delivered` — successfully delivered. `bounced` — rejected by recipient server. `failed` — generation or policy failure.",
                "enum": [
                  "scheduled",
                  "delivered",
                  "bounced",
                  "failed"
                ],
                "example": "delivered"
              },
              "scheduled_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "The scheduled delivery time, if the email was scheduled. Usually `null` for immediately-sent emails.",
                "example": null
              },
              "from": {
                "type": "string",
                "format": "email",
                "description": "Sender email address.",
                "example": "sender@example.com"
              },
              "from_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Always null for a sent email: its delivery events do not record the sender display name. A scheduled email returns it from GET /emails/scheduled/{transmissionId} until it is sent.",
                "example": null
              },
              "subject": {
                "type": "string",
                "description": "Email subject line.",
                "example": "Welcome to Lettr"
              },
              "recipients": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "description": "Unique list of recipient email addresses derived from events.",
                "example": [
                  "recipient@example.com"
                ]
              },
              "num_recipients": {
                "type": "integer",
                "description": "Total number of unique recipients.",
                "example": 1
              },
              "events": {
                "type": "array",
                "description": "Delivery events for this email (injection, delivery, bounce, open, click, etc.).",
                "items": {
                  "$ref": "#/components/schemas/EmailEvent"
                }
              }
            }
          }
        }
      },
      "ListEmailEventsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Email events retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "events"
            ],
            "properties": {
              "events": {
                "type": "object",
                "required": [
                  "data",
                  "total_count",
                  "from",
                  "to",
                  "pagination"
                ],
                "properties": {
                  "data": {
                    "type": "array",
                    "description": "List of email events. Each event contains common fields plus type-specific fields (e.g. bounce events include bounce_class and reason, click events include target_link_url).",
                    "items": {
                      "$ref": "#/components/schemas/EmailEvent"
                    }
                  },
                  "total_count": {
                    "type": "integer",
                    "description": "Total number of events matching the query",
                    "example": 2
                  },
                  "from": {
                    "type": "string",
                    "description": "Start of the date range used for the query",
                    "example": "2024-01-05T00:00:00+00:00"
                  },
                  "to": {
                    "type": "string",
                    "description": "End of the date range used for the query",
                    "example": "2024-01-15T10:35:00+00:00"
                  },
                  "pagination": {
                    "type": "object",
                    "properties": {
                      "next_cursor": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "Cursor for the next page of results. Null if no more pages.",
                        "example": null
                      },
                      "per_page": {
                        "type": "integer",
                        "description": "Number of events per page",
                        "example": 25
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "EmailEvent": {
        "description": "An email event. The `type` field determines which additional fields are present. All event types share common fields defined in `CommonEventProperties`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/InjectionEvent"
          },
          {
            "$ref": "#/components/schemas/DeliveryEvent"
          },
          {
            "$ref": "#/components/schemas/BounceEvent"
          },
          {
            "$ref": "#/components/schemas/DelayEvent"
          },
          {
            "$ref": "#/components/schemas/OutOfBandEvent"
          },
          {
            "$ref": "#/components/schemas/SpamComplaintEvent"
          },
          {
            "$ref": "#/components/schemas/PolicyRejectionEvent"
          },
          {
            "$ref": "#/components/schemas/ClickEvent"
          },
          {
            "$ref": "#/components/schemas/OpenEvent"
          },
          {
            "$ref": "#/components/schemas/InitialOpenEvent"
          },
          {
            "$ref": "#/components/schemas/AmpClickEvent"
          },
          {
            "$ref": "#/components/schemas/AmpOpenEvent"
          },
          {
            "$ref": "#/components/schemas/AmpInitialOpenEvent"
          },
          {
            "$ref": "#/components/schemas/GenerationFailureEvent"
          },
          {
            "$ref": "#/components/schemas/GenerationRejectionEvent"
          },
          {
            "$ref": "#/components/schemas/ListUnsubscribeEvent"
          },
          {
            "$ref": "#/components/schemas/LinkUnsubscribeEvent"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "injection": "#/components/schemas/InjectionEvent",
            "delivery": "#/components/schemas/DeliveryEvent",
            "bounce": "#/components/schemas/BounceEvent",
            "delay": "#/components/schemas/DelayEvent",
            "out_of_band": "#/components/schemas/OutOfBandEvent",
            "spam_complaint": "#/components/schemas/SpamComplaintEvent",
            "policy_rejection": "#/components/schemas/PolicyRejectionEvent",
            "click": "#/components/schemas/ClickEvent",
            "open": "#/components/schemas/OpenEvent",
            "initial_open": "#/components/schemas/InitialOpenEvent",
            "amp_click": "#/components/schemas/AmpClickEvent",
            "amp_open": "#/components/schemas/AmpOpenEvent",
            "amp_initial_open": "#/components/schemas/AmpInitialOpenEvent",
            "generation_failure": "#/components/schemas/GenerationFailureEvent",
            "generation_rejection": "#/components/schemas/GenerationRejectionEvent",
            "list_unsubscribe": "#/components/schemas/ListUnsubscribeEvent",
            "link_unsubscribe": "#/components/schemas/LinkUnsubscribeEvent"
          }
        }
      },
      "CommonEventProperties": {
        "type": "object",
        "required": [
          "event_id",
          "type",
          "timestamp",
          "request_id",
          "rcpt_to",
          "raw_rcpt_to",
          "recipient_domain",
          "mailbox_provider",
          "mailbox_provider_region"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "description": "Unique identifier for the event",
            "example": "7609871845907017144"
          },
          "type": {
            "type": "string",
            "description": "The event type",
            "enum": [
              "injection",
              "delivery",
              "bounce",
              "delay",
              "out_of_band",
              "spam_complaint",
              "policy_rejection",
              "click",
              "open",
              "initial_open",
              "amp_click",
              "amp_open",
              "amp_initial_open",
              "generation_failure",
              "generation_rejection",
              "list_unsubscribe",
              "link_unsubscribe"
            ]
          },
          "timestamp": {
            "type": "string",
            "description": "When the event occurred (ISO 8601)",
            "example": "2024-01-15T10:31:00.000Z"
          },
          "request_id": {
            "type": "string",
            "description": "The transmission/request ID that generated this event",
            "example": "7610639000055488914"
          },
          "rcpt_to": {
            "type": "string",
            "format": "email",
            "description": "Recipient email address",
            "example": "recipient@example.com"
          },
          "raw_rcpt_to": {
            "type": "string",
            "format": "email",
            "description": "Original recipient email address before any modifications",
            "example": "recipient@example.com"
          },
          "recipient_domain": {
            "type": "string",
            "description": "Domain of the recipient",
            "example": "example.com"
          },
          "mailbox_provider": {
            "type": "string",
            "description": "Mailbox provider of the recipient",
            "example": "Gmail"
          },
          "mailbox_provider_region": {
            "type": "string",
            "description": "Region of the mailbox provider",
            "example": "Global"
          },
          "message_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SMTP message ID",
            "example": "699715cd9e6961853a97"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ],
            "description": "Email subject line",
            "example": "Welcome to Lettr"
          },
          "friendly_from": {
            "type": [
              "string",
              "null"
            ],
            "description": "Friendly from address",
            "example": "sender@example.com"
          },
          "sending_domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "The sending domain",
            "example": "example.com"
          },
          "sending_ip": {
            "type": [
              "string",
              "null"
            ],
            "description": "IP address used to send the email",
            "example": "168.203.51.91"
          },
          "click_tracking": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether click tracking was enabled"
          },
          "open_tracking": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether open tracking was enabled"
          },
          "transactional": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether this was a transactional message"
          },
          "msg_size": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Message size in bytes",
            "example": 30823
          },
          "injection_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the message was injected into the system (ISO 8601)",
            "example": "2024-01-15T10:30:00.000Z"
          },
          "rcpt_meta": {
            "type": [
              "array",
              "null"
            ],
            "description": "Recipient metadata"
          },
          "campaign_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Campaign identifier",
            "example": "welcome-series"
          },
          "template_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Template identifier",
            "example": "template_7610639000055488914"
          },
          "template_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Template version",
            "example": "0"
          },
          "ip_pool": {
            "type": [
              "string",
              "null"
            ],
            "description": "IP pool used for sending",
            "example": "default"
          },
          "msg_from": {
            "type": [
              "string",
              "null"
            ],
            "description": "Envelope sender (MAIL FROM)",
            "example": "msprvs1=abc123=bounces@sparkpostmail1.com"
          },
          "rcpt_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient type"
          },
          "rcpt_tags": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Recipient tags"
          },
          "amp_enabled": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether AMP was enabled"
          },
          "delv_method": {
            "type": [
              "string",
              "null"
            ],
            "description": "Delivery method (e.g. esmtp)",
            "example": "esmtp"
          },
          "recv_method": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reception method (e.g. rest)",
            "example": "rest"
          },
          "routing_domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "Routing domain",
            "example": "gmail.com"
          },
          "scheduled_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "Scheduled delivery time if the email was scheduled"
          },
          "ab_test_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "A/B test identifier"
          },
          "ab_test_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "A/B test version"
          }
        }
      },
      "UserAgentParsed": {
        "type": "object",
        "description": "Parsed user agent information from the open/click event.",
        "properties": {
          "agent_family": {
            "type": [
              "string",
              "null"
            ],
            "description": "Browser or email client family",
            "example": "Edge"
          },
          "device_brand": {
            "type": [
              "string",
              "null"
            ],
            "description": "Device brand (e.g. Apple, Samsung)"
          },
          "device_family": {
            "type": [
              "string",
              "null"
            ],
            "description": "Device family (e.g. iPhone, Desktop)"
          },
          "os_family": {
            "type": [
              "string",
              "null"
            ],
            "description": "Operating system family",
            "example": "Windows"
          },
          "os_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Operating system version",
            "example": "10"
          },
          "is_mobile": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the device is mobile"
          },
          "is_proxy": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the request came through a proxy"
          },
          "is_prefetched": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the open was prefetched by an email provider (e.g. Gmail Image Proxy, Apple Mail Privacy Protection). If true, this may not represent a real human open."
          }
        }
      },
      "GeoIp": {
        "type": "object",
        "description": "Geolocation data derived from the IP address of the open/click event.",
        "properties": {
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 3166-1 alpha-2 country code",
            "example": "CZ"
          },
          "region": {
            "type": [
              "string",
              "null"
            ],
            "description": "Region or state code",
            "example": "10"
          },
          "city": {
            "type": [
              "string",
              "null"
            ],
            "description": "City name",
            "example": "Prague"
          },
          "latitude": {
            "type": [
              "number",
              "null"
            ],
            "description": "Latitude",
            "example": 50.0883
          },
          "longitude": {
            "type": [
              "number",
              "null"
            ],
            "description": "Longitude",
            "example": 14.4124
          },
          "zip": {
            "type": [
              "string",
              "null"
            ],
            "description": "ZIP code",
            "example": "110"
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Postal code",
            "example": "110 00"
          }
        }
      },
      "InjectionEvent": {
        "description": "Fired when a message is received by the system and queued for delivery.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "injection"
                ]
              },
              "initial_pixel": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Whether initial open tracking pixel was included"
              }
            }
          }
        ]
      },
      "DeliveryEvent": {
        "description": "Fired when a message is successfully delivered to the recipient's mail server.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "delivery"
                ]
              },
              "queue_time": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Time spent in queue in milliseconds",
                "example": 1845
              },
              "outbound_tls": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Whether TLS was used for outbound delivery (\"1\" = yes)",
                "example": "1"
              }
            }
          }
        ]
      },
      "BounceEvent": {
        "description": "Fired when a message is permanently rejected by the recipient's mail server.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "bounce"
                ]
              },
              "bounce_class": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Bounce classification code (e.g. 10 = Invalid Recipient, 30 = Generic Bounce)",
                "example": 10
              },
              "error_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "SMTP error code",
                "example": "550"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Human-readable bounce reason",
                "example": "550 5.1.1 The email account that you tried to reach does not exist."
              },
              "raw_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw SMTP reason string",
                "example": "550 5.1.1 User unknown"
              },
              "num_retries": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Number of delivery retries attempted"
              },
              "device_token": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Device token if applicable"
              }
            }
          }
        ]
      },
      "DelayEvent": {
        "description": "Fired when a message delivery is temporarily delayed (will be retried).",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "delay"
                ]
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Human-readable delay reason"
              },
              "raw_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw SMTP reason string"
              },
              "error_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "SMTP error code",
                "example": "421"
              },
              "bounce_class": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Bounce classification code"
              },
              "num_retries": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Number of delivery retries attempted so far"
              },
              "queue_time": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Time spent in queue in milliseconds"
              },
              "outbound_tls": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Whether TLS was used for outbound delivery"
              }
            }
          }
        ]
      },
      "OutOfBandEvent": {
        "description": "Fired when a remote mail server sends an asynchronous bounce after initially accepting the message.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "out_of_band"
                ]
              },
              "bounce_class": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Bounce classification code"
              },
              "error_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "SMTP error code"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Human-readable bounce reason"
              },
              "raw_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw SMTP reason string"
              },
              "device_token": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Device token if applicable"
              }
            }
          }
        ]
      },
      "SpamComplaintEvent": {
        "description": "Fired when a recipient marks the message as spam via a feedback loop.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "spam_complaint"
                ]
              },
              "fbtype": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Feedback type (e.g. \"abuse\")",
                "example": "abuse"
              },
              "report_by": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Who reported the spam"
              },
              "report_to": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Where the spam report was sent"
              }
            }
          }
        ]
      },
      "PolicyRejectionEvent": {
        "description": "Fired when a message is rejected due to policy (e.g. suppression list, rate limiting).",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "policy_rejection"
                ]
              },
              "remote_addr": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Remote IP address"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Human-readable rejection reason"
              },
              "raw_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw rejection reason"
              },
              "error_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Error code"
              },
              "bounce_class": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Bounce classification code"
              }
            }
          }
        ]
      },
      "ClickEvent": {
        "description": "Fired when a recipient clicks a tracked link in the email.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "click"
                ]
              },
              "target_link_url": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The URL that was clicked",
                "example": "https://example.com/reset-password?token=abc123"
              },
              "target_link_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name/label of the clicked link"
              },
              "user_agent": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw user agent string",
                "example": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
              },
              "user_agent_parsed": {
                "$ref": "#/components/schemas/UserAgentParsed"
              },
              "geo_ip": {
                "$ref": "#/components/schemas/GeoIp"
              },
              "ip_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "IP address of the click",
                "example": "104.28.114.11"
              }
            }
          }
        ]
      },
      "OpenEvent": {
        "description": "Fired when a recipient opens the email (subsequent opens after the initial open).",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "open"
                ]
              },
              "user_agent": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw user agent string",
                "example": "Mozilla/5.0"
              },
              "user_agent_parsed": {
                "$ref": "#/components/schemas/UserAgentParsed"
              },
              "geo_ip": {
                "$ref": "#/components/schemas/GeoIp"
              },
              "ip_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "IP address of the open",
                "example": "104.28.114.11"
              },
              "initial_pixel": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Whether this was triggered by the initial tracking pixel"
              }
            }
          }
        ]
      },
      "InitialOpenEvent": {
        "description": "Fired the first time a recipient opens the email.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "initial_open"
                ]
              },
              "user_agent": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw user agent string",
                "example": "Mozilla/5.0"
              },
              "user_agent_parsed": {
                "$ref": "#/components/schemas/UserAgentParsed"
              },
              "geo_ip": {
                "$ref": "#/components/schemas/GeoIp"
              },
              "ip_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "IP address of the open",
                "example": "104.28.114.11"
              },
              "initial_pixel": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Whether this was triggered by the initial tracking pixel"
              }
            }
          }
        ]
      },
      "AmpClickEvent": {
        "description": "Fired when a recipient clicks a tracked link in an AMP email.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "amp_click"
                ]
              },
              "target_link_url": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The URL that was clicked"
              },
              "target_link_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name/label of the clicked link"
              },
              "user_agent": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw user agent string"
              },
              "user_agent_parsed": {
                "$ref": "#/components/schemas/UserAgentParsed"
              },
              "geo_ip": {
                "$ref": "#/components/schemas/GeoIp"
              },
              "ip_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "IP address of the click"
              }
            }
          }
        ]
      },
      "AmpOpenEvent": {
        "description": "Fired when a recipient opens an AMP email (subsequent opens).",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "amp_open"
                ]
              },
              "user_agent": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw user agent string"
              },
              "user_agent_parsed": {
                "$ref": "#/components/schemas/UserAgentParsed"
              },
              "geo_ip": {
                "$ref": "#/components/schemas/GeoIp"
              },
              "ip_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "IP address of the open"
              },
              "initial_pixel": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Whether this was triggered by the initial tracking pixel"
              }
            }
          }
        ]
      },
      "AmpInitialOpenEvent": {
        "description": "Fired the first time a recipient opens an AMP email.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "amp_initial_open"
                ]
              },
              "user_agent": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw user agent string"
              },
              "user_agent_parsed": {
                "$ref": "#/components/schemas/UserAgentParsed"
              },
              "geo_ip": {
                "$ref": "#/components/schemas/GeoIp"
              },
              "ip_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "IP address of the open"
              },
              "initial_pixel": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Whether this was triggered by the initial tracking pixel"
              }
            }
          }
        ]
      },
      "GenerationFailureEvent": {
        "description": "Fired when the system fails to generate a message (e.g. template rendering error).",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "generation_failure"
                ]
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Human-readable failure reason"
              },
              "raw_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw failure reason"
              },
              "error_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Error code"
              }
            }
          }
        ]
      },
      "GenerationRejectionEvent": {
        "description": "Fired when the system rejects message generation (e.g. policy violation).",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "generation_rejection"
                ]
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Human-readable rejection reason"
              },
              "raw_reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Raw rejection reason"
              },
              "error_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Error code"
              }
            }
          }
        ]
      },
      "ListUnsubscribeEvent": {
        "description": "Fired when a recipient uses the List-Unsubscribe header to unsubscribe.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "list_unsubscribe"
                ]
              }
            }
          }
        ]
      },
      "LinkUnsubscribeEvent": {
        "description": "Fired when a recipient clicks an unsubscribe link in the email body.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonEventProperties"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "link_unsubscribe"
                ]
              }
            }
          }
        ]
      },
      "ListEmailsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "events"
            ],
            "properties": {
              "events": {
                "type": "object",
                "required": [
                  "data",
                  "total_count",
                  "from",
                  "to",
                  "pagination"
                ],
                "properties": {
                  "data": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/SentEmailListItem"
                    }
                  },
                  "total_count": {
                    "type": "integer",
                    "description": "Total number of matching emails"
                  },
                  "from": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Start of the query date range"
                  },
                  "to": {
                    "type": "string",
                    "format": "date-time",
                    "description": "End of the query date range"
                  },
                  "pagination": {
                    "type": "object",
                    "properties": {
                      "next_cursor": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "Cursor for the next page, or null if no more results"
                      },
                      "per_page": {
                        "type": "integer"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SentEmailListItem": {
        "type": "object",
        "required": [
          "event_id",
          "type",
          "timestamp"
        ],
        "properties": {
          "event_id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "SparkPost event type (e.g., injection)"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "message_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "friendly_from": {
            "type": [
              "string",
              "null"
            ]
          },
          "sending_domain": {
            "type": [
              "string",
              "null"
            ]
          },
          "rcpt_to": {
            "type": [
              "string",
              "null"
            ]
          },
          "raw_rcpt_to": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipient_domain": {
            "type": [
              "string",
              "null"
            ]
          },
          "mailbox_provider": {
            "type": [
              "string",
              "null"
            ]
          },
          "mailbox_provider_region": {
            "type": [
              "string",
              "null"
            ]
          },
          "sending_ip": {
            "type": [
              "string",
              "null"
            ]
          },
          "click_tracking": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "open_tracking": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "transactional": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "msg_size": {
            "type": [
              "integer",
              "null"
            ]
          },
          "injection_time": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "rcpt_meta": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          }
        }
      },
      "GetTemplateHtmlResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "data": {
            "type": "object",
            "required": [
              "html",
              "merge_tags"
            ],
            "properties": {
              "html": {
                "type": "string",
                "description": "The template HTML content"
              },
              "merge_tags": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "key",
                    "name",
                    "required"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "required": {
                      "type": "boolean"
                    }
                  }
                }
              },
              "subject": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The template subject line, if set"
              }
            }
          }
        }
      },
      "ListProjectsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "projects",
              "pagination"
            ],
            "properties": {
              "projects": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ProjectView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/ProjectsPagination"
              }
            }
          }
        }
      },
      "ProjectView": {
        "type": "object",
        "required": [
          "id",
          "name",
          "team_id",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "emoji": {
            "type": [
              "string",
              "null"
            ]
          },
          "team_id": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProjectsPagination": {
        "type": "object",
        "required": [
          "total",
          "per_page",
          "current_page",
          "last_page"
        ],
        "properties": {
          "total": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "current_page": {
            "type": "integer"
          },
          "last_page": {
            "type": "integer"
          }
        }
      },
      "AudiencePagination": {
        "type": "object",
        "description": "Pagination info for audience list responses",
        "required": [
          "total",
          "per_page",
          "current_page",
          "last_page"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total items",
            "example": 42
          },
          "per_page": {
            "type": "integer",
            "description": "Items per page",
            "example": 20
          },
          "current_page": {
            "type": "integer",
            "description": "Current page (1-indexed)",
            "example": 1
          },
          "last_page": {
            "type": "integer",
            "description": "Last available page (= ceil(total / per_page), minimum 1)",
            "example": 3
          }
        }
      },
      "AudienceListView": {
        "type": "object",
        "description": "Audience list summary",
        "required": [
          "id",
          "name",
          "contacts_count"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "List ID",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          },
          "name": {
            "type": "string",
            "description": "List name",
            "example": "Newsletter subscribers"
          },
          "contacts_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of contacts in the list",
            "example": 124
          }
        }
      },
      "ListAudienceListsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Lists retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "lists",
              "pagination"
            ],
            "properties": {
              "lists": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AudienceListView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/AudiencePagination"
              }
            }
          }
        }
      },
      "ShowAudienceListResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "List retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/AudienceListView"
          }
        }
      },
      "StoreAudienceListRequest": {
        "type": "object",
        "description": "Request to create an audience list",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "List name (must be unique within the team)",
            "example": "Newsletter subscribers"
          }
        }
      },
      "UpdateAudienceListRequest": {
        "type": "object",
        "description": "Request to update an audience list. All fields are optional.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "New list name (must remain unique within the team)",
            "example": "Newsletter subscribers (renamed)"
          }
        }
      },
      "BulkDestroyAudienceListsRequest": {
        "type": "object",
        "description": "Bulk delete audience lists",
        "required": [
          "list_ids"
        ],
        "properties": {
          "list_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "1–50 list IDs (all must belong to the authenticated team)",
            "example": [
              "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0",
              "0193e6a8-2a4b-7d1c-a3f5-2bb2e3f6e4a1"
            ]
          }
        }
      },
      "BulkDestroyAudienceListsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Lists deleted successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "deleted"
            ],
            "properties": {
              "deleted": {
                "type": "integer",
                "minimum": 0,
                "description": "Number of lists actually deleted",
                "example": 2
              }
            }
          }
        }
      },
      "AudienceContactStatus": {
        "type": "string",
        "enum": [
          "subscribed",
          "unsubscribed",
          "bounced",
          "complained",
          "unverified"
        ],
        "description": "Contact subscription status",
        "example": "subscribed"
      },
      "AudienceContactListLink": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "AudienceContactTopicLink": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "AudienceContactView": {
        "type": "object",
        "description": "Audience contact",
        "required": [
          "id",
          "email",
          "status",
          "properties",
          "created_at",
          "paused_until",
          "lists",
          "topics"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "0193e6b0-9c1d-7d4f-a8f1-cef9a1b2d3e4"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "jane@example.com"
          },
          "status": {
            "$ref": "#/components/schemas/AudienceContactStatus"
          },
          "properties": {
            "type": "object",
            "description": "Custom properties for the contact (string values)",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "first_name": "Jane",
              "country": "US"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "example": "2024-01-15T10:30:00Z"
          },
          "paused_until": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "End of the contact's send pause, set from the unsubscribe page. While this is in the future the contact keeps status subscribed but campaigns are not delivered to them.",
            "example": null
          },
          "lists": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudienceContactListLink"
            }
          },
          "topics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudienceContactTopicLink"
            }
          }
        }
      },
      "ListAudienceContactsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contacts retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "contacts",
              "pagination"
            ],
            "properties": {
              "contacts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AudienceContactView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/AudiencePagination"
              }
            }
          }
        }
      },
      "ShowAudienceContactResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contact retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/AudienceContactView"
          }
        }
      },
      "DoubleOptInConfig": {
        "type": "object",
        "description": "Double opt-in configuration. When provided, the contact receives a confirmation email and is created in `unverified` status until they click the confirmation link.",
        "required": [
          "from",
          "subject",
          "template_slug",
          "redirect_url"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "example": "no-reply@example.com"
          },
          "from_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "example": "Example Newsletter"
          },
          "subject": {
            "type": "string",
            "maxLength": 998,
            "example": "Please confirm your subscription"
          },
          "template_slug": {
            "type": "string",
            "maxLength": 255,
            "example": "double-opt-in"
          },
          "redirect_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "example": "https://example.com/confirmed"
          }
        }
      },
      "StoreAudienceContactRequest": {
        "type": "object",
        "description": "Request to create a single contact",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "example": "jane@example.com"
          },
          "list_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Optional list to add the contact to. Must be a list of your team, otherwise the response is `422` with `errors.list_id`."
          },
          "properties": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string",
              "maxLength": 1000
            },
            "description": "Custom property values. Each key must match a property defined for the team.",
            "example": {
              "first_name": "Jane"
            }
          },
          "double_opt_in": {
            "$ref": "#/components/schemas/DoubleOptInConfig"
          }
        }
      },
      "BulkStoreAudienceContactsRequest": {
        "type": "object",
        "description": "Bulk create contacts, up to 1000 per request. Send either `emails` (one shared property map for the whole batch) or `contacts` (a row per contact, each with its own properties, lists and topics) — not both. Emails are normalized (lowercased, trimmed) and deduplicated, with the last row for an address winning. Batch-wide `list_ids` and `topics` are unioned into every row.",
        "properties": {
          "emails": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "items": {
              "type": "string",
              "format": "email",
              "maxLength": 255
            },
            "example": [
              "jane@example.com",
              "joe@example.com"
            ],
            "description": "Legacy shape: a flat list of addresses that all share `properties` and `list_id`."
          },
          "list_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Optional list to add all contacts to. Kept for backwards compatibility; folded into `list_ids`."
          },
          "properties": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string",
              "maxLength": 1000
            },
            "description": "Custom property values applied to every contact in the batch. Works with both shapes; with `contacts`, a key set on a row overrides the batch value for that key."
          },
          "contacts": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "description": "One row per contact. A row that fails validation is skipped and reported in the response `errors` array — the rest of the batch is still written.",
            "items": {
              "$ref": "#/components/schemas/BulkAudienceContactRow"
            }
          },
          "list_ids": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 50,
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lists every contact in the batch is added to."
          },
          "topics": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/AudienceTopicSubscription"
            },
            "description": "Topic subscriptions applied to every contact in the batch. A row-level `opt_out` wins over a batch-level `opt_in` for that contact."
          },
          "update_existing": {
            "type": "boolean",
            "default": false,
            "description": "When true, contacts that already exist have their properties merged \u2014 submitted keys overwrite, others are preserved. When false their properties are left alone and they are counted in `already_existed`. This flag governs property merges only: lists, topic opt-ins and topic `opt_out` entries are always applied, so a row-level `opt_out` drops an existing subscription whether or not the flag is set."
          }
        },
        "anyOf": [
          {
            "required": [
              "emails"
            ]
          },
          {
            "required": [
              "contacts"
            ]
          }
        ]
      },
      "BulkStoreAudienceContactsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contacts created successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "created",
              "updated",
              "already_existed",
              "error_count",
              "errors",
              "contacts"
            ],
            "properties": {
              "created": {
                "type": "integer",
                "minimum": 0,
                "example": 2
              },
              "already_existed": {
                "type": "integer",
                "minimum": 0,
                "example": 0,
                "description": "Submitted addresses that were already in the audience."
              },
              "updated": {
                "type": "integer",
                "minimum": 0,
                "description": "Existing contacts the request changed — properties merged, a list or topic attached, or a subscription dropped.",
                "example": 0
              },
              "error_count": {
                "type": "integer",
                "minimum": 0,
                "example": 0
              },
              "errors": {
                "type": "array",
                "description": "Rows that were skipped. Empty when the whole batch was accepted.",
                "items": {
                  "$ref": "#/components/schemas/BulkAudienceContactError"
                }
              },
              "contacts": {
                "type": "array",
                "description": "Every contact in the batch that exists after the request, in submission order.",
                "items": {
                  "$ref": "#/components/schemas/BulkAudienceContactRef"
                }
              }
            }
          }
        }
      },
      "UpdateAudienceContactRequest": {
        "type": "object",
        "description": "Request to update a contact. All fields are optional.",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "description": "New email address (must remain unique within the team)"
          },
          "status": {
            "type": "string",
            "enum": [
              "subscribed",
              "unsubscribed"
            ]
          },
          "properties": {
            "type": "object",
            "additionalProperties": {
              "type": [
                "string",
                "null"
              ],
              "maxLength": 1000
            },
            "description": "Partial property update. A property set to null is removed."
          }
        }
      },
      "BulkAudienceContactListsRequest": {
        "type": "object",
        "description": "Bulk attach/detach contacts to/from lists. All combinations of contact_ids × list_ids are processed.",
        "required": [
          "contact_ids",
          "list_ids"
        ],
        "properties": {
          "contact_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "list_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "type": "string",
              "format": "uuid"
            }
          }
        }
      },
      "BulkAttachContactsToListsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contacts attached to lists."
          },
          "data": {
            "type": "object",
            "required": [
              "attached",
              "already_attached",
              "total_pairs"
            ],
            "properties": {
              "attached": {
                "type": "integer",
                "minimum": 0,
                "description": "Newly attached pairs"
              },
              "already_attached": {
                "type": "integer",
                "minimum": 0,
                "description": "Pairs that already existed"
              },
              "total_pairs": {
                "type": "integer",
                "minimum": 0,
                "description": "Total contact × list pairs processed"
              }
            }
          }
        }
      },
      "BulkDetachContactsFromListsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contacts detached from lists."
          },
          "data": {
            "type": "object",
            "required": [
              "detached",
              "not_present",
              "total_pairs"
            ],
            "properties": {
              "detached": {
                "type": "integer",
                "minimum": 0,
                "description": "Newly detached pairs"
              },
              "not_present": {
                "type": "integer",
                "minimum": 0,
                "description": "Pairs that were not attached"
              },
              "total_pairs": {
                "type": "integer",
                "minimum": 0
              }
            }
          }
        }
      },
      "AttachContactToListResponse": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contact attached to list."
          }
        }
      },
      "AttachContactToTopicResponse": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contact subscribed to topic."
          }
        }
      },
      "AudienceTopicVisibility": {
        "type": "string",
        "enum": [
          "private",
          "public"
        ],
        "description": "Whether the topic is visible to public subscription pages",
        "example": "public"
      },
      "AudienceTopicDefaultSubscription": {
        "type": "string",
        "enum": [
          "opt_in",
          "opt_out"
        ],
        "description": "Default subscription state for newly-created contacts. `opt_in` means the contact must subscribe themselves (not auto-attached). `opt_out` means the contact is subscribed by default and must opt out to leave (auto-attached on creation).",
        "example": "opt_in"
      },
      "AudienceTopicView": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "default_subscription",
          "visibility",
          "contacts_count",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "example": "Product updates"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "example": "Monthly product updates"
          },
          "default_subscription": {
            "$ref": "#/components/schemas/AudienceTopicDefaultSubscription"
          },
          "visibility": {
            "$ref": "#/components/schemas/AudienceTopicVisibility"
          },
          "contacts_count": {
            "type": "integer",
            "description": "Number of subscribed contacts on the topic. Contacts that are unsubscribed, bounced or unverified are not counted.",
            "minimum": 0,
            "example": 12
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ListAudienceTopicsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Topics retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "topics",
              "pagination"
            ],
            "properties": {
              "topics": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AudienceTopicView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/AudiencePagination"
              }
            }
          }
        }
      },
      "ShowAudienceTopicResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Topic retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/AudienceTopicView"
          }
        }
      },
      "StoreAudienceTopicRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "example": "Product updates"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000
          },
          "default_subscription": {
            "$ref": "#/components/schemas/AudienceTopicDefaultSubscription",
            "default": "opt_in",
            "description": "Defaults to `opt_in` when omitted."
          },
          "visibility": {
            "$ref": "#/components/schemas/AudienceTopicVisibility",
            "default": "private",
            "description": "Defaults to `private` when omitted."
          }
        }
      },
      "UpdateAudienceTopicRequest": {
        "type": "object",
        "description": "Update a topic. All fields are optional. The `default_subscription` field is immutable.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000
          },
          "visibility": {
            "$ref": "#/components/schemas/AudienceTopicVisibility"
          }
        }
      },
      "AudiencePropertyType": {
        "type": "string",
        "enum": [
          "string",
          "number",
          "boolean",
          "date",
          "json"
        ],
        "description": "Data type of the property",
        "example": "string"
      },
      "AudiencePropertyView": {
        "type": "object",
        "required": [
          "id",
          "name",
          "type",
          "fallback_value",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "example": "first_name"
          },
          "type": {
            "$ref": "#/components/schemas/AudiencePropertyType"
          },
          "fallback_value": {
            "type": [
              "string",
              "null"
            ],
            "example": "Friend"
          },
          "purpose": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "communication_language",
              null
            ],
            "description": "Role the property is designated for. `communication_language` marks the property campaigns read the recipient language from; only one property per team can hold it."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ListAudiencePropertiesResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Properties retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "properties",
              "pagination"
            ],
            "properties": {
              "properties": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AudiencePropertyView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/AudiencePagination"
              }
            }
          }
        }
      },
      "ShowAudiencePropertyResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Property retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/AudiencePropertyView"
          }
        }
      },
      "StoreAudiencePropertyRequest": {
        "type": "object",
        "required": [
          "name",
          "type"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "Property name. Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores.",
            "example": "first_name"
          },
          "type": {
            "$ref": "#/components/schemas/AudiencePropertyType"
          },
          "fallback_value": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "example": "Friend"
          },
          "purpose": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "communication_language",
              null
            ],
            "description": "Designate this property as the team's communication language. Assigning it takes the role away from whichever property held it before."
          }
        }
      },
      "UpdateAudiencePropertyRequest": {
        "type": "object",
        "description": "Update a property's fallback value. The `name` and `type` fields are immutable (changing them would orphan data on existing contacts) and must not be provided.",
        "properties": {
          "fallback_value": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "example": "Friend"
          }
        }
      },
      "SegmentOperator": {
        "type": "string",
        "enum": [
          "contains",
          "not_contains",
          "equals",
          "not_equals",
          "starts_with",
          "not_starts_with",
          "ends_with",
          "not_ends_with",
          "is_true",
          "is_false",
          "is_empty",
          "is_not_empty",
          "greater_than",
          "greater_than_or_equal",
          "less_than",
          "less_than_or_equal",
          "before",
          "after"
        ],
        "description": "Segment condition operator",
        "example": "equals"
      },
      "SegmentCondition": {
        "type": "object",
        "required": [
          "field",
          "operator"
        ],
        "properties": {
          "field": {
            "type": "string",
            "maxLength": 255,
            "description": "Field to match: `email`, `status`, `created_at`, `properties.<name>` for a custom property, or `topics` / `lists` (by name, `equals` and `not_equals` only). Any other field or operator combination is rejected with `422`.",
            "example": "email"
          },
          "operator": {
            "$ref": "#/components/schemas/SegmentOperator"
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000,
            "description": "Value to compare against. Required for all operators except `is_true` and `is_false`, which evaluate the field's truthiness and accept no value (may be omitted or `null`).",
            "example": "@example.com"
          }
        }
      },
      "SegmentConditionGroup": {
        "type": "object",
        "description": "Group of conditions joined by OR. Multiple groups in a segment are joined by AND.",
        "required": [
          "conditions"
        ],
        "properties": {
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/SegmentCondition"
            }
          }
        }
      },
      "SegmentConditionsInput": {
        "type": "object",
        "required": [
          "groups"
        ],
        "properties": {
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentConditionGroup"
            }
          }
        }
      },
      "AudienceSegmentView": {
        "type": "object",
        "required": [
          "id",
          "name",
          "list_id",
          "list_name",
          "condition_groups",
          "cached_contacts_count",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "example": "Engaged subscribers"
          },
          "list_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Restrict segment to a single list (null = all lists)"
          },
          "list_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "condition_groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentConditionGroup"
            }
          },
          "cached_contacts_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Last computed contacts count (may be stale)"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ListAudienceSegmentsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Segments retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "segments",
              "pagination"
            ],
            "properties": {
              "segments": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AudienceSegmentView"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/AudiencePagination"
              }
            }
          }
        }
      },
      "ShowAudienceSegmentResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Segment retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/AudienceSegmentView"
          }
        }
      },
      "StoreAudienceSegmentRequest": {
        "type": "object",
        "required": [
          "name",
          "conditions"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "example": "Engaged subscribers"
          },
          "list_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Restrict segment to a single list. Must belong to the authenticated team."
          },
          "conditions": {
            "$ref": "#/components/schemas/SegmentConditionsInput"
          }
        }
      },
      "UpdateAudienceSegmentRequest": {
        "type": "object",
        "description": "Update a segment. All fields are optional.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "list_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "conditions": {
            "$ref": "#/components/schemas/SegmentConditionsInput"
          }
        }
      },
      "CampaignStats": {
        "type": "object",
        "description": "Aggregated engagement statistics for a campaign.",
        "required": [
          "injections",
          "deliveries",
          "bounces",
          "spam_complaints",
          "opens",
          "unique_opens",
          "clicks",
          "unique_clicks",
          "unsubscribes"
        ],
        "properties": {
          "injections": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "deliveries": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "bounces": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "spam_complaints": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "opens": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "unique_opens": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "clicks": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "unique_clicks": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          },
          "unsubscribes": {
            "type": "integer",
            "minimum": 0,
            "example": 0
          }
        }
      },
      "CampaignSummary": {
        "type": "object",
        "description": "Campaign summary with embedded engagement stats.",
        "required": [
          "id",
          "name",
          "status",
          "sent_count",
          "created_at",
          "stats"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0"
          },
          "name": {
            "type": "string",
            "example": "Spring Sale"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ],
            "description": "Email subject line"
          },
          "from_email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sender email address",
            "format": "email"
          },
          "from_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sender display name"
          },
          "reply_to": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reply-to address",
            "format": "email"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "scheduled",
              "preparing",
              "in_review",
              "sending",
              "sent",
              "failed"
            ],
            "example": "sent"
          },
          "scheduled_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Scheduled delivery time (ISO 8601)",
            "format": "date-time"
          },
          "total_recipients": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Total recipients resolved for the send"
          },
          "sent_count": {
            "type": "integer",
            "minimum": 0,
            "example": 124
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the campaign finished sending (ISO 8601)",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-05-01T09:00:00+00:00"
          },
          "stats": {
            "$ref": "#/components/schemas/CampaignStats"
          }
        }
      },
      "CampaignDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CampaignSummary"
          },
          {
            "type": "object",
            "properties": {
              "html_content": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Rendered HTML content of the campaign email"
              },
              "language_overrides": {
                "type": "object",
                "description": "Per-language subject and sender overrides for a multi-language template, keyed by the template's language key. Absent fields fall back to the campaign's primary values.",
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "subject": { "type": ["string", "null"] },
                    "from_email": { "type": ["string", "null"], "format": "email" },
                    "from_name": { "type": ["string", "null"] },
                    "reply_to": { "type": ["string", "null"], "format": "email" }
                  }
                }
              }
            }
          }
        ],
        "description": "Full campaign representation including rendered HTML content."
      },
      "CampaignEvent": {
        "type": "object",
        "description": "A single campaign engagement event.",
        "required": [
          "event_id",
          "event_type",
          "email",
          "timestamp"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "example": "92356829"
          },
          "event_type": {
            "type": "string",
            "enum": [
              "injection",
              "delivery",
              "bounce",
              "spam_complaint",
              "open",
              "click",
              "list_unsubscribe"
            ],
            "example": "open"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "jane@example.com"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "example": "2026-05-01T12:30:00+00:00"
          },
          "bounce_class": {
            "type": [
              "string",
              "null"
            ],
            "description": "SparkPost bounce classification code"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Failure or bounce reason"
          },
          "target_link_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Clicked link URL (click events only)"
          },
          "user_agent": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient user agent (open/click events)"
          }
        }
      },
      "CampaignPagination": {
        "type": "object",
        "description": "Pagination info for campaign list responses",
        "required": [
          "total",
          "per_page",
          "current_page",
          "last_page"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "example": 42
          },
          "per_page": {
            "type": "integer",
            "example": 20
          },
          "current_page": {
            "type": "integer",
            "example": 1
          },
          "last_page": {
            "type": "integer",
            "example": 3
          }
        }
      },
      "ListCampaignsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Campaigns retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "campaigns",
              "pagination"
            ],
            "properties": {
              "campaigns": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CampaignSummary"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/CampaignPagination"
              }
            }
          }
        }
      },
      "ShowCampaignResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Campaign retrieved successfully."
          },
          "data": {
            "$ref": "#/components/schemas/CampaignDetail"
          }
        }
      },
      "ListCampaignEventsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Campaign events retrieved successfully."
          },
          "data": {
            "type": "object",
            "required": [
              "events",
              "next_cursor"
            ],
            "properties": {
              "events": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CampaignEvent"
                }
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Opaque cursor for the next page; null when there are no more events"
              }
            }
          }
        }
      },
      "CampaignActionResponse": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Campaign scheduled for delivery."
          },
          "data": {
            "description": "The updated campaign. Present on success; omitted in the rare case the campaign cannot be re-read immediately after the action (e.g. it was concurrently deleted).",
            "$ref": "#/components/schemas/CampaignSummary"
          }
        }
      },
      "StoreCampaignRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Campaign name. Required unless `subject` is given, in which case the subject is used.",
            "example": "October newsletter"
          },
          "subject": {
            "type": "string",
            "nullable": true,
            "maxLength": 998,
            "example": "News for October"
          },
          "from_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 255,
            "example": "news@example.com"
          },
          "from_name": {
            "type": "string",
            "nullable": true,
            "maxLength": 255,
            "example": "Example"
          },
          "reply_to": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 255
          },
          "html_content": {
            "type": "string",
            "nullable": true,
            "description": "Email HTML. Merge tags such as `{{first_name}}` are filled from contact properties. Cannot be combined with `template_id`; required when `json_content` is given.",
            "example": "<p>Hello {{first_name}}</p>"
          },
          "json_content": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Editor JSON stored next to `html_content` so the campaign can be opened in the editor."
          },
          "template_id": {
            "type": "integer",
            "nullable": true,
            "description": "Template from one of your projects. Its HTML is copied onto the campaign. Cannot be combined with `html_content`."
          },
          "audience_config": {
            "type": "object",
            "nullable": true,
            "description": "Who receives the campaign. Lists and segments are combined (a contact in any of them receives it); `topic_id` further limits recipients to contacts subscribed to that topic. With no lists or segments, every subscribed contact receives it.",
            "additionalProperties": false,
            "properties": {
              "all_contacts": {
                "type": "boolean",
                "nullable": true
              },
              "list_ids": {
                "type": "array",
                "nullable": true,
                "items": {
                  "type": "string"
                }
              },
              "segment_ids": {
                "type": "array",
                "nullable": true,
                "items": {
                  "type": "string"
                }
              },
              "topic_id": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "language_overrides": {
            "type": "object",
            "nullable": true,
            "description": "Per-language sender and subject overrides, keyed by language code.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "subject": {
                  "type": "string",
                  "nullable": true,
                  "maxLength": 998
                },
                "from_email": {
                  "type": "string",
                  "format": "email",
                  "nullable": true,
                  "maxLength": 255
                },
                "from_email_domain": {
                  "type": "string",
                  "nullable": true,
                  "maxLength": 253,
                  "description": "Verified sending domain to send this language from, keeping the local part of `from_email`."
                },
                "from_name": {
                  "type": "string",
                  "nullable": true,
                  "maxLength": 255
                },
                "reply_to": {
                  "type": "string",
                  "format": "email",
                  "nullable": true,
                  "maxLength": 255
                }
              }
            }
          }
        }
      },
      "CreateCampaignResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Campaign created successfully."
          },
          "data": {
            "$ref": "#/components/schemas/CampaignDetail"
          }
        }
      },
      "ScheduleCampaignRequest": {
        "type": "object",
        "required": [
          "scheduled_at"
        ],
        "properties": {
          "scheduled_at": {
            "type": "string",
            "format": "date-time",
            "description": "Future delivery time (ISO 8601). Include a timezone offset (e.g. `+02:00` or `Z`); a value without an offset is interpreted as UTC. Must be in the future.",
            "example": "2026-06-01T09:00:00+00:00"
          }
        }
      },
      "AudienceTopicSubscription": {
        "type": "object",
        "description": "A topic and the subscription state to apply to it.",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "subscription": {
            "type": "string",
            "enum": [
              "opt_in",
              "opt_out"
            ],
            "default": "opt_in",
            "description": "`opt_in` subscribes the contact. `opt_out` suppresses the topic — including topics that auto-subscribe new contacts — and, with `update_existing`, unsubscribes a contact that was already subscribed."
          }
        }
      },
      "BulkAudienceContactRow": {
        "type": "object",
        "description": "One contact in a bulk create payload.",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "example": "jane@example.com"
          },
          "properties": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string",
              "maxLength": 1000
            },
            "description": "Custom property values for this contact. Each key must match a property defined for the team.",
            "example": {
              "first_name": "Jane"
            }
          },
          "list_ids": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 50,
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lists this contact is added to, on top of the batch-wide ones."
          },
          "topics": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/AudienceTopicSubscription"
            },
            "description": "Topic subscriptions for this contact."
          }
        }
      },
      "BulkAudienceContactError": {
        "type": "object",
        "description": "A row that was skipped, with its position in the submitted array.",
        "required": [
          "index",
          "email",
          "error_code",
          "error"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "minimum": 0,
            "description": "Zero-based position of the row in the request."
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "error_code": {
            "type": "string",
            "enum": [
              "missing_email",
              "invalid_email",
              "invalid_property_value",
              "unknown_property_key",
              "unknown_list",
              "unknown_topic",
              "invalid_topic_subscription"
            ]
          },
          "error": {
            "type": "string"
          }
        }
      },
      "BulkAudienceContactRef": {
        "type": "object",
        "description": "Identity of a contact touched by the request, so the caller can chain into the bulk list and topic endpoints without looking ids up again.",
        "required": [
          "id",
          "email",
          "created"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "created": {
            "type": "boolean",
            "description": "True when this request created the contact."
          }
        }
      },
      "BulkAudienceContactTopicsRequest": {
        "type": "object",
        "description": "Bulk subscribe/unsubscribe contacts to/from topics. All combinations of contact_ids × topic_ids are processed.",
        "required": [
          "contact_ids",
          "topic_ids"
        ],
        "properties": {
          "contact_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "topic_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "type": "string",
              "format": "uuid"
            }
          }
        }
      },
      "BulkSubscribeContactsToTopicsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contacts subscribed to topics."
          },
          "data": {
            "type": "object",
            "required": [
              "subscribed",
              "already_subscribed",
              "total_pairs"
            ],
            "properties": {
              "subscribed": {
                "type": "integer",
                "minimum": 0,
                "description": "Newly subscribed pairs"
              },
              "already_subscribed": {
                "type": "integer",
                "minimum": 0,
                "description": "Pairs that already existed"
              },
              "total_pairs": {
                "type": "integer",
                "minimum": 0,
                "description": "Total contact × topic pairs processed"
              }
            }
          }
        }
      },
      "BulkUnsubscribeContactsFromTopicsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string",
            "example": "Contacts unsubscribed from topics."
          },
          "data": {
            "type": "object",
            "required": [
              "unsubscribed",
              "total_pairs"
            ],
            "properties": {
              "unsubscribed": {
                "type": "integer",
                "minimum": 0,
                "description": "Pairs that were removed"
              },
              "total_pairs": {
                "type": "integer",
                "minimum": 0,
                "description": "Total contact × topic pairs processed"
              }
            }
          }
        }
      },
      "ScheduledEmailsPagination": {
        "type": "object",
        "required": [
          "total",
          "per_page",
          "current_page",
          "last_page"
        ],
        "properties": {
          "total": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "current_page": {
            "type": "integer"
          },
          "last_page": {
            "type": "integer"
          }
        }
      },
      "ListScheduledEmailsResponse": {
        "type": "object",
        "required": [
          "message",
          "data"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "scheduled_emails",
              "pagination"
            ],
            "properties": {
              "scheduled_emails": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ScheduledEmailResponse"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/ScheduledEmailsPagination"
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Emails",
      "description": "Email sending operations"
    },
    {
      "name": "Templates",
      "description": "Email template management operations"
    },
    {
      "name": "Domains",
      "description": "Domain management operations"
    },
    {
      "name": "Webhooks",
      "description": "Webhook management operations"
    },
    {
      "name": "Audience",
      "description": "Audience management: lists, contacts, topics, properties, and segments"
    },
    {
      "name": "Campaigns",
      "description": "Campaign operations: listing, stats, engagement events, and dispatch/scheduling"
    }
  ]
}
