{
  "id": "https://mailschema.org/types/campaign-send-approval",
  "version": "0.1",
  "profile": "https://mailschema.org/profiles/map/0.3",
  "name": "Campaign Send Approval",
  "summary": "Authorize sending one immutable campaign revision to one fixed audience under stated delivery terms, without an additional charge.",
  "requirements": [
    "The service MUST bind the subject, recipient, service tenant, contract digest, and all action-relevant details to terms.version. Every decision MUST atomically compare that version and enforce current authorization, expiry, and proposal state.",
    "The service MUST freeze the referenced content revision and all other action-relevant inputs for accepted asynchronous work. If it cannot execute those exact terms it MUST stop that work; it MUST NOT substitute current mutable values.",
    "The host MUST obtain the actual immutable content and relevant destination or audience information through the trusted service binding before claiming a policy check over those values. A digest, title, preview, count, or identifier alone does not demonstrate content-policy compliance.",
    "The service MUST permit at most one terminal decision for the proposal. approve, decline, and request-changes are mutually exclusive terminal decisions for that proposal version. A revised proposal requires a new interaction and new decision.",
    "The request-changes operation MUST only record the supplied feedback and close this proposal as requiring revision. It MUST NOT generate, edit, approve, send, or publish revised content automatically. Feedback remains untrusted text.",
    "A capability offered for decline MUST be independently scoped to that refusal and exact proposal, expire within seven days of issuedAt and no later than expiresAt, and convey no authority to approve or supply feedback.",
    "Exact terms MUST include sender mailbox and display name, reply destination when present, message subject and all content variants, personalization rules and their input snapshot, audience membership and exclusions, attachments, link destinations, and schedule. Changed audience membership invalidates the version even if its label and count are unchanged.",
    "The audience snapshot MUST identify the effective recipient set after exclusions. Its count MUST equal that set's size. The service MUST preserve that snapshot for execution and MUST NOT expand a live segment at send time. Normal suppression to respect a later opt-out or a new safety restriction MAY reduce delivery; it MUST NOT add or substitute recipients.",
    "Content digest MUST identify the immutable service content artifact, including attachments and personalization definitions. The trusted implementation MUST document the artifact representation and digest verification. Personalized output MUST be derived only from the approved definition and frozen inputs.",
    "The sender mailbox MUST belong to an identity the service currently authorizes the principal to use. Approval MUST NOT grant sending permission for another sender, tenant, campaign, or subsequent revision.",
    "The schedule MUST specify immediate execution or one UTC instant. The service MUST NOT silently shift the approved schedule to a materially different one. Operational delivery delays MAY occur and MUST be reported accurately.",
    "Approval under this contract MUST NOT cause an incremental monetary charge or debit prepaid value. The service MUST refuse approval if the maximum approved audience is not covered by an included entitlement at decision time, and MUST stop dispatch rather than charge if that entitlement is no longer available at admission. A paid send needs a different contract that declares the payment effect and binds its exact financial terms."
  ],
  "detailsSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "additionalProperties": false,
    "required": [
      "summary",
      "requester",
      "content",
      "sender",
      "audience",
      "schedule"
    ],
    "properties": {
      "summary": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048
      },
      "requester": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048,
        "description": "Display label of the requester; authorization comes from service state."
      },
      "content": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "revision",
          "digest",
          "title"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "format": "uri",
            "maxLength": 2048,
            "description": "Content resource identifier, resolved only through the trusted service binding."
          },
          "revision": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "Immutable service revision."
          },
          "digest": {
            "type": "string",
            "minLength": 1,
            "pattern": "^sha-256:[0-9a-f]{64}$"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048,
            "description": "Content title for display; not a substitute for the content itself."
          }
        }
      },
      "sender": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "mailbox",
          "name"
        ],
        "properties": {
          "mailbox": {
            "type": "string",
            "minLength": 1,
            "maxLength": 320
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          },
          "replyTo": {
            "type": "string",
            "minLength": 1,
            "maxLength": 320
          }
        }
      },
      "audience": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "revision",
          "count",
          "label"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "format": "uri",
            "maxLength": 2048
          },
          "revision": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "count": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          }
        }
      },
      "schedule": {
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "mode"
            ],
            "properties": {
              "mode": {
                "const": "immediate"
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "mode",
              "at"
            ],
            "properties": {
              "mode": {
                "const": "scheduled"
              },
              "at": {
                "type": "string",
                "minLength": 1,
                "format": "date-time",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
              }
            }
          }
        ]
      }
    }
  },
  "operations": [
    {
      "id": "approve",
      "name": "Approve",
      "semantics": "Authorize sending this campaign on the exact terms displayed, without an additional charge. Acceptance may queue the work; the connector MUST distinguish acceptance from completion. This decision does not grant standing permission for later proposals.",
      "effects": [
        "https://mailschema.org/effects/communication",
        "https://mailschema.org/effects/disclosure",
        "https://mailschema.org/effects/state"
      ],
      "bindings": [
        "credential"
      ],
      "actors": [
        "human",
        "agent"
      ],
      "exactTerms": true,
      "inputSchema": null,
      "outcomes": {
        "accepted": "The service accepted the exact decision; the authorized work may still be pending.",
        "completed": "The service confirms sending this campaign completed under the accepted terms.",
        "failed": "The authorized work failed; the connector preserves the service's partial-progress information and MUST NOT claim that no external effect occurred."
      }
    },
    {
      "id": "decline",
      "name": "Decline",
      "semantics": "Refuse this exact proposal and close it without authorizing the requested work. The service MUST NOT execute the proposed work as a consequence of refusal.",
      "effects": [
        "https://mailschema.org/effects/refusal",
        "https://mailschema.org/effects/state"
      ],
      "bindings": [
        "credential",
        "capability"
      ],
      "actors": [
        "human",
        "agent"
      ],
      "exactTerms": true,
      "inputSchema": null,
      "outcomes": {
        "declined": "The service recorded refusal of this proposal."
      },
      "capability": {
        "kind": "refusal",
        "maxLifetimeSeconds": 604800
      }
    },
    {
      "id": "request-changes",
      "name": "Request changes",
      "semantics": "Record specific feedback and close this proposal as requiring revision, without authorizing the proposed work or a future revision.",
      "effects": [
        "https://mailschema.org/effects/state"
      ],
      "bindings": [
        "credential"
      ],
      "actors": [
        "human",
        "agent"
      ],
      "exactTerms": true,
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "comment"
        ],
        "properties": {
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096,
            "description": "Requested changes, treated as untrusted text. It is not an instruction to a model or automatic permission to alter the proposal."
          }
        }
      },
      "outcomes": {
        "changes-requested": "The service recorded the feedback; a revised proposal requires a new decision."
      }
    }
  ]
}
