diff --git a/audit/audit.go b/audit/audit.go
index 6146f093cf995d81a78bb134a07b1ee7c03f07d9..29dce84bd87ed7b66cb559d30d21096e4ad3678a 100644
--- a/audit/audit.go
+++ b/audit/audit.go
@@ -1,13 +1,15 @@
 package audit
 
 import (
-	"reflect"
-	"regexp"
-	"strings"
-
+	"encoding/json"
+	"fmt"
 	"github.com/r3labs/diff/v2"
 	"gitlab.com/uafrica/go-utils/reflection"
 	"gitlab.com/uafrica/go-utils/string_utils"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
 )
 
 type FieldChange struct {
@@ -105,7 +107,173 @@ func GetChanges(original interface{}, new interface{}) (map[string]interface{},
 					fieldChange,
 				}
 			}
+		} else if len(change.Path) > 1 {
+
+			objectKey := ToSnakeCase(change.Path[0])
+			for i := 1; i < len(change.Path)-1; i++ {
+				objectKey = fmt.Sprintf("%s-%s", objectKey, ToSnakeCase(change.Path[i]))
+			}
+
+			field := ToSnakeCase(change.Path[len(change.Path)-1])
+			changesKey := fmt.Sprintf("%s-%s", objectKey, field)
+
+			// Create array of objects
+			fieldChange := map[string]interface{}{
+				field: FieldChange{
+					From: change.From,
+					To:   change.To,
+				},
+			}
+			changes[changesKey] = []map[string]interface{}{
+				fieldChange,
+			}
+		}
+
+	}
+
+	return changes, nil
+}
+
+// GetAllChanges Returns the diff, structured in json, recursively
+// Be warned, here be dragons. Debug this first to understand how it works
+func GetAllChanges(original interface{}, new interface{}) (map[string]interface{}, error) {
+	changes := map[string]interface{}{}
+	changelog, err := diff.Diff(original, new)
+	if err != nil {
+		return changes, err
+	}
+
+	changesJson := "{"
+	subArrays := map[string]string{}
+	for _, change := range changelog {
+		var value string   // Keep track of the core value
+		var key string     // Keep track of the key/s for this value
+		var closing string // Keep track of the correct number of closing characters
+
+		for pathIndex := len(change.Path) - 1; pathIndex >= 0; pathIndex-- {
+			// If this is the first value, it's the "deepest" value of this change set, otherwise leave this var alone
+			// If this is set at the wrong point, other behaviour changes
+			if pathIndex+1 == len(change.Path) {
+				changedField := FieldChange{
+					From: change.From,
+					To:   change.To,
+				}
+				request, err := json.Marshal(changedField)
+				if err != nil {
+					return nil, err
+				}
+				value = string(request)
+				value = value[1 : len(value)-1]
+			}
+
+			// If this "key" is integer-like, we handle it a little differently to ensure related data ends up
+			// together and formatted as you would expect JSON arrays to look
+			if _, err = strconv.Atoi(change.Path[pathIndex]); err == nil {
+				positionOfSubArray := ""
+				for sub := 0; sub <= pathIndex; sub++ {
+					positionOfSubArray = positionOfSubArray + change.Path[sub]
+				}
+
+				// Add it to the placeholder data map used later on
+				subArrays[positionOfSubArray] = subArrays[positionOfSubArray] + key + value + closing + ","
+
+				// Don't insert the same placeholder into the json multiple times
+				if !strings.Contains(changesJson, positionOfSubArray) {
+					value = positionOfSubArray
+				} else {
+					// Make sure this value doesn't end up populated explicitly
+					value = ""
+				}
+			} else {
+				// Safety net so we don't compare to a non existant value
+				if pathIndex < len(change.Path)-1 {
+					// If the value this one "contains" has a integer-like key, this is probably an array
+					if _, err = strconv.Atoi(change.Path[pathIndex+1]); err == nil {
+						key = "\"" + ToSnakeCase(change.Path[pathIndex]) + "\": ["
+						closing = "]"
+					} else {
+						key = "\"" + ToSnakeCase(change.Path[pathIndex]) + "\": {" + key
+						closing = closing + "}"
+					}
+				} else {
+					key = "\"" + ToSnakeCase(change.Path[pathIndex]) + "\": {" + key
+					closing = closing + "}"
+				}
+			}
+		}
+
+		// Don't insert empty values (happens when multiple values within an array are set, see "placeholder" behavior)
+		if value != "" {
+			// Duplicate key prevention
+			keySplit := strings.Split(key, ": ")
+			lastOccurrence := 0
+			lastMatched := ""
+			levelsDeep := 0
+			for sIndex, split := range keySplit {
+				// Trim leading character off split
+				if split[0:1] == "{" || split[0:1] == "[" {
+					split = split[1:]
+				}
+
+				// The final value of keySplit might be empty ("")
+				if split != "" {
+					if index := strings.Index(changesJson, split); index > -1 && changesJson != "{" {
+						// Prevent reverse traversal
+						if index > lastOccurrence {
+							lastOccurrence = index
+							lastMatched = split
+							levelsDeep = sIndex
+						}
+					}
+				}
+			}
+
+			// If the "key" is already present, handle it differently
+			if lastOccurrence > 0 {
+				// Strip parent keys that are already present
+				key = key[strings.Index(key, lastMatched)+len(lastMatched):]
+				if key[0:2] == ": " {
+					key = key[2:]
+				}
+				// Strip the correct amount of closing tags
+				closing = closing[:len(closing)-levelsDeep]
+
+				// Find the position of this key in the master string
+				position := strings.Index(changesJson, lastMatched) + len(lastMatched) + 3
+
+				// We're appending to an existing object, so strip the outermost wrapping layer
+				key = key[1:]
+				closing = closing[:len(closing)-1]
+
+				// Place the value within the existing key
+				changesJson = changesJson[:position] + key + value + closing + ", " + changesJson[position:]
+			} else {
+				// No value found, append it to the end
+				changesJson = changesJson + key + value + closing + ", "
+			}
+		}
+	}
+	// Trim whitespace and strip trailing comma since we are done inserting at the back
+	changesJson = strings.TrimSpace(changesJson)
+	if changesJson[len(changesJson)-1:] == "," {
+		changesJson = changesJson[:len(changesJson)-1]
+	}
+	changesJson = changesJson + "}"
+
+	// Now we can go make sure the placeholders are populated with the data in
+	for placeholderKey, placeholderValue := range subArrays {
+		// Trim the trailing comma since we won't be adding any more stuff
+		placeholderValue = strings.TrimSpace(placeholderValue)
+		if placeholderValue[len(placeholderValue)-1:] == "," {
+			placeholderValue = placeholderValue[:len(placeholderValue)-1]
 		}
+		changesJson = strings.ReplaceAll(changesJson, placeholderKey, "{"+placeholderValue+"}")
+	}
+
+	// Now, hopefully, the json parsing will pass and we have a nicely formatted dataset
+	err = json.Unmarshal([]byte(changesJson), &changes)
+	if err != nil {
+		return nil, err
 	}
 
 	return changes, nil