{
"version": 1,
"rules": [
{
"id": "unique-rule-id",
"scope": "ancestorForbidden",
"severity": "error",
"subjectTypes": ["target_abtest"],
"relatedTypes": ["trigger_start"],
"relatedParams": {"sendTimeOptimization": true},
"message": "A/B testing cannot be used while send-time optimization is enabled"
}
]
}id and a scope. subjectTypes identifies the activity to which the rule applies. Type lists support the wildcard "*", meaning any activity type.error — the operation is rejected until the validation problem is fixed.warning — the operation may continue, but the problem is reported as a validation warning.parent and child{
"id": "email-must-follow-filter",
"scope": "parent",
"effect": "allow",
"subjectTypes": ["action_email"],
"relatedTypes": ["target_filter"],
"passThroughTypes": ["action_delay"]
}parent, passThroughTypes allows the validator to look past transparent activities, such as a delay, when determining the relevant upstream activity.deny rule rejects a matching connection:{
"id": "condition-only-after-email",
"scope": "parent",
"effect": "deny",
"severity": "error",
"subjectTypes": ["target_condition"],
"relatedTypes": ["*"],
"message": "A condition must follow an eligible send activity"
}allow rules take precedence over matching deny rules. If no rule matches, the connection is allowed by default.ancestorRequired{
"id": "send-requires-narrowing",
"scope": "ancestorRequired",
"severity": "error",
"subjectTypes": ["action_email", "action_sms", "action_social"],
"relatedTypes": ["target_filter", "target_condition"],
"requiredIfAncestorTypes": ["trigger_start", "trigger_recurring", "trigger_scheduled_start"],
"message": "A bulk send must have a contact-narrowing activity upstream"
}requiredIfAncestorTypes makes the rule conditional. In the example, narrowing is required only when the send is reachable from a bulk trigger. If omitted, the requirement always applies.ancestorForbidden{
"id": "abtest-forbidden-send-time-optimization",
"scope": "ancestorForbidden",
"severity": "error",
"subjectTypes": ["target_abtest"],
"relatedTypes": ["trigger_start", "trigger_recurring", "trigger_scheduled_start"],
"relatedParams": {"sendTimeOptimization": true},
"message": "A/B testing cannot be used while send-time optimization is enabled"
}relatedParams is an optional predicate on the matching upstream activity. Every listed parameter must have exactly the specified value. The upstream activity must match both relatedTypes and relatedParams; a matching activity type with a different value does not violate the rule.sendTimeOptimization set to true. A value of false or an omitted value does not match this predicate.subjectParams is the equivalent predicate for the subject activity itself:{
"id": "open-filter-after-email",
"scope": "parent",
"effect": "allow",
"subjectTypes": ["target_condition"],
"subjectParams": {"filter": "open"},
"relatedTypes": ["action_email", "target_abtest"]
}cardinality{
"id": "cardinality-merge",
"scope": "cardinality",
"subjectTypes": ["target_merge"],
"minAncestors": 1,
"maxAncestors": null,
"maxDescendants": 1,
"severity": "error"
}null means unlimited. The first matching cardinality rule is used, so specific rules should precede a wildcard rule.param{
"id": "scheduled-start-datetime-future",
"scope": "param",
"severity": "warning",
"subjectTypes": ["trigger_scheduled_start"],
"field": "startDateTime",
"check": "futureDateTime",
"whenSmartflowState": ["running"],
"message": "The scheduled start must be in the future"
}futureDateTime — the specified value must represent a future date and time. Empty values are skipped.paramPresent — the specified parameter must have a truthy value.whenSmartflowState optionally limits the rule to selected Smartflow states. Without it, the rule applies in every state.flow{
"id": "max-one-start",
"scope": "flow",
"effect": "deny",
"severity": "error",
"check": "maxCountByType",
"types": ["trigger_start"],
"max": 1,
"message": "A Smartflow may contain only one immediate trigger"
}maxCountByType — rejects the flow when the number of matching activities exceeds max.requiresTypePresent — rejects the flow when none of the listed activity types is present.sendTimeOptimization: true.target_filter or target_condition somewhere upstream.target_condition may follow action_email, action_sms, action_social, or target_abtest (through action_delay); for filter="open", the upstream activity must be action_email or target_abtest.message. The placeholders {subjectType} and {relatedType} are replaced with the actual activity types when applicable. If no message is provided, a generic validation message is generated.target_abtest conditiontarget_abtest activity must define params.condition. The value is normalized by trimming whitespace and converting it to lowercase, so the accepted values are:open — evaluate the variants by unique email opens.click — evaluate the variants by unique email clicks.curl --location '/smartflows/validation-rules'{
"version": 0,
"rules": [
{
"id": "string",
"scope": "string",
"effect": "string",
"severity": "string",
"subjectTypes": [
"string"
],
"relatedTypes": [
"string"
],
"property1": "string",
"property2": "string"
}
]
}