{
  "openapi": "3.1.0",
  "info": {
    "title": "Rhino Relay API",
    "version": "1.0.0",
    "description": "Email campaigns where your list never leaves your AWS account. Every request acts on exactly one tenant, set by the credential.",
    "contact": {
      "name": "Rhino Relay support",
      "url": "https://docs.rhinorelay.com/trust/support/"
    }
  },
  "servers": [
    {
      "url": "https://api.rhinorelay.com/v1",
      "description": "API key, for tenants in the home Region (us-east-2)",
      "x-region": "us-east-2"
    },
    {
      "url": "https://api.{region}.rhinorelay.com/v1",
      "description": "API key, for tenants in any other Region (the console shows yours)",
      "variables": {
        "region": {
          "default": "us-east-1",
          "enum": [
            "us-east-1",
            "us-west-1",
            "us-west-2",
            "ca-central-1",
            "sa-east-1",
            "eu-west-1",
            "eu-west-2",
            "eu-west-3",
            "eu-central-1",
            "eu-north-1",
            "eu-south-1",
            "il-central-1",
            "me-south-1",
            "af-south-1",
            "ap-south-1",
            "ap-northeast-1",
            "ap-northeast-2",
            "ap-northeast-3",
            "ap-southeast-1",
            "ap-southeast-2",
            "ap-southeast-3"
          ]
        }
      }
    },
    {
      "url": "https://api.{clientDomain}/v1",
      "description": "API key, through your custom API domain",
      "variables": {
        "clientDomain": {
          "default": "example.com"
        }
      }
    }
  ],
  "tags": [
    {
      "name": "Contacts",
      "description": "Create, find, update and erase contacts.",
      "x-group": "contacts"
    },
    {
      "name": "Segments",
      "description": "Saved audiences and their counts.",
      "x-group": "segments"
    },
    {
      "name": "Templates",
      "description": "Email templates, their versions and previews.",
      "x-group": "templates"
    },
    {
      "name": "Campaigns",
      "description": "Create, test, schedule and report on campaigns.",
      "x-group": "campaigns"
    },
    {
      "name": "Imports",
      "description": "CSV and Mailchimp imports.",
      "x-group": "imports"
    },
    {
      "name": "Exports",
      "description": "Export contacts, send records and events to your own bucket.",
      "x-group": "exports"
    },
    {
      "name": "Health",
      "description": "Check setup and sending health.",
      "x-group": "health"
    },
    {
      "name": "Setup",
      "description": "Connect the installed template.",
      "x-group": "setup"
    },
    {
      "name": "Domains",
      "description": "The tracking domain and a custom API domain.",
      "x-group": "domains"
    },
    {
      "name": "Settings",
      "description": "Account settings.",
      "x-group": "settings"
    },
    {
      "name": "API keys",
      "description": "API keys and their scopes.",
      "x-group": "keys"
    },
    {
      "name": "Public",
      "description": "Unsubscribe links and the Mailchimp redirect. Not called with a credential.",
      "x-group": "public"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key: `Authorization: Bearer ek_<keyId>_<secret>`"
      }
    },
    "schemas": {
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ct_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Contact ID",
            "example": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          },
          "status": {
            "$ref": "#/components/schemas/ContactStatus"
          },
          "statusReason": {
            "type": "string"
          },
          "statusAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/FieldValue"
            },
            "description": "Custom fields used as merge values (up to 100 keys, values up to 1 KB)",
            "example": {
              "FNAME": "Ada",
              "plan": "pro"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "maxItems": 200,
            "description": "Up to 200 tags",
            "example": [
              "customer",
              "newsletter"
            ]
          },
          "consent": {
            "$ref": "#/components/schemas/Consent"
          },
          "score": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Engagement score, 0-100, decayed when read"
          },
          "lastOpenAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "lastClickAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "lastSentAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "sunsetAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "email",
          "status",
          "statusReason",
          "statusAt",
          "fields",
          "tags",
          "score",
          "lastOpenAt",
          "lastClickAt",
          "lastSentAt",
          "sunsetAt",
          "createdAt",
          "updatedAt",
          "version"
        ],
        "example": {
          "id": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8",
          "email": "ada@example.com",
          "status": "subscribed",
          "statusReason": "api",
          "statusAt": "2026-01-15T10:00:00.000Z",
          "fields": {
            "FNAME": "Ada"
          },
          "tags": [
            "customer"
          ],
          "consent": {
            "source": "signup-form",
            "at": "2026-01-15T10:00:00.000Z",
            "method": "single_opt_in"
          },
          "score": 12.5,
          "lastOpenAt": "2026-09-01T08:00:00.000Z",
          "lastClickAt": null,
          "lastSentAt": "2026-09-01T07:59:00.000Z",
          "sunsetAt": null,
          "createdAt": "2026-01-15T10:00:00.000Z",
          "updatedAt": "2026-09-01T08:00:00.000Z",
          "version": 3
        }
      },
      "ContactStatus": {
        "type": "string",
        "enum": [
          "subscribed",
          "unsubscribed",
          "bounced",
          "complained",
          "cleaned"
        ]
      },
      "FieldValue": {
        "anyOf": [
          {
            "type": "string",
            "maxLength": 1024
          },
          {
            "type": "number"
          },
          {
            "type": "boolean"
          },
          {
            "type": "null"
          }
        ],
        "description": "A custom field value: string, number, boolean or null"
      },
      "Consent": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "example": "signup-form"
          },
          "at": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "ip": {
            "type": "string",
            "maxLength": 45
          },
          "method": {
            "$ref": "#/components/schemas/ConsentMethod"
          }
        },
        "required": [
          "source",
          "at",
          "method"
        ],
        "description": "How and when the contact agreed to receive email",
        "example": {
          "source": "signup-form",
          "at": "2026-01-15T10:00:00.000Z",
          "method": "single_opt_in"
        }
      },
      "ConsentMethod": {
        "type": "string",
        "enum": [
          "single_opt_in",
          "double_opt_in",
          "attested",
          "imported"
        ],
        "description": "How the contact consented"
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Link to the error's documentation page"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation. Never repeats input values."
          },
          "requestId": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldError"
            }
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code",
          "detail",
          "requestId"
        ],
        "description": "RFC 9457 problem details (application/problem+json)",
        "example": {
          "type": "https://docs.rhinorelay.com/api/errors/validation-failed/",
          "title": "Validation failed",
          "status": 422,
          "code": "validation_failed",
          "detail": "The request body is invalid.",
          "requestId": "req_01J9Z8X7W6V5T4S3R2Q1P0N9M8",
          "errors": [
            {
              "path": "email",
              "message": "Invalid email address"
            }
          ]
        }
      },
      "ErrorCode": {
        "type": "string",
        "enum": [
          "bad_request",
          "unauthenticated",
          "entitlement_inactive",
          "forbidden",
          "not_found",
          "tenant_disconnected",
          "contact_suppressed",
          "email_taken",
          "cannot_resubscribe",
          "segment_in_use",
          "not_draft",
          "invalid_state",
          "quota_reserve_exhausted",
          "not_ready",
          "already_committed",
          "idempotency_conflict",
          "version_conflict",
          "batch_too_large",
          "validation_failed",
          "consent_required",
          "segment_invalid",
          "template_invalid",
          "from_domain_unverified",
          "render_failed",
          "schedule_checks_failed",
          "acknowledge_mismatch",
          "mailchimp_auth_failed",
          "stack_not_found",
          "role_assume_failed",
          "wrong_region",
          "rate_limited",
          "internal",
          "dependency_unavailable"
        ]
      },
      "FieldError": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "path",
          "message"
        ],
        "description": "What's wrong with one field, without its value"
      },
      "ContactInput": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          },
          "status": {
            "$ref": "#/components/schemas/SubscriptionChoice"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/FieldValue"
            },
            "description": "Custom fields used as merge values (up to 100 keys, values up to 1 KB)",
            "example": {
              "FNAME": "Ada",
              "plan": "pro"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "maxItems": 200,
            "description": "Up to 200 tags",
            "example": [
              "customer",
              "newsletter"
            ]
          },
          "consent": {
            "$ref": "#/components/schemas/ConsentInput"
          }
        },
        "required": [
          "email"
        ],
        "additionalProperties": false,
        "description": "A subscribed contact (the default status) needs consent.",
        "example": {
          "email": "ada@example.com",
          "fields": {
            "FNAME": "Ada"
          },
          "tags": [
            "customer"
          ],
          "consent": {
            "source": "signup-form",
            "at": "2026-01-15T10:00:00Z",
            "method": "single_opt_in"
          }
        }
      },
      "SubscriptionChoice": {
        "type": "string",
        "enum": [
          "subscribed",
          "unsubscribed"
        ],
        "description": "The status to create a contact with (default subscribed)"
      },
      "ConsentInput": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "example": "signup-form"
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 date-time",
            "example": "2026-10-01T09:30:00Z"
          },
          "ip": {
            "type": "string",
            "maxLength": 45
          },
          "method": {
            "$ref": "#/components/schemas/ConsentMethod"
          }
        },
        "required": [
          "source",
          "at",
          "method"
        ]
      },
      "ContactBatchResult": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchResultItem"
            }
          }
        },
        "required": [
          "results"
        ]
      },
      "BatchResultItem": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer"
          },
          "status": {
            "type": "integer"
          },
          "contact": {
            "$ref": "#/components/schemas/Contact"
          },
          "error": {
            "$ref": "#/components/schemas/BatchItemError"
          }
        },
        "required": [
          "index",
          "status"
        ],
        "description": "The outcome for one item, by its index in the request"
      },
      "BatchItemError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "title"
        ],
        "description": "Why one item of a batch failed"
      },
      "ContactBatchInput": {
        "type": "object",
        "properties": {
          "contacts": {
            "type": "array",
            "items": {},
            "minItems": 1,
            "description": "Up to 1,000 ContactInput objects"
          }
        },
        "required": [
          "contacts"
        ],
        "additionalProperties": false
      },
      "ContactLookupResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Contact"
            },
            "maxItems": 1
          }
        },
        "required": [
          "data"
        ],
        "description": "Zero or one contact with the email"
      },
      "ContactLookupInput": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          }
        },
        "required": [
          "email"
        ],
        "additionalProperties": false
      },
      "ContactPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Contact"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "ContactPatch": {
        "type": "object",
        "properties": {
          "fields": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/FieldValue"
            },
            "description": "Merged into existing fields; null removes a field",
            "example": {
              "FNAME": "Ada",
              "plan": "pro"
            }
          },
          "addTags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "maxItems": 200,
            "description": "Up to 200 tags",
            "example": [
              "customer",
              "newsletter"
            ]
          },
          "removeTags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "maxItems": 200,
            "description": "Up to 200 tags",
            "example": [
              "customer",
              "newsletter"
            ]
          },
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          }
        },
        "additionalProperties": false,
        "example": {
          "fields": {
            "plan": "team"
          },
          "addTags": [
            "beta"
          ]
        }
      },
      "UnsubscribeInput": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 200
          }
        },
        "additionalProperties": false
      },
      "ResubscribeInput": {
        "type": "object",
        "properties": {
          "consent": {
            "$ref": "#/components/schemas/ConsentInput"
          }
        },
        "required": [
          "consent"
        ],
        "additionalProperties": false
      },
      "Segment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^sg_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Segment ID",
            "example": "sg_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "name": {
            "type": "string"
          },
          "definition": {
            "$ref": "#/components/schemas/SegmentDefinition"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "name",
          "definition",
          "createdAt",
          "updatedAt",
          "version"
        ]
      },
      "SegmentDefinition": {
        "type": "object",
        "properties": {
          "all": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentNode"
            }
          },
          "any": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentNode"
            }
          },
          "none": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentNode"
            }
          },
          "includeSunset": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Filters on tags, fields and engagement, up to 3 levels deep and 50 conditions. An empty definition matches every sendable contact.",
        "example": {
          "all": [
            {
              "type": "tag",
              "tag": "customer"
            },
            {
              "type": "clicked",
              "withinDays": 180
            }
          ],
          "none": [
            {
              "type": "tag",
              "tag": "vip"
            }
          ]
        }
      },
      "SegmentNode": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/TagCondition"
          },
          {
            "$ref": "#/components/schemas/FieldCondition"
          },
          {
            "$ref": "#/components/schemas/ScoreCondition"
          },
          {
            "$ref": "#/components/schemas/ClickedCondition"
          },
          {
            "$ref": "#/components/schemas/OpenedCondition"
          },
          {
            "$ref": "#/components/schemas/CreatedCondition"
          },
          {
            "$ref": "#/components/schemas/SegmentGroup"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "tag": "#/components/schemas/TagCondition",
            "field": "#/components/schemas/FieldCondition",
            "score": "#/components/schemas/ScoreCondition",
            "clicked": "#/components/schemas/ClickedCondition",
            "opened": "#/components/schemas/OpenedCondition",
            "created": "#/components/schemas/CreatedCondition",
            "group": "#/components/schemas/SegmentGroup"
          }
        },
        "description": "A condition or a nested group, told apart by type"
      },
      "TagCondition": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "tag"
            ]
          },
          "tag": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "type",
          "tag"
        ],
        "additionalProperties": false,
        "description": "The contact has this tag"
      },
      "FieldCondition": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "field"
            ]
          },
          "field": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "op": {
            "$ref": "#/components/schemas/FieldOperator"
          },
          "value": {
            "$ref": "#/components/schemas/FieldValue"
          },
          "values": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldValue"
            },
            "minItems": 1,
            "maxItems": 100,
            "description": "in only: the field equals one of these 1-100 values"
          }
        },
        "required": [
          "type",
          "field",
          "op"
        ],
        "additionalProperties": false,
        "description": "A custom field compared with a value. value for eq and neq: a string, number, boolean or null; gt and lt: a number; before and after: an ISO date; exists: an optional boolean. in takes values instead."
      },
      "FieldOperator": {
        "type": "string",
        "enum": [
          "eq",
          "neq",
          "in",
          "exists",
          "gt",
          "lt",
          "before",
          "after"
        ]
      },
      "ScoreCondition": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "score"
            ]
          },
          "min": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          }
        },
        "required": [
          "type",
          "min"
        ],
        "additionalProperties": false,
        "description": "Engagement score at least min (0-100)"
      },
      "ClickedCondition": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "clicked"
            ]
          },
          "withinDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          }
        },
        "required": [
          "type",
          "withinDays"
        ],
        "additionalProperties": false,
        "description": "Clicked a link within the last withinDays days"
      },
      "OpenedCondition": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "opened"
            ]
          },
          "withinDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          }
        },
        "required": [
          "type",
          "withinDays"
        ],
        "additionalProperties": false,
        "description": "Opened an email within the last withinDays days"
      },
      "CreatedCondition": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "created"
            ]
          },
          "withinDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          }
        },
        "required": [
          "type",
          "withinDays"
        ],
        "additionalProperties": false,
        "description": "Created within the last withinDays days"
      },
      "SegmentGroup": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "group"
            ]
          },
          "all": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentNode"
            }
          },
          "any": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentNode"
            }
          },
          "none": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentNode"
            }
          }
        },
        "required": [
          "type"
        ],
        "additionalProperties": false,
        "description": "Nested conditions: all must match, at least one of any, and none of none"
      },
      "SegmentInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "definition": {
            "$ref": "#/components/schemas/SegmentDefinition"
          }
        },
        "required": [
          "name",
          "definition"
        ],
        "additionalProperties": false,
        "example": {
          "name": "Engaged customers",
          "definition": {
            "all": [
              {
                "type": "tag",
                "tag": "customer"
              },
              {
                "type": "opened",
                "withinDays": 180
              }
            ]
          }
        }
      },
      "SegmentPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Segment"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "SegmentPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "definition": {
            "$ref": "#/components/schemas/SegmentDefinition"
          }
        },
        "additionalProperties": false
      },
      "SegmentCount": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "evaluatedAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          }
        },
        "required": [
          "count",
          "evaluatedAt"
        ],
        "example": {
          "count": 48210,
          "evaluatedAt": "2026-10-01T09:30:00.000Z"
        }
      },
      "SegmentCountInput": {
        "type": "object",
        "properties": {
          "definition": {
            "$ref": "#/components/schemas/SegmentDefinition"
          }
        },
        "required": [
          "definition"
        ],
        "additionalProperties": false
      },
      "Template": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^tp_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Template ID",
            "example": "tp_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "name": {
            "type": "string"
          },
          "latestVersion": {
            "type": "integer"
          },
          "versions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateVersion"
            },
            "description": "Newest 20 versions, newest first"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "latestVersion",
          "versions",
          "createdAt"
        ]
      },
      "TemplateVersion": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string",
            "minLength": 1,
            "maxLength": 998
          },
          "preheader": {
            "type": "string",
            "maxLength": 200
          },
          "html": {
            "type": "string",
            "minLength": 1,
            "maxLength": 524288,
            "description": "Liquid HTML. Must contain {{ unsubscribe_url }} and {{ footer_address }}. The HTML and plain text together must stay under 380 KB."
          },
          "text": {
            "type": "string"
          },
          "fromName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "fromEmail": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "An address on the verified sending domain",
            "example": "ada@example.com"
          },
          "replyTo": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          },
          "version": {
            "type": "integer"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          }
        },
        "required": [
          "subject",
          "html",
          "text",
          "fromName",
          "fromEmail",
          "version",
          "warnings",
          "createdAt"
        ]
      },
      "TemplateCreateInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "version": {
            "$ref": "#/components/schemas/TemplateVersionInput"
          }
        },
        "required": [
          "name",
          "version"
        ],
        "additionalProperties": false
      },
      "TemplateVersionInput": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string",
            "minLength": 1,
            "maxLength": 998
          },
          "preheader": {
            "type": "string",
            "maxLength": 200
          },
          "html": {
            "type": "string",
            "minLength": 1,
            "maxLength": 524288,
            "description": "Liquid HTML. Must contain {{ unsubscribe_url }} and {{ footer_address }}. The HTML and plain text together must stay under 380 KB."
          },
          "text": {
            "type": "string",
            "maxLength": 524288,
            "description": "Generated from the HTML if left out"
          },
          "fromName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "fromEmail": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "An address on the verified sending domain",
            "example": "ada@example.com"
          },
          "replyTo": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          }
        },
        "required": [
          "subject",
          "html",
          "fromName",
          "fromEmail"
        ],
        "example": {
          "subject": "Hi {{ contact.fields.FNAME | default: \"there\" }}, here is October",
          "html": "<p>Hello!</p><p><a href=\"{{ unsubscribe_url }}\">Unsubscribe</a><br>{{ footer_address }}</p>",
          "fromName": "Example Co",
          "fromEmail": "news@example.com"
        }
      },
      "TemplatePage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Template"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "TemplateVersionPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateVersion"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "RenderResult": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "required": [
          "subject",
          "html",
          "text",
          "headers"
        ]
      },
      "RenderInput": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "contactId": {
            "type": "string",
            "pattern": "^ct_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Contact ID",
            "example": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "sample": {
            "$ref": "#/components/schemas/RenderSample"
          }
        },
        "additionalProperties": false,
        "description": "Render with a stored contact or with sample values (one of them)"
      },
      "RenderSample": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254,
            "description": "Email address (normalized: trimmed and lower-cased)",
            "example": "ada@example.com"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/FieldValue"
            },
            "description": "Custom fields used as merge values (up to 100 keys, values up to 1 KB)",
            "example": {
              "FNAME": "Ada",
              "plan": "pro"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "maxItems": 200,
            "description": "Up to 200 tags",
            "example": [
              "customer",
              "newsletter"
            ]
          }
        },
        "additionalProperties": false,
        "description": "Sample values to render with instead of a stored contact"
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^cm_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Campaign ID",
            "example": "cm_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "name": {
            "type": "string"
          },
          "templateId": {
            "type": "string",
            "pattern": "^tp_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Template ID",
            "example": "tp_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "templateVersion": {
            "type": "integer"
          },
          "segmentId": {
            "type": "string",
            "pattern": "^sg_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Segment ID",
            "example": "sg_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "segment": {
            "$ref": "#/components/schemas/SegmentDefinition"
          },
          "stagePlan": {
            "$ref": "#/components/schemas/StagePlan"
          },
          "sendAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "state": {
            "$ref": "#/components/schemas/CampaignState"
          },
          "stageIndex": {
            "type": [
              "integer",
              "null"
            ]
          },
          "pauseReason": {
            "$ref": "#/components/schemas/PauseReason"
          },
          "stats": {
            "$ref": "#/components/schemas/CampaignStats"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "name",
          "templateId",
          "templateVersion",
          "stagePlan",
          "state",
          "stageIndex",
          "pauseReason",
          "stats",
          "createdAt",
          "updatedAt",
          "version"
        ]
      },
      "StagePlan": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/PresetStagePlan"
          },
          {
            "$ref": "#/components/schemas/CustomStagePlan"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "preset": "#/components/schemas/PresetStagePlan",
            "custom": "#/components/schemas/CustomStagePlan"
          }
        },
        "description": "A preset plan or your own, told apart by type"
      },
      "PresetStagePlan": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "preset"
            ]
          },
          "name": {
            "$ref": "#/components/schemas/StagePlanName"
          }
        },
        "required": [
          "type",
          "name"
        ],
        "additionalProperties": false,
        "description": "warmup: 2, 8, 20, 30 and 40% a day apart; standard: 10 then 90% two hours later; single: everyone at once"
      },
      "StagePlanName": {
        "type": "string",
        "enum": [
          "warmup",
          "standard",
          "single"
        ],
        "description": "A preset stage plan"
      },
      "CustomStagePlan": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "custom"
            ]
          },
          "stages": {
            "type": "array",
            "items": {
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 100
            },
            "minItems": 1,
            "maxItems": 10,
            "description": "Percent of the audience per stage; must add up to 100"
          },
          "waitMinutes": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10080
          }
        },
        "required": [
          "type",
          "stages",
          "waitMinutes"
        ],
        "additionalProperties": false,
        "description": "Your own stage percentages and wait"
      },
      "CampaignState": {
        "type": "string",
        "enum": [
          "draft",
          "scheduled",
          "sending",
          "paused",
          "completed",
          "cancelled"
        ]
      },
      "PauseReason": {
        "type": [
          "string",
          "null"
        ],
        "enum": [
          "hard_bounce_rate",
          "complaint_rate",
          "manual",
          "ses_paused",
          null
        ],
        "description": "Why a campaign paused"
      },
      "CampaignStats": {
        "type": "object",
        "properties": {
          "audience": {
            "type": "integer"
          },
          "enqueued": {
            "type": "integer"
          },
          "sent": {
            "type": "integer"
          },
          "skipped": {
            "type": "integer"
          },
          "failed": {
            "type": "integer"
          },
          "unknown": {
            "type": "integer"
          },
          "delivered": {
            "type": "integer"
          },
          "uniqueOpens": {
            "type": "integer"
          },
          "machineOpens": {
            "type": "integer"
          },
          "uniqueClicks": {
            "type": "integer"
          },
          "clicks": {
            "type": "integer"
          },
          "botClicks": {
            "type": "integer"
          },
          "hardBounces": {
            "type": "integer"
          },
          "softBounces": {
            "type": "integer"
          },
          "undeterminedBounces": {
            "type": "integer"
          },
          "suppressedBounces": {
            "type": "integer"
          },
          "complaints": {
            "type": "integer"
          },
          "unsubscribes": {
            "type": "integer"
          },
          "delayed": {
            "type": "integer"
          }
        },
        "required": [
          "audience",
          "enqueued",
          "sent",
          "skipped",
          "failed",
          "unknown",
          "delivered",
          "uniqueOpens",
          "machineOpens",
          "uniqueClicks",
          "clicks",
          "botClicks",
          "hardBounces",
          "softBounces",
          "undeterminedBounces",
          "suppressedBounces",
          "complaints",
          "unsubscribes",
          "delayed"
        ]
      },
      "CampaignCreateInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "templateId": {
            "type": "string",
            "pattern": "^tp_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Template ID",
            "example": "tp_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "templateVersion": {
            "type": "integer",
            "minimum": 1
          },
          "segmentId": {
            "type": "string",
            "pattern": "^sg_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Segment ID",
            "example": "sg_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "segment": {
            "$ref": "#/components/schemas/SegmentDefinition"
          },
          "stagePlan": {
            "$ref": "#/components/schemas/StagePlan"
          },
          "sendAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 date-time",
            "example": "2026-10-01T09:30:00Z"
          }
        },
        "required": [
          "name",
          "templateId",
          "templateVersion"
        ],
        "additionalProperties": false,
        "description": "Give exactly one of segmentId or segment. Without stagePlan: warmup for a first send, standard otherwise.",
        "example": {
          "name": "October",
          "templateId": "tp_01J9Z8X7W6V5T4S3R2Q1P0N9M8",
          "templateVersion": 1,
          "segment": {},
          "stagePlan": {
            "type": "preset",
            "name": "warmup"
          }
        }
      },
      "CampaignPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "templateId": {
            "type": "string",
            "pattern": "^tp_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Template ID",
            "example": "tp_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "templateVersion": {
            "type": "integer",
            "minimum": 1
          },
          "segmentId": {
            "type": "string",
            "pattern": "^sg_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Segment ID",
            "example": "sg_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "segment": {
            "$ref": "#/components/schemas/SegmentDefinition"
          },
          "stagePlan": {
            "$ref": "#/components/schemas/StagePlan"
          },
          "sendAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 date-time",
            "example": "2026-10-01T09:30:00Z"
          }
        },
        "additionalProperties": false
      },
      "TestSendResult": {
        "type": "object",
        "properties": {
          "messageIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "messageIds"
        ]
      },
      "TestSendInput": {
        "type": "object",
        "properties": {
          "to": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 254,
              "description": "Email address (normalized: trimmed and lower-cased)",
              "example": "ada@example.com"
            },
            "minItems": 1,
            "maxItems": 10
          },
          "contactId": {
            "type": "string",
            "pattern": "^ct_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Render with this contact's fields",
            "example": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          }
        },
        "required": [
          "to"
        ],
        "additionalProperties": false,
        "example": {
          "to": [
            "you@example.com"
          ]
        }
      },
      "PauseInput": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 200
          }
        },
        "additionalProperties": false
      },
      "ResumeInput": {
        "type": "object",
        "properties": {
          "acknowledge": {
            "type": "string",
            "description": "Must equal the campaign's pauseReason"
          }
        },
        "required": [
          "acknowledge"
        ],
        "additionalProperties": false,
        "example": {
          "acknowledge": "hard_bounce_rate"
        }
      },
      "CampaignPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Campaign"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "Report": {
        "type": "object",
        "properties": {
          "campaignId": {
            "type": "string",
            "pattern": "^cm_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Campaign ID",
            "example": "cm_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "stats": {
            "$ref": "#/components/schemas/CampaignStats"
          },
          "rates": {
            "$ref": "#/components/schemas/Rates"
          },
          "byStage": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StageReport"
            }
          },
          "byLink": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LinkReport"
            }
          }
        },
        "required": [
          "campaignId",
          "stats",
          "rates"
        ]
      },
      "Rates": {
        "type": "object",
        "properties": {
          "delivery": {
            "type": "number"
          },
          "open": {
            "type": "number"
          },
          "click": {
            "type": "number"
          },
          "clickToOpen": {
            "type": "number"
          },
          "hardBounce": {
            "type": "number"
          },
          "complaint": {
            "type": "number"
          },
          "unsubscribe": {
            "type": "number"
          }
        },
        "required": [
          "delivery",
          "open",
          "click",
          "clickToOpen",
          "hardBounce",
          "complaint",
          "unsubscribe"
        ],
        "description": "Rates from human events only; the hard-bounce rate excludes suppression-list and undetermined bounces"
      },
      "StageReport": {
        "type": "object",
        "properties": {
          "stage": {
            "type": "integer"
          },
          "stats": {
            "$ref": "#/components/schemas/CampaignStats"
          }
        },
        "required": [
          "stage",
          "stats"
        ],
        "description": "One stage's counters"
      },
      "LinkReport": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "clicks": {
            "type": "integer"
          },
          "uniqueClicks": {
            "type": "integer"
          }
        },
        "required": [
          "url",
          "clicks",
          "uniqueClicks"
        ],
        "description": "Clicks on one link of the template"
      },
      "RecipientPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Recipient"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "Recipient": {
        "type": "object",
        "properties": {
          "contactId": {
            "type": "string",
            "pattern": "^ct_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Contact ID",
            "example": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "stage": {
            "type": "integer"
          },
          "state": {
            "$ref": "#/components/schemas/RecipientState"
          },
          "messageId": {
            "type": [
              "string",
              "null"
            ]
          },
          "sentAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "firstOpenAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "firstClickAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "bounce": {
            "$ref": "#/components/schemas/BounceKind"
          },
          "complaintAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "unsubAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "failureReason": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "contactId",
          "email",
          "stage",
          "state",
          "messageId",
          "sentAt",
          "deliveredAt",
          "firstOpenAt",
          "firstClickAt",
          "bounce",
          "complaintAt",
          "unsubAt",
          "failureReason"
        ]
      },
      "RecipientState": {
        "type": "string",
        "enum": [
          "queued",
          "claimed",
          "sent",
          "failed",
          "skipped",
          "unknown"
        ],
        "description": "Where one send is. unknown: claimed for over 30 minutes with no outcome"
      },
      "BounceKind": {
        "type": [
          "string",
          "null"
        ],
        "enum": [
          "hard",
          "soft",
          "undetermined",
          "suppressed",
          null
        ]
      },
      "Import": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^im_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Import ID",
            "example": "im_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "source": {
            "$ref": "#/components/schemas/ImportSource"
          },
          "state": {
            "$ref": "#/components/schemas/ImportState"
          },
          "filters": {
            "$ref": "#/components/schemas/ImportFilters"
          },
          "summary": {
            "$ref": "#/components/schemas/ImportSummary"
          },
          "failureReason": {
            "$ref": "#/components/schemas/ImportFailureReason"
          },
          "uploadUrl": {
            "type": "string",
            "description": "CSV: presigned PUT to your own imports bucket; see uploadUrlExpiresAt"
          },
          "uploadUrlExpiresAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "authorizeUrl": {
            "type": "string",
            "description": "Mailchimp OAuth: send the user here. Returned, freshly signed, while the import waits to connect"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "updatedAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          }
        },
        "required": [
          "id",
          "source",
          "state",
          "summary",
          "failureReason",
          "createdAt",
          "updatedAt"
        ]
      },
      "ImportSource": {
        "type": "string",
        "enum": [
          "csv",
          "mailchimp"
        ]
      },
      "ImportState": {
        "type": "string",
        "enum": [
          "connecting",
          "reading",
          "dry_run_ready",
          "committing",
          "completed",
          "failed",
          "cancelled"
        ]
      },
      "ImportFilters": {
        "type": "object",
        "properties": {
          "engagedWithinDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          },
          "minRating": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          },
          "includeUnengaged": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Defaults: engagedWithinDays 365, minRating 2, includeUnengaged false"
      },
      "ImportSummary": {
        "type": "object",
        "properties": {
          "read": {
            "type": "integer"
          },
          "toImport": {
            "type": "integer"
          },
          "suppressed": {
            "type": "integer"
          },
          "skipped": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "removedByCleaning": {
            "type": "integer"
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ImportRowError"
            }
          }
        },
        "required": [
          "read",
          "toImport",
          "suppressed",
          "skipped",
          "removedByCleaning",
          "errors"
        ],
        "description": "The dry run's counts"
      },
      "ImportRowError": {
        "type": "object",
        "properties": {
          "row": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ],
        "description": "A row that couldn't be imported. Never echoes addresses"
      },
      "ImportFailureReason": {
        "type": [
          "string",
          "null"
        ],
        "enum": [
          "mailchimp_not_connected",
          "mailchimp_auth_failed",
          "credential_not_saved",
          "credential_missing",
          "mailchimp_refused",
          "mailchimp_not_found",
          "mailchimp_rejected",
          null
        ],
        "description": "Why an import failed; null unless its state is failed. mailchimp_not_connected: nobody signed in to Mailchimp within a day; mailchimp_auth_failed: Mailchimp didn't accept the sign-in; credential_not_saved: the token couldn't be written to your parameter store; credential_missing: the stored credential was gone when the import read; mailchimp_refused: Mailchimp refused the credential (401 or 403); mailchimp_not_found: something asked for doesn't exist, such as an audience ID (404); mailchimp_rejected: Mailchimp rejected a request for another reason (another 4xx)"
      },
      "CsvImportInput": {
        "type": "object",
        "properties": {
          "consentAttestation": {
            "$ref": "#/components/schemas/ConsentAttestation"
          }
        },
        "additionalProperties": false
      },
      "ConsentAttestation": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 date-time",
            "example": "2026-10-01T09:30:00Z"
          }
        },
        "required": [
          "source"
        ],
        "additionalProperties": false,
        "description": "Attest that every subscribed row consented; used for rows without consent_source and consent_at"
      },
      "MailchimpImportInput": {
        "type": "object",
        "properties": {
          "method": {
            "$ref": "#/components/schemas/MailchimpAuthMethod"
          },
          "apiKey": {
            "type": "string",
            "minLength": 10,
            "maxLength": 200,
            "description": "Required when method is apiKey"
          },
          "audienceIds": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 50
            },
            "maxItems": 50
          },
          "filters": {
            "$ref": "#/components/schemas/ImportFilters"
          },
          "importTemplates": {
            "type": "boolean"
          }
        },
        "required": [
          "method"
        ],
        "additionalProperties": false,
        "example": {
          "method": "apiKey",
          "apiKey": "0123456789abcdef-us21",
          "filters": {
            "engagedWithinDays": 365
          }
        }
      },
      "MailchimpAuthMethod": {
        "type": "string",
        "enum": [
          "oauth",
          "apiKey"
        ],
        "description": "Connect with OAuth, or with a Mailchimp API key"
      },
      "ImportPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Import"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "ImportCommitInput": {
        "type": "object",
        "properties": {
          "filters": {
            "$ref": "#/components/schemas/ImportFilters"
          }
        },
        "additionalProperties": false
      },
      "ExportPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Export"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "Export": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ex_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Export ID",
            "example": "ex_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "kind": {
            "$ref": "#/components/schemas/ExportKind"
          },
          "campaignId": {
            "type": "string",
            "pattern": "^cm_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Campaign ID",
            "example": "cm_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "contactId": {
            "type": "string",
            "pattern": "^ct_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Contact ID",
            "example": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "from": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "to": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "state": {
            "$ref": "#/components/schemas/ExportState"
          },
          "downloadUrl": {
            "type": "string",
            "description": "Presigned GET from your own exports bucket; see downloadUrlExpiresAt. Only on GET /exports/{id}, not in lists"
          },
          "downloadUrlExpiresAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          }
        },
        "required": [
          "id",
          "kind",
          "state",
          "createdAt"
        ]
      },
      "ExportKind": {
        "type": "string",
        "enum": [
          "contacts",
          "recipients",
          "events",
          "contact_data"
        ]
      },
      "ExportState": {
        "type": "string",
        "enum": [
          "running",
          "ready",
          "failed"
        ]
      },
      "ExportInput": {
        "type": "object",
        "properties": {
          "kind": {
            "$ref": "#/components/schemas/ExportKind"
          },
          "campaignId": {
            "type": "string",
            "pattern": "^cm_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Campaign ID",
            "example": "cm_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "contactId": {
            "type": "string",
            "pattern": "^ct_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "Contact ID",
            "example": "ct_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "from": {
            "type": "string",
            "format": "date-time",
            "description": "events only: keep events at or after this time",
            "example": "2026-10-01T09:30:00Z"
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "description": "events only: keep events before this time",
            "example": "2026-10-01T09:30:00Z"
          }
        },
        "required": [
          "kind"
        ],
        "additionalProperties": false,
        "example": {
          "kind": "contacts"
        }
      },
      "Health": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "tenantState": {
            "$ref": "#/components/schemas/TenantState"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HealthCheck"
            }
          }
        },
        "required": [
          "ok",
          "tenantState",
          "checks"
        ]
      },
      "TenantState": {
        "type": "string",
        "enum": [
          "pending",
          "connected",
          "disconnected",
          "read_only"
        ]
      },
      "HealthCheck": {
        "type": "object",
        "properties": {
          "name": {
            "$ref": "#/components/schemas/HealthCheckName"
          },
          "ok": {
            "type": "boolean"
          },
          "detail": {
            "type": "string"
          },
          "fix": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "ok",
          "detail"
        ],
        "description": "One setup or sending check, with how to fix it"
      },
      "HealthCheckName": {
        "type": "string",
        "enum": [
          "connection",
          "template_version",
          "ses_production",
          "ses_sending_enabled",
          "ses_enforcement",
          "quota",
          "send_rate",
          "dkim",
          "mail_from",
          "dmarc",
          "tracking_domain",
          "api_domain",
          "entitlement"
        ]
      },
      "Domains": {
        "type": "object",
        "properties": {
          "api": {
            "$ref": "#/components/schemas/DomainStatus"
          },
          "tracking": {
            "$ref": "#/components/schemas/DomainStatus"
          }
        }
      },
      "DomainStatus": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/DomainState"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DnsRecord"
            }
          }
        },
        "required": [
          "name",
          "status",
          "records"
        ]
      },
      "DomainState": {
        "type": "string",
        "enum": [
          "pending_validation",
          "issued",
          "deploying",
          "live",
          "failed"
        ],
        "description": "Where a domain is in its setup"
      },
      "DnsRecord": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "CNAME"
            ]
          },
          "value": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "type",
          "value"
        ],
        "description": "A DNS record to add"
      },
      "DomainsInput": {
        "type": "object",
        "properties": {
          "apiDomain": {
            "type": "string",
            "maxLength": 253
          },
          "trackingDomain": {
            "type": "string",
            "maxLength": 253
          }
        },
        "required": [
          "trackingDomain"
        ],
        "additionalProperties": false,
        "example": {
          "trackingDomain": "track.example.com",
          "apiDomain": "api.example.com"
        }
      },
      "Settings": {
        "type": "object",
        "properties": {
          "defaultFromName": {
            "type": "string",
            "maxLength": 100
          },
          "defaultFromEmail": {
            "type": "string",
            "maxLength": 254
          },
          "defaultReplyTo": {
            "type": "string",
            "maxLength": 254
          },
          "footerAddress": {
            "type": "string",
            "maxLength": 500,
            "description": "Your physical mailing address (CAN-SPAM)"
          },
          "pause": {
            "$ref": "#/components/schemas/PauseSettings"
          },
          "sunset": {
            "$ref": "#/components/schemas/SunsetSettings"
          },
          "quotaReserve": {
            "type": "integer",
            "minimum": 0
          },
          "iamScopes": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/Scope"
              }
            },
            "description": "Maps SigV4 caller role ARNs to scopes (default admin)"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "defaultFromName",
          "defaultFromEmail",
          "footerAddress",
          "pause",
          "sunset",
          "quotaReserve",
          "iamScopes",
          "version"
        ]
      },
      "PauseSettings": {
        "type": "object",
        "properties": {
          "hardBounceRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "complaintRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "minDelivered": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "hardBounceRate",
          "complaintRate",
          "minDelivered"
        ],
        "description": "When a campaign pauses itself"
      },
      "SunsetSettings": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "minSends": {
            "type": "integer",
            "minimum": 1
          },
          "inactiveDays": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "enabled",
          "minSends",
          "inactiveDays"
        ],
        "description": "Dropping unengaged contacts. Off by default; when on, contacts sent at least minSends emails with no human open or click in inactiveDays are left out of segments."
      },
      "Scope": {
        "type": "string",
        "enum": [
          "contacts:read",
          "contacts:write",
          "campaigns:write",
          "campaigns:send",
          "admin"
        ],
        "description": "Permission carried by an API key"
      },
      "SettingsPatch": {
        "type": "object",
        "properties": {
          "defaultFromName": {
            "type": "string",
            "maxLength": 100
          },
          "defaultFromEmail": {
            "type": "string",
            "maxLength": 254
          },
          "defaultReplyTo": {
            "type": "string",
            "maxLength": 254
          },
          "footerAddress": {
            "type": "string",
            "maxLength": 500,
            "description": "Your physical mailing address (CAN-SPAM)"
          },
          "pause": {
            "$ref": "#/components/schemas/PauseSettingsPatch"
          },
          "sunset": {
            "$ref": "#/components/schemas/SunsetSettingsPatch"
          },
          "quotaReserve": {
            "type": "integer",
            "minimum": 0
          },
          "iamScopes": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/Scope"
              }
            },
            "description": "Maps SigV4 caller role ARNs to scopes (default admin)"
          }
        },
        "additionalProperties": false
      },
      "PauseSettingsPatch": {
        "type": "object",
        "properties": {
          "hardBounceRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "complaintRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "minDelivered": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": false
      },
      "SunsetSettingsPatch": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "minSends": {
            "type": "integer",
            "minimum": 1
          },
          "inactiveDays": {
            "type": "integer",
            "minimum": 1
          }
        },
        "additionalProperties": false
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^key_[0-9A-HJKMNP-TV-Z]{26}$",
            "description": "API key ID",
            "example": "key_01J9Z8X7W6V5T4S3R2Q1P0N9M8"
          },
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Scope"
            }
          },
          "secret": {
            "type": "string",
            "description": "Returned once, when the key is created"
          },
          "lastUsedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "revokedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          },
          "createdAt": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp with milliseconds",
            "example": "2026-10-01T09:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "scopes",
          "lastUsedAt",
          "revokedAt",
          "createdAt"
        ]
      },
      "ApiKeyInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Scope"
            },
            "minItems": 1
          }
        },
        "required": [
          "name",
          "scopes"
        ],
        "additionalProperties": false,
        "example": {
          "name": "Production",
          "scopes": [
            "admin"
          ]
        }
      },
      "ApiKeyPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKey"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "schema": {
          "type": "string",
          "description": "Makes the request safe to retry for 24 hours"
        },
        "required": false,
        "description": "Makes the request safe to retry for 24 hours",
        "name": "Idempotency-Key",
        "in": "header"
      },
      "IdempotencyKeyRequired": {
        "schema": {
          "type": "string",
          "description": "Makes the request safe to retry for 24 hours"
        },
        "required": true,
        "description": "Makes the request safe to retry for 24 hours",
        "name": "Idempotency-Key",
        "in": "header"
      },
      "IfMatch": {
        "schema": {
          "type": "string",
          "description": "The resource version you read"
        },
        "required": false,
        "description": "The resource version you read",
        "name": "If-Match",
        "in": "header"
      },
      "Limit": {
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 500,
          "default": 100,
          "description": "Page size, 1-500 (default 100)"
        },
        "required": false,
        "description": "Page size, 1-500 (default 100)",
        "name": "limit",
        "in": "query"
      },
      "Cursor": {
        "schema": {
          "type": "string",
          "maxLength": 2048,
          "description": "Cursor from the previous page"
        },
        "required": false,
        "description": "Cursor from the previous page",
        "name": "cursor",
        "in": "query"
      }
    }
  },
  "paths": {
    "/contacts": {
      "post": {
        "operationId": "createContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Create or update a contact",
        "description": "Upserts by email. Returns 201 when the contact is new and 200 when it existed. A subscribed contact needs a consent record.\n\nScope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`contact_suppressed`: The address is unsubscribed, bounced, complained, cleaned or erased.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].\n\n`consent_required`: Subscribed contacts need a consent record.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "create"
        },
        "x-idempotency": "key-optional"
      },
      "get": {
        "operationId": "listContacts",
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "schema": {
              "$ref": "#/components/schemas/ContactStatus"
            },
            "required": false,
            "description": "Filter by status",
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100,
              "description": "Filter by tag"
            },
            "required": false,
            "description": "Filter by tag",
            "name": "tag",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of contacts",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/contacts/batch": {
      "post": {
        "operationId": "batchContacts",
        "tags": [
          "Contacts"
        ],
        "summary": "Create or update up to 1,000 contacts",
        "description": "Each item is processed like POST /contacts; results are returned per item.\n\nScope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBatchInput"
              }
            }
          }
        },
        "responses": {
          "207": {
            "description": "Per-item results",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactBatchResult"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "`batch_too_large`: Over 1,000 items or 1 MB.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "batch"
        },
        "x-idempotency": "key-optional"
      }
    },
    "/contacts/lookup": {
      "post": {
        "operationId": "lookupContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Look up a contact by email",
        "description": "Email addresses never go in URLs, so lookups by email use POST.\n\nScope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactLookupInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Matching contacts (zero or one)",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLookupResult"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "lookup"
        },
        "x-idempotency": "safe"
      }
    },
    "/contacts/{id}": {
      "get": {
        "operationId": "getContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The contact",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "get"
        },
        "x-idempotency": "safe"
      },
      "patch": {
        "operationId": "updateContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact's fields, tags or email",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated contact",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`email_taken`: Another contact already has this address.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "412": {
            "description": "`version_conflict`: If-Match doesn't match the resource's current version.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "update"
        },
        "x-idempotency": "safe"
      },
      "delete": {
        "operationId": "deleteContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Erase a contact",
        "description": "Deletes the contact, its email index and every send record, and keeps a salted hash of the address so it can't be re-imported.\n\nScope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Erased",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "delete"
        },
        "x-idempotency": "safe"
      }
    },
    "/contacts/{id}/unsubscribe": {
      "post": {
        "operationId": "unsubscribeContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Unsubscribe a contact",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnsubscribeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The contact",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "unsubscribe"
        },
        "x-idempotency": "safe"
      }
    },
    "/contacts/{id}/resubscribe": {
      "post": {
        "operationId": "resubscribeContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Resubscribe an unsubscribed contact with new consent",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResubscribeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The contact",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`cannot_resubscribe`: Bounced, complained and cleaned contacts can't be resubscribed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "contacts",
          "method": "resubscribe"
        },
        "x-idempotency": "safe"
      }
    },
    "/segments": {
      "post": {
        "operationId": "createSegment",
        "tags": [
          "Segments"
        ],
        "summary": "Create a segment",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SegmentInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Segment"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`segment_invalid`: The segment definition is invalid (over 3 levels, over 50 conditions, or an unknown operator).\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "create"
        },
        "x-idempotency": "key-optional"
      },
      "get": {
        "operationId": "listSegments",
        "tags": [
          "Segments"
        ],
        "summary": "List segments",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of segments",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SegmentPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/segments/{id}": {
      "get": {
        "operationId": "getSegment",
        "tags": [
          "Segments"
        ],
        "summary": "Get a segment",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The segment",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Segment"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "get"
        },
        "x-idempotency": "safe"
      },
      "patch": {
        "operationId": "updateSegment",
        "tags": [
          "Segments"
        ],
        "summary": "Update a segment",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SegmentPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated segment",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Segment"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "412": {
            "description": "`version_conflict`: If-Match doesn't match the resource's current version.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`segment_invalid`: The segment definition is invalid (over 3 levels, over 50 conditions, or an unknown operator).\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "update"
        },
        "x-idempotency": "safe"
      },
      "delete": {
        "operationId": "deleteSegment",
        "tags": [
          "Segments"
        ],
        "summary": "Delete a segment",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`segment_in_use`: A draft, scheduled or sending campaign uses this segment.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "delete"
        },
        "x-idempotency": "safe"
      }
    },
    "/segments/{id}/count": {
      "get": {
        "operationId": "countSegment",
        "tags": [
          "Segments"
        ],
        "summary": "Count a saved segment's sendable contacts",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The count",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SegmentCount"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "count"
        },
        "x-idempotency": "safe"
      }
    },
    "/segments/count": {
      "post": {
        "operationId": "countSegmentDefinition",
        "tags": [
          "Segments"
        ],
        "summary": "Count sendable contacts matching a definition",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SegmentCountInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The count",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SegmentCount"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`segment_invalid`: The segment definition is invalid (over 3 levels, over 50 conditions, or an unknown operator).\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "segments",
          "method": "countDefinition"
        },
        "x-idempotency": "safe"
      }
    },
    "/templates": {
      "post": {
        "operationId": "createTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Create a template with its first version",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateCreateInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`template_invalid`: The template is missing {{ unsubscribe_url }} or {{ footer_address }}, doesn't parse, or is over 380 KB.\n\n`from_domain_unverified`: fromEmail must be on the tenant's verified sending domain.\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "templates",
          "method": "create"
        },
        "x-idempotency": "key-optional"
      },
      "get": {
        "operationId": "listTemplates",
        "tags": [
          "Templates"
        ],
        "summary": "List templates",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of templates",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplatePage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "templates",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/templates/{id}/versions": {
      "post": {
        "operationId": "createTemplateVersion",
        "tags": [
          "Templates"
        ],
        "summary": "Add a template version",
        "description": "Versions never change once created.\n\nScope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateVersionInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateVersion"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`template_invalid`: The template is missing {{ unsubscribe_url }} or {{ footer_address }}, doesn't parse, or is over 380 KB.\n\n`from_domain_unverified`: fromEmail must be on the tenant's verified sending domain.\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "templates",
          "method": "createVersion"
        },
        "x-idempotency": "key-optional"
      },
      "get": {
        "operationId": "listTemplateVersions",
        "tags": [
          "Templates"
        ],
        "summary": "List a template's versions",
        "description": "Every version, newest first, including those older than the newest 20.\n\nScope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of versions",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateVersionPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "templates",
          "method": "versions"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/templates/{id}": {
      "get": {
        "operationId": "getTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Get a template and its newest 20 versions",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The template",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "templates",
          "method": "get"
        },
        "x-idempotency": "safe"
      }
    },
    "/templates/{id}/render": {
      "post": {
        "operationId": "renderTemplate",
        "tags": [
          "Templates"
        ],
        "summary": "Render a preview",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenderInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The rendered email",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderResult"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`render_failed`: The template failed to render with the given contact or sample.\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "templates",
          "method": "render"
        },
        "x-idempotency": "safe"
      }
    },
    "/campaigns": {
      "post": {
        "operationId": "createCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Create a draft campaign",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignCreateInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].\n\n`segment_invalid`: The segment definition is invalid (over 3 levels, over 50 conditions, or an unknown operator).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "create"
        },
        "x-idempotency": "key-optional"
      },
      "get": {
        "operationId": "listCampaigns",
        "tags": [
          "Campaigns"
        ],
        "summary": "List campaigns",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "schema": {
              "$ref": "#/components/schemas/CampaignState"
            },
            "required": false,
            "name": "state",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of campaigns",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/campaigns/{id}": {
      "patch": {
        "operationId": "updateCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Update a draft campaign",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated campaign",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`not_draft`: Only draft campaigns can change or be deleted.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "412": {
            "description": "`version_conflict`: If-Match doesn't match the resource's current version.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "update"
        },
        "x-idempotency": "safe"
      },
      "delete": {
        "operationId": "deleteCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Delete a draft campaign",
        "description": "Only drafts can be deleted; cancel a campaign that has been scheduled.\n\nScope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`not_draft`: Only draft campaigns can change or be deleted.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "delete"
        },
        "x-idempotency": "safe"
      },
      "get": {
        "operationId": "getCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Get a campaign",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The campaign",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "get"
        },
        "x-idempotency": "safe",
        "x-waiters": {
          "completed": {
            "description": "Every stage has gone out. A pause or cancel ends the wait, since it needs you to act",
            "delaySeconds": 30,
            "maxAttempts": 2880,
            "acceptors": [
              {
                "path": "state",
                "expected": "completed",
                "state": "success"
              },
              {
                "path": "state",
                "expected": "paused",
                "state": "failure"
              },
              {
                "path": "state",
                "expected": "cancelled",
                "state": "failure"
              }
            ]
          }
        }
      }
    },
    "/campaigns/{id}/test": {
      "post": {
        "operationId": "testCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Send test emails",
        "description": "Up to 10 addresses, with a [TEST] subject prefix. Test sends don't change campaign counters and count against the quota reserve.\n\nScope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestSendInput"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted by SES",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestSendResult"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`quota_reserve_exhausted`: Test sends would exceed the daily quota reserve.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`render_failed`: The template failed to render with the given contact or sample.\n\n`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "test"
        },
        "x-idempotency": "key-required"
      }
    },
    "/campaigns/{id}/schedule": {
      "post": {
        "operationId": "scheduleCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Schedule a campaign",
        "description": "Runs the pre-send checks (template, connection, entitlement, SES production access, DKIM, MAIL FROM, DMARC, non-empty segment) and schedules stage 0 at sendAt or now.\n\nScope: `campaigns:send`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "responses": {
          "202": {
            "description": "Scheduled",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            },
            "links": {
              "getCampaign": {
                "operationId": "getCampaign",
                "description": "Poll it (waiters: completed)",
                "parameters": {
                  "id": "$response.body#/id"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "`entitlement_inactive`: The subscription ended and the grace period is over. Unsubscribe, erasure, export and reads keep working.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`invalid_state`: The campaign's state doesn't allow this action.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`schedule_checks_failed`: One or more pre-send checks failed. See errors[] for each check and its fix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "schedule"
        },
        "x-idempotency": "key-required"
      }
    },
    "/campaigns/{id}/pause": {
      "post": {
        "operationId": "pauseCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Pause a sending campaign",
        "description": "Scope: `campaigns:send`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PauseInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Paused",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`invalid_state`: The campaign's state doesn't allow this action.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "pause"
        },
        "x-idempotency": "safe"
      }
    },
    "/campaigns/{id}/resume": {
      "post": {
        "operationId": "resumeCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Resume a paused campaign",
        "description": "Scope: `campaigns:send`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResumeInput"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Resumed",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            },
            "links": {
              "getCampaign": {
                "operationId": "getCampaign",
                "description": "Poll it (waiters: completed)",
                "parameters": {
                  "id": "$response.body#/id"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "`entitlement_inactive`: The subscription ended and the grace period is over. Unsubscribe, erasure, export and reads keep working.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`invalid_state`: The campaign's state doesn't allow this action.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`acknowledge_mismatch`: Resume needs acknowledge equal to the campaign's pauseReason.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "resume"
        },
        "x-idempotency": "key-required"
      }
    },
    "/campaigns/{id}/cancel": {
      "post": {
        "operationId": "cancelCampaign",
        "tags": [
          "Campaigns"
        ],
        "summary": "Cancel a campaign",
        "description": "Scope: `campaigns:send`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`invalid_state`: The campaign's state doesn't allow this action.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "cancel"
        },
        "x-idempotency": "safe"
      }
    },
    "/campaigns/{id}/report": {
      "get": {
        "operationId": "getCampaignReport",
        "tags": [
          "Campaigns"
        ],
        "summary": "Get a campaign report",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "stage",
                "link"
              ]
            },
            "required": false,
            "name": "by",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Counters and rates",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "report"
        },
        "x-idempotency": "safe"
      }
    },
    "/campaigns/{id}/recipients": {
      "get": {
        "operationId": "listCampaignRecipients",
        "tags": [
          "Campaigns"
        ],
        "summary": "List a campaign's send records",
        "description": "Scope: `campaigns:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "schema": {
              "$ref": "#/components/schemas/RecipientState"
            },
            "required": false,
            "description": "Where one send is. unknown: claimed for over 30 minutes with no outcome",
            "name": "state",
            "in": "query"
          },
          {
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            },
            "required": false,
            "name": "stage",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of recipients",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecipientPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "campaigns",
          "method": "recipients"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/imports/csv": {
      "post": {
        "operationId": "createCsvImport",
        "tags": [
          "Imports"
        ],
        "summary": "Start a CSV import",
        "description": "Returns a presigned PUT URL for your own imports bucket. Upload the file there; it never passes through our account.\n\nScope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CsvImportInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created, with uploadUrl",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Import"
                }
              }
            },
            "links": {
              "getImport": {
                "operationId": "getImport",
                "description": "Poll it (waiters: dryRunReady, completed)",
                "parameters": {
                  "id": "$response.body#/id"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "`entitlement_inactive`: The subscription ended and the grace period is over. Unsubscribe, erasure, export and reads keep working.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "imports",
          "method": "createCsv"
        },
        "x-idempotency": "key-optional"
      }
    },
    "/imports/mailchimp": {
      "post": {
        "operationId": "createMailchimpImport",
        "tags": [
          "Imports"
        ],
        "summary": "Start a Mailchimp import",
        "description": "With an API key the import starts at once; with OAuth, send the user to authorizeUrl. Credentials are kept in your account's SSM and deleted on commit.\n\nScope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MailchimpImportInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Import"
                }
              }
            },
            "links": {
              "getImport": {
                "operationId": "getImport",
                "description": "Poll it (waiters: dryRunReady, completed)",
                "parameters": {
                  "id": "$response.body#/id"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "`entitlement_inactive`: The subscription ended and the grace period is over. Unsubscribe, erasure, export and reads keep working.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].\n\n`mailchimp_auth_failed`: Mailchimp rejected the API key or OAuth grant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "imports",
          "method": "createMailchimp"
        },
        "x-idempotency": "key-optional"
      }
    },
    "/imports": {
      "get": {
        "operationId": "listImports",
        "tags": [
          "Imports"
        ],
        "summary": "List imports",
        "description": "Newest first.\n\nScope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "schema": {
              "$ref": "#/components/schemas/ImportState"
            },
            "required": false,
            "description": "Filter by state",
            "name": "state",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of imports",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "imports",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/imports/{id}": {
      "get": {
        "operationId": "getImport",
        "tags": [
          "Imports"
        ],
        "summary": "Get an import and its dry-run summary",
        "description": "Scope: `contacts:read`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The import",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Import"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "imports",
          "method": "get"
        },
        "x-idempotency": "safe",
        "x-waiters": {
          "dryRunReady": {
            "description": "The dry run is ready to review and commit (or the import went further)",
            "delaySeconds": 5,
            "maxAttempts": 720,
            "acceptors": [
              {
                "path": "state",
                "expected": "dry_run_ready",
                "state": "success"
              },
              {
                "path": "state",
                "expected": "committing",
                "state": "success"
              },
              {
                "path": "state",
                "expected": "completed",
                "state": "success"
              },
              {
                "path": "state",
                "expected": "failed",
                "state": "failure"
              },
              {
                "path": "state",
                "expected": "cancelled",
                "state": "failure"
              }
            ]
          },
          "completed": {
            "description": "The import is committed",
            "delaySeconds": 10,
            "maxAttempts": 1080,
            "acceptors": [
              {
                "path": "state",
                "expected": "completed",
                "state": "success"
              },
              {
                "path": "state",
                "expected": "failed",
                "state": "failure"
              },
              {
                "path": "state",
                "expected": "cancelled",
                "state": "failure"
              }
            ]
          }
        }
      },
      "delete": {
        "operationId": "deleteImport",
        "tags": [
          "Imports"
        ],
        "summary": "Cancel an uncommitted import",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Cancelled",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`already_committed`: The import has already been committed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "imports",
          "method": "delete"
        },
        "x-idempotency": "safe"
      }
    },
    "/imports/{id}/commit": {
      "post": {
        "operationId": "commitImport",
        "tags": [
          "Imports"
        ],
        "summary": "Commit a dry-run import",
        "description": "Scope: `contacts:write`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportCommitInput"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Committing",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Import"
                }
              }
            },
            "links": {
              "getImport": {
                "operationId": "getImport",
                "description": "Poll it (waiters: dryRunReady, completed)",
                "parameters": {
                  "id": "$response.body#/id"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "`entitlement_inactive`: The subscription ended and the grace period is over. Unsubscribe, erasure, export and reads keep working.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`not_ready`: The import isn't ready to commit yet.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "imports",
          "method": "commit"
        },
        "x-idempotency": "key-optional"
      }
    },
    "/exports": {
      "get": {
        "operationId": "listExports",
        "tags": [
          "Exports"
        ],
        "summary": "List exports",
        "description": "Newest first.\n\nScope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "schema": {
              "$ref": "#/components/schemas/ExportKind"
            },
            "required": false,
            "description": "Filter by kind",
            "name": "kind",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of exports",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "exports",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      },
      "post": {
        "operationId": "createExport",
        "tags": [
          "Exports"
        ],
        "summary": "Start an export",
        "description": "Writes to your own exports bucket. contact_data exports one contact's data (a GDPR access request).\n\nScope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportInput"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Running",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this is the stored response to an earlier request"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Export"
                }
              }
            },
            "links": {
              "getExport": {
                "operationId": "getExport",
                "description": "Poll it (waiters: ready)",
                "parameters": {
                  "id": "$response.body#/id"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.\n\n`idempotency_conflict`: The Idempotency-Key was used with a different request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "exports",
          "method": "create"
        },
        "x-idempotency": "key-optional"
      }
    },
    "/exports/{id}": {
      "get": {
        "operationId": "getExport",
        "tags": [
          "Exports"
        ],
        "summary": "Get an export and its download link",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The export",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Export"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "exports",
          "method": "get"
        },
        "x-idempotency": "safe",
        "x-waiters": {
          "ready": {
            "description": "The export is written and downloadUrl is set",
            "delaySeconds": 5,
            "maxAttempts": 720,
            "acceptors": [
              {
                "path": "state",
                "expected": "ready",
                "state": "success"
              },
              {
                "path": "state",
                "expected": "failed",
                "state": "failure"
              }
            ]
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "Health"
        ],
        "summary": "Check setup and sending health",
        "description": "Returns 200 even when ok is false; each failing check says how to fix it.\n\nAny valid credential.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Health checks",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "health",
          "method": "get"
        },
        "x-idempotency": "safe",
        "x-waiters": {
          "healthy": {
            "description": "Every setup and sending check passes (DNS can take a while to spread)",
            "delaySeconds": 30,
            "maxAttempts": 240,
            "acceptors": [
              {
                "path": "ok",
                "expected": true,
                "state": "success"
              }
            ]
          }
        }
      }
    },
    "/setup/verify": {
      "post": {
        "operationId": "verifySetup",
        "tags": [
          "Setup"
        ],
        "summary": "Connect the installed template",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Health after connecting",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            },
            "links": {
              "getHealth": {
                "operationId": "getHealth",
                "description": "Poll it (waiters: healthy)"
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`stack_not_found`: The tenant template stack wasn't found in the registered account and Region.\n\n`role_assume_failed`: Our service couldn't assume the tenant role with the issued external ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "setup",
          "method": "verify"
        },
        "x-idempotency": "safe"
      }
    },
    "/setup/domains": {
      "post": {
        "operationId": "setDomains",
        "tags": [
          "Domains"
        ],
        "summary": "Set the tracking domain and an optional custom API domain",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DomainsInput"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Certificates requested; add the validation records",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Domains"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "domains",
          "method": "set"
        },
        "x-idempotency": "safe"
      },
      "get": {
        "operationId": "getDomains",
        "tags": [
          "Domains"
        ],
        "summary": "Get domain and certificate status",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Domains",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Domains"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "domains",
          "method": "get"
        },
        "x-idempotency": "safe"
      }
    },
    "/settings": {
      "get": {
        "operationId": "getSettings",
        "tags": [
          "Settings"
        ],
        "summary": "Get settings",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Settings",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settings"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "settings",
          "method": "get"
        },
        "x-idempotency": "safe"
      },
      "patch": {
        "operationId": "updateSettings",
        "tags": [
          "Settings"
        ],
        "summary": "Update settings",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettingsPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              },
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "The resource version, quoted; send it back in If-Match"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settings"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "412": {
            "description": "`version_conflict`: If-Match doesn't match the resource's current version.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "settings",
          "method": "update"
        },
        "x-idempotency": "safe"
      }
    },
    "/keys": {
      "post": {
        "operationId": "createApiKey",
        "tags": [
          "API keys"
        ],
        "summary": "Create an API key",
        "description": "The secret is returned once.\n\nScope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created, with secret",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "`validation_failed`: The request body or parameters are invalid. See errors[].",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "keys",
          "method": "create"
        },
        "x-idempotency": "unsafe"
      },
      "get": {
        "operationId": "listApiKeys",
        "tags": [
          "API keys"
        ],
        "summary": "List API keys",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of keys (no secrets)",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyPage"
                }
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "keys",
          "method": "list"
        },
        "x-idempotency": "safe",
        "x-pagination": {
          "type": "cursor",
          "limitParam": "limit",
          "cursorParam": "cursor",
          "itemsField": "data",
          "nextCursorField": "nextCursor"
        }
      }
    },
    "/keys/{id}": {
      "delete": {
        "operationId": "revokeApiKey",
        "tags": [
          "API keys"
        ],
        "summary": "Revoke an API key",
        "description": "Scope: `admin`.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            }
          },
          "400": {
            "description": "`bad_request`: Malformed JSON or headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "`unauthenticated`: The credential is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "`forbidden`: The credential doesn't carry the scope this endpoint needs.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: No such resource in this tenant, or an invalid token.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`tenant_disconnected`: The tenant's role or stack is unavailable. Check /health.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "421": {
            "description": "`wrong_region`: This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Too many requests. Retry after the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "`internal`: Something went wrong on our side. Quote requestId to support.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "`dependency_unavailable`: An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "keys",
          "method": "revoke"
        },
        "x-idempotency": "safe"
      }
    },
    "/u/{token}": {
      "get": {
        "operationId": "unsubscribePage",
        "tags": [
          "Public"
        ],
        "summary": "Unsubscribe confirmation page",
        "description": "Shows a button. A GET never unsubscribes (link scanners open every link).\n\nNo authentication.",
        "security": [],
        "servers": [
          {
            "url": "https://api.rhinorelay.com"
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1024
            },
            "required": true,
            "name": "token",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmation page",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Invalid link page",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "public",
          "method": "unsubscribePage"
        },
        "x-idempotency": "safe"
      },
      "post": {
        "operationId": "unsubscribeOneClick",
        "tags": [
          "Public"
        ],
        "summary": "Unsubscribe (one-click or the page's button)",
        "description": "RFC 8058 one-click: body List-Unsubscribe=One-Click. Unsubscribes immediately.\n\nNo authentication.",
        "security": [],
        "servers": [
          {
            "url": "https://api.rhinorelay.com"
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1024
            },
            "required": true,
            "name": "token",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "List-Unsubscribe": {
                    "type": "string",
                    "enum": [
                      "One-Click"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Unsubscribed page",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Invalid link page",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "public",
          "method": "unsubscribeOneClick"
        },
        "x-idempotency": "safe"
      }
    },
    "/oauth/mailchimp/callback": {
      "get": {
        "operationId": "mailchimpCallback",
        "tags": [
          "Public"
        ],
        "summary": "Mailchimp OAuth redirect",
        "description": "Mailchimp redirects here after the user approves access. The token is written straight to the tenant's SSM.\n\nNo authentication.",
        "security": [],
        "servers": [
          {
            "url": "https://api.rhinorelay.com"
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "required": false,
            "name": "code",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1024
            },
            "required": true,
            "name": "state",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "error",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Connected page",
            "headers": {
              "x-request-id": {
                "schema": {
                  "type": "string"
                },
                "description": "Request ID"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-client": {
          "group": "public",
          "method": "mailchimpCallback"
        },
        "x-idempotency": "safe"
      }
    }
  },
  "webhooks": {},
  "x-sigv4": {
    "description": "Instead of an API key, IAM principals in your own AWS account can sign requests with AWS Signature Version 4 (service lambda), sent to your Region's SigV4 endpoint. Every operation works the same way there. Sign with the AWS SDK's signer.",
    "url": "https://{urlId}.lambda-url.{region}.on.aws/v1",
    "service": "lambda",
    "docs": "https://docs.rhinorelay.com/api/authentication/#sigv4-from-your-aws-account"
  },
  "x-error-codes": {
    "bad_request": {
      "status": 400,
      "title": "Bad request",
      "description": "Malformed JSON or headers.",
      "type": "https://docs.rhinorelay.com/api/errors/bad-request/"
    },
    "unauthenticated": {
      "status": 401,
      "title": "Unauthenticated",
      "description": "The credential is missing or invalid.",
      "type": "https://docs.rhinorelay.com/api/errors/unauthenticated/"
    },
    "entitlement_inactive": {
      "status": 402,
      "title": "Entitlement inactive",
      "description": "The subscription ended and the grace period is over. Unsubscribe, erasure, export and reads keep working.",
      "type": "https://docs.rhinorelay.com/api/errors/entitlement-inactive/"
    },
    "forbidden": {
      "status": 403,
      "title": "Forbidden",
      "description": "The credential doesn't carry the scope this endpoint needs.",
      "type": "https://docs.rhinorelay.com/api/errors/forbidden/"
    },
    "not_found": {
      "status": 404,
      "title": "Not found",
      "description": "No such resource in this tenant, or an invalid token.",
      "type": "https://docs.rhinorelay.com/api/errors/not-found/"
    },
    "tenant_disconnected": {
      "status": 409,
      "title": "Tenant disconnected",
      "description": "The tenant's role or stack is unavailable. Check /health.",
      "type": "https://docs.rhinorelay.com/api/errors/tenant-disconnected/"
    },
    "contact_suppressed": {
      "status": 409,
      "title": "Contact suppressed",
      "description": "The address is unsubscribed, bounced, complained, cleaned or erased.",
      "type": "https://docs.rhinorelay.com/api/errors/contact-suppressed/"
    },
    "email_taken": {
      "status": 409,
      "title": "Email taken",
      "description": "Another contact already has this address.",
      "type": "https://docs.rhinorelay.com/api/errors/email-taken/"
    },
    "cannot_resubscribe": {
      "status": 409,
      "title": "Cannot resubscribe",
      "description": "Bounced, complained and cleaned contacts can't be resubscribed.",
      "type": "https://docs.rhinorelay.com/api/errors/cannot-resubscribe/"
    },
    "segment_in_use": {
      "status": 409,
      "title": "Segment in use",
      "description": "A draft, scheduled or sending campaign uses this segment.",
      "type": "https://docs.rhinorelay.com/api/errors/segment-in-use/"
    },
    "not_draft": {
      "status": 409,
      "title": "Not a draft",
      "description": "Only draft campaigns can change or be deleted.",
      "type": "https://docs.rhinorelay.com/api/errors/not-draft/"
    },
    "invalid_state": {
      "status": 409,
      "title": "Invalid state",
      "description": "The campaign's state doesn't allow this action.",
      "type": "https://docs.rhinorelay.com/api/errors/invalid-state/"
    },
    "quota_reserve_exhausted": {
      "status": 409,
      "title": "Quota reserve exhausted",
      "description": "Test sends would exceed the daily quota reserve.",
      "type": "https://docs.rhinorelay.com/api/errors/quota-reserve-exhausted/"
    },
    "not_ready": {
      "status": 409,
      "title": "Not ready",
      "description": "The import isn't ready to commit yet.",
      "type": "https://docs.rhinorelay.com/api/errors/not-ready/"
    },
    "already_committed": {
      "status": 409,
      "title": "Already committed",
      "description": "The import has already been committed.",
      "type": "https://docs.rhinorelay.com/api/errors/already-committed/"
    },
    "idempotency_conflict": {
      "status": 409,
      "title": "Idempotency conflict",
      "description": "The Idempotency-Key was used with a different request.",
      "type": "https://docs.rhinorelay.com/api/errors/idempotency-conflict/"
    },
    "version_conflict": {
      "status": 412,
      "title": "Version conflict",
      "description": "If-Match doesn't match the resource's current version.",
      "type": "https://docs.rhinorelay.com/api/errors/version-conflict/"
    },
    "batch_too_large": {
      "status": 413,
      "title": "Batch too large",
      "description": "Over 1,000 items or 1 MB.",
      "type": "https://docs.rhinorelay.com/api/errors/batch-too-large/"
    },
    "validation_failed": {
      "status": 422,
      "title": "Validation failed",
      "description": "The request body or parameters are invalid. See errors[].",
      "type": "https://docs.rhinorelay.com/api/errors/validation-failed/"
    },
    "consent_required": {
      "status": 422,
      "title": "Consent required",
      "description": "Subscribed contacts need a consent record.",
      "type": "https://docs.rhinorelay.com/api/errors/consent-required/"
    },
    "segment_invalid": {
      "status": 422,
      "title": "Segment invalid",
      "description": "The segment definition is invalid (over 3 levels, over 50 conditions, or an unknown operator).",
      "type": "https://docs.rhinorelay.com/api/errors/segment-invalid/"
    },
    "template_invalid": {
      "status": 422,
      "title": "Template invalid",
      "description": "The template is missing {{ unsubscribe_url }} or {{ footer_address }}, doesn't parse, or is over 380 KB.",
      "type": "https://docs.rhinorelay.com/api/errors/template-invalid/"
    },
    "from_domain_unverified": {
      "status": 422,
      "title": "From domain unverified",
      "description": "fromEmail must be on the tenant's verified sending domain.",
      "type": "https://docs.rhinorelay.com/api/errors/from-domain-unverified/"
    },
    "render_failed": {
      "status": 422,
      "title": "Render failed",
      "description": "The template failed to render with the given contact or sample.",
      "type": "https://docs.rhinorelay.com/api/errors/render-failed/"
    },
    "schedule_checks_failed": {
      "status": 422,
      "title": "Schedule checks failed",
      "description": "One or more pre-send checks failed. See errors[] for each check and its fix.",
      "type": "https://docs.rhinorelay.com/api/errors/schedule-checks-failed/"
    },
    "acknowledge_mismatch": {
      "status": 422,
      "title": "Acknowledge mismatch",
      "description": "Resume needs acknowledge equal to the campaign's pauseReason.",
      "type": "https://docs.rhinorelay.com/api/errors/acknowledge-mismatch/"
    },
    "mailchimp_auth_failed": {
      "status": 422,
      "title": "Mailchimp authentication failed",
      "description": "Mailchimp rejected the API key or OAuth grant.",
      "type": "https://docs.rhinorelay.com/api/errors/mailchimp-auth-failed/"
    },
    "stack_not_found": {
      "status": 422,
      "title": "Stack not found",
      "description": "The tenant template stack wasn't found in the registered account and Region.",
      "type": "https://docs.rhinorelay.com/api/errors/stack-not-found/"
    },
    "role_assume_failed": {
      "status": 422,
      "title": "Role assume failed",
      "description": "Our service couldn't assume the tenant role with the issued external ID.",
      "type": "https://docs.rhinorelay.com/api/errors/role-assume-failed/"
    },
    "wrong_region": {
      "status": 421,
      "title": "Wrong Region",
      "description": "This tenant's data lives in another Region. Call https://api.<region>.rhinorelay.com (the console's Setup page shows your API host).",
      "type": "https://docs.rhinorelay.com/api/errors/wrong-region/"
    },
    "rate_limited": {
      "status": 429,
      "title": "Rate limited",
      "description": "Too many requests. Retry after the Retry-After header.",
      "type": "https://docs.rhinorelay.com/api/errors/rate-limited/"
    },
    "internal": {
      "status": 500,
      "title": "Internal error",
      "description": "Something went wrong on our side. Quote requestId to support.",
      "type": "https://docs.rhinorelay.com/api/errors/internal/"
    },
    "dependency_unavailable": {
      "status": 503,
      "title": "Dependency unavailable",
      "description": "An AWS dependency is unavailable. Retry with the same Idempotency-Key.",
      "type": "https://docs.rhinorelay.com/api/errors/dependency-unavailable/"
    }
  }
}
