Parse json, where the modifying part is in "query".
diff --git a/mapper/mapper.go b/mapper/mapper.go
index 1405b58..15e3984 100644
--- a/mapper/mapper.go
+++ b/mapper/mapper.go
@@ -81,8 +81,8 @@
 	Direction Direction
 }
 
-// ApplyMappings applies the specified mapping rules to a JSON object
-func (m *Mapper) ApplyMappings(mappingID string, opts MappingOptions, jsonData any) (any, error) {
+// ApplyQueryMappings applies the specified mapping rules to a JSON object
+func (m *Mapper) ApplyQueryMappings(mappingID string, opts MappingOptions, jsonData any) (any, error) {
 	// Validate mapping ID
 	if _, exists := m.mappingLists[mappingID]; !exists {
 		return nil, fmt.Errorf("mapping list with ID %s not found", mappingID)
@@ -91,8 +91,32 @@
 	// Get the parsed rules
 	rules := m.parsedRules[mappingID]
 
+	// Check if we have a wrapper object with a "query" field
+	var queryData any
+	var hasQueryWrapper bool
+
+	if jsonMap, ok := jsonData.(map[string]any); ok {
+		if query, exists := jsonMap["query"]; exists {
+			queryData = query
+			hasQueryWrapper = true
+		}
+	}
+
+	// If no query wrapper was found, use the entire input
+	if !hasQueryWrapper {
+		// If the input itself is not a valid query object, return it as is
+		if !isValidQueryObject(jsonData) {
+			return jsonData, nil
+		}
+		queryData = jsonData
+	} else if queryData == nil || !isValidQueryObject(queryData) {
+		// If we have a query wrapper but the query is nil or not a valid object,
+		// return the original data
+		return jsonData, nil
+	}
+
 	// Convert input JSON to AST
-	jsonBytes, err := json.Marshal(jsonData)
+	jsonBytes, err := json.Marshal(queryData)
 	if err != nil {
 		return nil, fmt.Errorf("failed to marshal input JSON: %w", err)
 	}
@@ -168,9 +192,33 @@
 		return nil, fmt.Errorf("failed to parse result JSON: %w", err)
 	}
 
+	// If we had a query wrapper, put the transformed data back in it
+	if hasQueryWrapper {
+		if wrapper, ok := jsonData.(map[string]any); ok {
+			wrapper["query"] = resultData
+			return wrapper, nil
+		}
+	}
+
 	return resultData, nil
 }
 
+// isValidQueryObject checks if the query data is a valid object that can be processed
+func isValidQueryObject(data any) bool {
+	// Check if it's a map
+	queryMap, ok := data.(map[string]any)
+	if !ok {
+		return false
+	}
+
+	// Check if it has the required @type field
+	if _, ok := queryMap["@type"]; !ok {
+		return false
+	}
+
+	return true
+}
+
 // applyFoundryAndLayerOverrides recursively applies foundry and layer overrides to terms
 func applyFoundryAndLayerOverrides(node ast.Node, foundry, layer string) {
 	if node == nil {
diff --git a/mapper/mapper_test.go b/mapper/mapper_test.go
index c84b7a2..74696ec 100644
--- a/mapper/mapper_test.go
+++ b/mapper/mapper_test.go
@@ -204,7 +204,7 @@
 			require.NoError(t, err)
 
 			// Apply mappings
-			result, err := m.ApplyMappings(tt.mappingID, tt.opts, inputData)
+			result, err := m.ApplyQueryMappings(tt.mappingID, tt.opts, inputData)
 			if tt.expectError {
 				assert.Error(t, err)
 				return
@@ -354,7 +354,7 @@
 			err := json.Unmarshal([]byte(tt.input), &inputData)
 			require.NoError(t, err)
 
-			result, err := m.ApplyMappings("test-mapper", MappingOptions{Direction: AtoB}, inputData)
+			result, err := m.ApplyQueryMappings("test-mapper", MappingOptions{Direction: AtoB}, inputData)
 			if tt.expectError {
 				assert.Error(t, err)
 				assert.Equal(t, tt.errorMsg, err.Error())
@@ -366,3 +366,170 @@
 		})
 	}
 }
+
+func TestQueryWrapperMappings(t *testing.T) {
+
+	mappingList := config.MappingList{
+		ID:       "test-wrapper",
+		FoundryA: "opennlp",
+		LayerA:   "orth",
+		FoundryB: "upos",
+		LayerB:   "orth",
+		Mappings: []config.MappingRule{
+			"[opennlp/orth=Baum] <> [opennlp/orth=X]",
+		},
+	}
+
+	// Create a new mapper
+	m, err := NewMapper([]config.MappingList{mappingList})
+	require.NoError(t, err)
+
+	tests := []struct {
+		name        string
+		mappingID   string
+		opts        MappingOptions
+		input       string
+		expected    string
+		expectError bool
+	}{
+		{
+			name:      "Query wrapper case",
+			mappingID: "test-wrapper",
+			opts: MappingOptions{
+				Direction: AtoB,
+			},
+			input: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"collection": {
+					"@type": "koral:doc",
+					"key": "availability",
+					"match": "match:eq",
+					"rewrites": [
+						{
+							"@type": "koral:rewrite",
+							"_comment": "Free corpus access policy has been added.",
+							"editor": "Kustvakt",
+							"operation": "operation:injection",
+							"src": "Kustvakt"
+						}
+					],
+					"type": "type:regex",
+					"value": "CC.*"
+				},
+				"query": {
+					"@type": "koral:token",
+					"wrap": {
+						"@type": "koral:term",
+						"foundry": "opennlp",
+						"key": "Baum",
+						"layer": "orth",
+						"match": "match:eq"
+					}
+				}
+			}`,
+			expected: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"collection": {
+					"@type": "koral:doc",
+					"key": "availability",
+					"match": "match:eq",
+					"rewrites": [
+						{
+							"@type": "koral:rewrite",
+							"_comment": "Free corpus access policy has been added.",
+							"editor": "Kustvakt",
+							"operation": "operation:injection",
+							"src": "Kustvakt"
+						}
+					],
+					"type": "type:regex",
+					"value": "CC.*"
+				},
+				"query": {
+					"@type": "koral:token",
+					"wrap": {
+						"@type": "koral:term",
+						"foundry": "opennlp",
+						"key": "X",
+						"layer": "orth",
+						"match": "match:eq"
+					}
+				}
+			}`,
+		},
+		{
+			name:      "Empty query field",
+			mappingID: "test-wrapper",
+			opts: MappingOptions{
+				Direction: AtoB,
+			},
+			input: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"query": null
+			}`,
+			expected: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"query": null
+			}`,
+		},
+		{
+			name:      "Missing query field",
+			mappingID: "test-wrapper",
+			opts: MappingOptions{
+				Direction: AtoB,
+			},
+			input: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"collection": {
+					"@type": "koral:doc"
+				}
+			}`,
+			expected: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"collection": {
+					"@type": "koral:doc"
+				}
+			}`,
+		},
+		{
+			name:      "Query field with non-object value",
+			mappingID: "test-wrapper",
+			opts: MappingOptions{
+				Direction: AtoB,
+			},
+			input: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"query": "invalid"
+			}`,
+			expected: `{
+				"@context": "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+				"query": "invalid"
+			}`,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			// Parse input JSON
+			var inputData interface{}
+			err := json.Unmarshal([]byte(tt.input), &inputData)
+			require.NoError(t, err)
+
+			// Apply mappings
+			result, err := m.ApplyQueryMappings(tt.mappingID, tt.opts, inputData)
+			if tt.expectError {
+				assert.Error(t, err)
+				return
+			}
+			require.NoError(t, err)
+
+			// Parse expected JSON
+			var expectedData interface{}
+			err = json.Unmarshal([]byte(tt.expected), &expectedData)
+			require.NoError(t, err)
+
+			// Compare results
+			assert.Equal(t, expectedData, result)
+		})
+	}
+}