{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/bangermail-com/json-schema/bangermail-com-journey-input-schema.json",
  "title": "JourneyInput",
  "x-generated": "2026-11-02",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/bangermail-com-openapi.json#/components/schemas/JourneyInput",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "name",
    "trigger",
    "steps"
  ],
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "description": {
      "type": "string",
      "maxLength": 2000
    },
    "mailbox_id": {
      "type": "string",
      "format": "uuid",
      "description": "Existing sender. Omit to prefer the onboarding sender then an active custom mailbox then hosted. Saved and explicit senders remain unchanged."
    },
    "from_local_part": {
      "type": "string",
      "maxLength": 64,
      "pattern": "^[a-z0-9][a-z0-9._+-]{0,62}$"
    },
    "trigger": {
      "type": "object",
      "required": [
        "kind"
      ],
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "manual",
            "contact_created",
            "audience_joined",
            "event",
            "schedule",
            "inbound_email",
            "email_replied",
            "api"
          ]
        },
        "connection_id": {
          "type": "string",
          "format": "uuid"
        },
        "config": {
          "type": "object",
          "additionalProperties": true,
          "properties": {
            "event": {
              "type": "string"
            },
            "every": {
              "type": "integer",
              "minimum": 1,
              "maximum": 366,
              "default": 1,
              "description": "For schedule triggers, calendar interval from the activation-local date."
            },
            "unit": {
              "type": "string",
              "enum": [
                "days",
                "weeks",
                "months"
              ],
              "default": "weeks",
              "description": "For schedule triggers. Months clamp to the last day without changing the original anchor day."
            },
            "time": {
              "type": "string",
              "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
              "default": "09:00",
              "description": "Schedule wall-clock time. The first occurrence is strictly after activation; DST gaps are skipped and repeated wall times run once."
            },
            "timezone": {
              "type": "string",
              "default": "UTC",
              "description": "IANA zone for schedule triggers. Only the latest due occurrence is recovered after downtime; times missed while paused are skipped. Trigger conditions must be empty; select contacts with audience. Normal review, suppression and re-entry rules still apply."
            },
            "once_per_person": {
              "type": "boolean",
              "default": true,
              "description": "Each person enters once. Set false to let people re-enter after they finish."
            },
            "reentry_days": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "description": "With once_per_person false, days after a person's last entry before they may enter again."
            }
          }
        },
        "conditions": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": true
          }
        }
      }
    },
    "audience": {
      "type": "object",
      "additionalProperties": true
    },
    "goal": {
      "$ref": "#/$defs/JourneyGoal"
    },
    "exit": {
      "$ref": "#/$defs/JourneyExit"
    },
    "approval_mode": {
      "type": "string",
      "enum": [
        "policy",
        "required"
      ]
    },
    "api": {
      "type": "object",
      "properties": {
        "key": {
          "type": "string",
          "maxLength": 100
        },
        "content_mode": {
          "type": "string",
          "enum": [
            "code",
            "managed"
          ]
        },
        "identity": {
          "type": "string",
          "maxLength": 300
        }
      }
    },
    "managed_content": {
      "$ref": "#/$defs/ManagedContentContract",
      "description": "Create-only shortcut: atomically save a source-managed email draft and a Journey whose email step references it. Missing target languages queue for free translation; this does not publish or activate the Journey."
    },
    "steps": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "$ref": "#/$defs/JourneyStep"
      }
    }
  },
  "$defs": {
    "JourneyArm": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "key",
        "label",
        "allocation",
        "steps"
      ],
      "properties": {
        "key": {
          "type": "string",
          "enum": [
            "A",
            "B",
            "C",
            "D"
          ]
        },
        "label": {
          "type": "string",
          "maxLength": 120
        },
        "allocation": {
          "type": "number",
          "minimum": 0,
          "maximum": 100
        },
        "steps": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/JourneyStep"
          }
        }
      }
    },
    "JourneyExit": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "on_reply": {
          "type": "boolean",
          "default": true
        },
        "on_unsubscribe": {
          "type": "boolean",
          "default": true
        },
        "on_suppression": {
          "type": "boolean",
          "default": true
        },
        "event": {
          "type": "string",
          "maxLength": 200
        }
      }
    },
    "JourneyGoal": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "kind",
        "config"
      ],
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "none",
            "event",
            "reply",
            "conversion"
          ]
        },
        "connection_id": {
          "type": "string",
          "format": "uuid"
        },
        "config": {
          "type": "object",
          "additionalProperties": true
        }
      }
    },
    "JourneyStep": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "kind",
        "name",
        "config"
      ],
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid"
        },
        "position": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        },
        "kind": {
          "type": "string",
          "enum": [
            "email",
            "wait",
            "condition",
            "action",
            "split"
          ]
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "managed_content": {
          "type": "object",
          "readOnly": true,
          "description": "Typed source contract and draft/published revision identity for an email step.",
          "properties": {
            "id": {
              "type": "string",
              "format": "uuid"
            },
            "version": {
              "type": "integer"
            },
            "draft_revision_id": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "published_revision_id": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "published_publication_id": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "source_revision_id": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "layout_revision_id": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "published_layout_revision_id": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "source_locale": {
              "type": [
                "string",
                "null"
              ]
            },
            "configured_locales": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "variables": {
              "type": "object",
              "additionalProperties": true
            },
            "published_variables": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "config": {
          "type": "object",
          "additionalProperties": true,
          "description": "Wait steps optionally accept until with name, path, operator (equals, not_equals, contains, or exists), and value, plus required on_met (continue or end_journey). continue skips the following reminder email; end_journey completes the Journey. A reminder email must immediately follow in the same branch. The wait checks current customer data every minute up to amount/unit. Missing fields are unknown and hold the reminder. Ordinary waits and standalone conditions retain their existing behavior. Name checks with verified customer milestones. Managed email steps reference the published content through managed_content_id; activation rejects an unpublished reference. Every email step sets delivery_class: product (transactional email, such as receipts and account mail) or broadcast (marketing, which carries an unsubscribe link and needs the product Brand's company name and mailing address); a step without it is refused with 400 journey_delivery_class_required. Email steps may set expires_after_seconds (1-604800) to discard a deferred send after that interval from its original start; the default is seven days."
        },
        "arms": {
          "type": "array",
          "minItems": 2,
          "maxItems": 4,
          "items": {
            "$ref": "#/$defs/JourneyArm"
          }
        }
      }
    },
    "ManagedContentContract": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "source"
      ],
      "properties": {
        "source_locale": {
          "type": "string",
          "description": "Canonical BCP 47 source locale; inherits product settings when omitted."
        },
        "configured_locales": {
          "type": "array",
          "maxItems": 100,
          "uniqueItems": true,
          "description": "Source plus target locales; omitted source is added by the server.",
          "items": {
            "type": "string"
          }
        },
        "fallback_locale": {
          "type": "string"
        },
        "layout_id": {
          "type": "string",
          "format": "uuid",
          "description": "Selected reusable layout; the server snapshots its published revision into this content revision."
        },
        "localization_policy": {
          "type": "object",
          "additionalProperties": false,
          "description": "A Journey email goes out only in the person's own language: it waits for their translation, about a minute for receipts, codes and security notices and up to a day for other email, and is not sent if the translation is not ready by then.",
          "properties": {
            "manual_review": {
              "type": "boolean",
              "default": false
            }
          }
        },
        "source": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "subject",
            "body_html",
            "variables"
          ],
          "properties": {
            "subject": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100000
            },
            "preheader": {
              "type": "string",
              "maxLength": 100000
            },
            "body_text": {
              "type": "string",
              "maxLength": 100000,
              "description": "Accepted for source compatibility; rendered plain text derives from final HTML."
            },
            "body_html": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100000
            },
            "layout": {
              "type": "string",
              "maxLength": 100000,
              "description": "Must contain one {{ content }} slot."
            },
            "variants": {
              "type": "object",
              "minProperties": 2,
              "maxProperties": 4,
              "description": "Optional source versions. Every version is translated automatically in the same revision.",
              "additionalProperties": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "subject",
                  "body_html"
                ],
                "properties": {
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100000
                  },
                  "preheader": {
                    "type": "string",
                    "maxLength": 100000
                  },
                  "body_html": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100000
                  },
                  "body_text": {
                    "type": "string",
                    "maxLength": 100000
                  },
                  "layout": {
                    "type": "string",
                    "maxLength": 100000
                  }
                }
              }
            },
            "variables": {
              "type": "object",
              "maxProperties": 100,
              "additionalProperties": {
                "$ref": "#/$defs/ManagedContentField"
              }
            }
          }
        },
        "samples": {
          "type": "object",
          "description": "Named sample value sets for preview and source validation.",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "translations": {
          "type": "object",
          "description": "Source ICU message catalog and optional supplied target catalogs. Missing configured targets are queued for asynchronous translation; saving does not require them.",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      }
    },
    "ManagedContentField": {
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "type"
          ],
          "properties": {
            "type": {
              "type": "string",
              "enum": [
                "string",
                "text",
                "url",
                "image_url",
                "html",
                "date",
                "datetime",
                "number",
                "boolean",
                "money"
              ]
            },
            "required": {
              "type": "boolean"
            },
            "description": {
              "type": "string",
              "maxLength": 2000
            },
            "default": {
              "description": "Must match the field type."
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "type",
            "properties"
          ],
          "properties": {
            "type": {
              "const": "object"
            },
            "required": {
              "type": "boolean"
            },
            "description": {
              "type": "string",
              "maxLength": 2000
            },
            "default": {
              "type": "object"
            },
            "properties": {
              "type": "object",
              "additionalProperties": {
                "$ref": "#/$defs/ManagedContentField"
              }
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "type",
            "items"
          ],
          "properties": {
            "type": {
              "const": "list"
            },
            "required": {
              "type": "boolean"
            },
            "description": {
              "type": "string",
              "maxLength": 2000
            },
            "default": {
              "type": "array"
            },
            "items": {
              "$ref": "#/$defs/ManagedContentField"
            }
          }
        }
      ],
      "description": "Recursive typed variable. Money values use {amount_cents: integer, currency: ISO 4217 code}; date values are ISO calendar dates and datetime values are ISO timestamps with offsets."
    }
  }
}