+func validateValue(payload ValuePayload, kind Kind, metadata Metadata) error {
+ if !json.Valid(payload.Value) {
+ return fmt.Errorf("value is required and must be valid JSON")
+ }
+
+ if kind == Command && metadata.ExpiresAt == nil {
+ return fmt.Errorf("command must have an expiry")
+ }
+
+ return nil
+}
+
+func validateEvent(payload EventPayload) error {
+ if payload == nil {
+ return fmt.Errorf("event must be a JSON object")
+ }
+
+ for _, value := range payload {
+ if value != nil && !json.Valid(value) {
+ return fmt.Errorf("event values must be valid JSON")
+ }
+ }
+
+ return nil
+}
+
+func validateResult(payload ResultPayload, address Address, metadata Metadata) error {
+ if metadata.CorrelationID != address.Target {
+ return fmt.Errorf("result correlation must match its command ID")
+ }
+
+ switch payload.Status {
+ case "accepted", "completed":
+ if payload.Reason != "" {
+ return fmt.Errorf("successful result must not have a reason")
+ }
+ case "rejected", "failed":
+ if payload.Reason == "" {
+ return fmt.Errorf("unsuccessful result must have a reason")
+ }
+ default:
+ return fmt.Errorf("result status is invalid")
+ }
+
+ return nil
+}
+
+func validateBatch(payload BatchPayload, metadata Metadata) error {