> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Visual Body Editor

> Use the drag-and-drop body editor to visually configure JSON injection without writing templates. Perfect for complex nested payloads.

# Visual Body Editor

Configure complex JSON body injection visually with drag-and-drop. No template syntax required.

## What is the Visual Body Editor?

The **Visual Body Editor** is a drag-and-drop interface for injecting values (like secrets) into specific locations in your JSON request body.

**Traditional way (manual templates):**

```json theme={"dark"}
{
  "api_key": "{{secret:stripe_key}}",
  "user": {
    "id": 123,
    "token": "{{secret:user_token}}"
  }
}
```

*Manual JSON editing with template syntax*

**Visual way:**

1. Capture or paste an example JSON payload
2. Drag injection rules onto specific fields
3. KnoxCall builds the template automatically

Perfect for complex nested payloads!

## When to Use This Feature

### Use Visual Editor When:

* ✅ You have complex nested JSON structures
* ✅ You need to inject multiple secrets at different depths
* ✅ You want to see the exact structure visually
* ✅ You're not comfortable with JSON template syntax
* ✅ You need to inject values into deeply nested objects

### Use Manual Template When:

* ⚠️ Simple flat JSON payloads (1-2 fields)
* ⚠️ You prefer writing JSON directly
* ⚠️ Dynamic payloads that vary by request

## How It Works

```text theme={"dark"}
1. Capture or paste example JSON payload
     ↓
2. KnoxCall parses structure and identifies all paths
     ↓
3. Create injection rules (key-value pairs)
     ↓
4. Drag rules onto specific JSON fields
     ↓
5. KnoxCall generates template automatically
     ↓
6. Backend receives requests with injected values
```

## Step-by-Step Guide

### Step 1: Open Route Configuration

1. Navigate to **Routes**
2. Click your route
3. Go to **Configuration** tab (or **Method Configs** for method-specific body)
4. Scroll to **Body Injection** section

### Step 2: Capture or Paste Payload

You have two options:

#### Option A: Capture Live Request (Recommended)

Best for APIs you can actually call.

1. Click **Capture Payload**
2. Choose **Live Request**
3. Copy the unique capture URL
4. Send a POST request to that URL with example payload:

```bash theme={"dark"}
curl -X POST "https://a1b2c3d4.DunderMifflin.knoxcall.com/capture/abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "payment": {
      "amount": 1000,
      "currency": "usd",
      "source": "tok_visa"
    },
    "customer": {
      "email": "customer@example.com",
      "name": "John Doe"
    }
  }'
```

5. KnoxCall automatically captures the structure

#### Option B: Paste JSON (Faster)

Best when you already have example JSON.

1. Click **Capture Payload**
2. Choose **Paste JSON**
3. Paste your example JSON:

```json theme={"dark"}
{
  "payment": {
    "amount": 1000,
    "currency": "usd",
    "source": "tok_visa",
    "api_key": ""
  },
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe"
  }
}
```

4. Click **Submit Payload**

<Note>
  **Tip:** Use realistic example data. The structure you provide becomes your template. Any fields you add later won't have drop zones unless you recapture.
</Note>

### Step 3: Create Injection Rules

Injection rules are key-value pairs you'll drag onto your JSON structure.

1. Click **+ Add Injection Rule**
2. Enter **Key** (field name to inject):
   ```
   api_key
   ```
3. Enter **Value** (what to inject):
   ```
   {{secret:stripe_prod_key}}
   ```
4. Or click **🔑 Secrets** button to pick from dropdown
5. Click **Add Rule**

**Example rules:**

| Key             | Value                       | Purpose          |
| --------------- | --------------------------- | ---------------- |
| api\_key        | `{{secret:stripe_key}}`     | Stripe API key   |
| auth\_token     | `{{secret:user_token}}`     | User auth token  |
| webhook\_secret | `{{secret:webhook_secret}}` | Webhook signing  |
| customer\_id    | `{{var:customer_id}}`       | From query param |

<Tip>
  **Variables work too!** Use `{{var:param_name}}` to inject query parameters from the incoming request.
</Tip>

### Step 4: Drag Rules onto JSON Structure

Now the fun part - visually place your injection rules.

**The interface shows:**

* **Top section:** List of injection rules (draggable)
* **Bottom section:** Your JSON payload structure (drop zones)

**To assign a rule:**

1. Click and hold an injection rule from the top
2. Drag it over the JSON structure below
3. Drop it onto a specific field

**Drop indicators:**

* **Blue line above** = Drop before this field
* **Blue line below** = Drop after this field
* **"DROP AS CHILD →"** badge = Drop inside nested object

**Example:**

```text theme={"dark"}
Injection Rules (top):
┌─────────────────────────────────────────┐
│ ⋮⋮ api_key: {{secret:stripe_key}}      │ ← Drag this
└─────────────────────────────────────────┘

Payload Structure (bottom):
payment                                     ← Drop zone
  amount: 1000
  currency: usd
  [Drop here to inject as child] ⬇️

After drop:
payment
  amount: 1000
  currency: usd
  ✓ INJECTED api_key: {{secret:stripe_key}} ← Injected!
```

### Step 5: Assign Nested Fields

For nested objects, you can inject at any depth:

**Example structure:**

```text theme={"dark"}
user
  profile
    settings
      notifications
        email: true
        sms: false
```

**Drag rule onto `notifications` with "DROP AS CHILD":**

```text theme={"dark"}
user
  profile
    settings
      notifications
        email: true
        sms: false
        ✓ INJECTED token: {{secret:notification_token}}
```

**Result JSON path:** `user.profile.settings.notifications.token`

### Step 6: Save Route

Click **Save** or **Update Route**

Your body injection template is now configured!

## Understanding Injection Rules

### Rule Components

Each injection rule has three properties:

**1. Key (Required)**

* The field name to inject
* Example: `api_key`, `token`, `customer_id`
* Shows in the final JSON

**2. Value (Required)**

* The value to inject
* Can be:
  * Secret: `{{secret:stripe_key}}`
  * Variable: `{{var:user_id}}`
  * Static: `"production"`
  * Mixed: `Bearer {{secret:token}}`

**3. Path (Auto-assigned by drag-drop)**

* Where in the JSON to inject
* Example: `payment.details.api_key`
* Automatically set when you drop the rule
* Can be empty if not assigned yet

### Rule States

**Unassigned (gray):**

```text theme={"dark"}
⋮⋮ api_key: {{secret:stripe_key}}     Not assigned ⚠️
```

*Rule exists but not placed in JSON structure*

**Assigned (green):**

```text theme={"dark"}
⋮⋮ api_key: {{secret:stripe_key}}     @ payment.api_key ✓
```

*Rule assigned to `payment.api_key` path*

<Warning>
  **Unassigned rules are not injected!** Only rules with a path (assigned via drag-drop) are included in requests.
</Warning>

## Managing Rules

### Reorder Rules (Drag Within JSON)

To move a rule to a different location:

1. Find the green **✓ INJECTED** box in your JSON structure
2. Drag it to a new location
3. Drop on a different field

The rule updates to the new path automatically.

### Remove Rule Assignment

To unassign a rule (without deleting it):

1. Click **Remove** button on the green **✓ INJECTED** box
2. Rule moves back to unassigned list (top section)
3. Can be reassigned later by dragging again

### Delete Rule Completely

To permanently delete a rule:

1. Click **Remove** button in the **Injection Rules** list (top section)
2. Rule is deleted entirely
3. If it was assigned, it's removed from JSON structure too

### Edit Existing Rule

Currently, rules cannot be edited after creation. To change:

1. Delete the existing rule
2. Create a new rule with updated values
3. Drag onto the same location

## Example Use Cases

### Use Case 1: Payment API with Nested Secrets

**Goal:** Inject Stripe key and webhook secret at different depths

**Example payload:**

```json theme={"dark"}
{
  "payment": {
    "amount": 5000,
    "currency": "usd",
    "api_key": ""
  },
  "webhook": {
    "url": "https://example.com/webhook",
    "secret": ""
  }
}
```

**Injection rules:**

| Key      | Value                        | Path             |
| -------- | ---------------------------- | ---------------- |
| api\_key | `{{secret:stripe_prod_key}}` | payment.api\_key |
| secret   | `{{secret:webhook_secret}}`  | webhook.secret   |

**Result (what backend receives):**

```json theme={"dark"}
{
  "payment": {
    "amount": 5000,
    "currency": "usd",
    "api_key": "sk_live_abc123xyz789..."
  },
  "webhook": {
    "url": "https://example.com/webhook",
    "secret": "whsec_def456..."
  }
}
```

### Use Case 2: User Profile with Dynamic Variables

**Goal:** Inject user-specific tokens from query params

**Example payload:**

```json theme={"dark"}
{
  "user": {
    "profile": {
      "email": "user@example.com"
    },
    "auth": {
      "token": ""
    }
  }
}
```

**Incoming request:**

```text theme={"dark"}
GET /api/user?user_id=12345
```

**Injection rules:**

| Key   | Value                  | Path            |
| ----- | ---------------------- | --------------- |
| token | `{{secret:api_token}}` | user.auth.token |
| id    | `{{var:user_id}}`      | user.id         |

**Result:**

```json theme={"dark"}
{
  "user": {
    "id": "12345",
    "profile": {
      "email": "user@example.com"
    },
    "auth": {
      "token": "bearer_abc123..."
    }
  }
}
```

### Use Case 3: Multi-Service Request

**Goal:** Call multiple services with different API keys in one payload

**Example payload:**

```json theme={"dark"}
{
  "stripe": {
    "key": "",
    "action": "charge"
  },
  "sendgrid": {
    "key": "",
    "action": "send"
  },
  "twilio": {
    "key": "",
    "action": "sms"
  }
}
```

**Injection rules:**

| Key | Value                     | Path         |
| --- | ------------------------- | ------------ |
| key | `{{secret:stripe_key}}`   | stripe.key   |
| key | `{{secret:sendgrid_key}}` | sendgrid.key |
| key | `{{secret:twilio_key}}`   | twilio.key   |

All secrets injected at different paths with the same key name!

## Editing Payload Structure

### Recapture Payload

If your API payload structure changed:

1. Click **Recapture** button (next to payload structure)
2. Send new request or paste updated JSON
3. **⚠️ Warning:** Existing rule assignments are lost
4. Drag rules onto new structure again

<Warning>
  **Recapturing clears all rule assignments!** Save your rule list somewhere if you need to reference it. The rules themselves aren't deleted, but their path assignments are cleared.
</Warning>

### Edit Payload Manually

For small tweaks:

1. Click **Edit** button
2. Modify JSON structure directly
3. Save
4. Reassign rules if paths changed

### Delete Payload Structure

To start over:

1. Click **Delete** button
2. Confirm deletion
3. All rule assignments cleared
4. Can capture new payload structure

## Advanced Features

### Nested Object Injection

Drop rules **into** nested objects:

**Drag rule to right side of parent:**

```text theme={"dark"}
user                    ← Hover here
  email: test@example.com
  [DROP AS CHILD →] appears
```

**Result:**

```text theme={"dark"}
user
  email: test@example.com
  ✓ INJECTED token: {{secret:token}}  ← Added as child
```

### Multiple Rules on Same Level

You can inject multiple fields at the same nesting level:

```text theme={"dark"}
payment
  amount: 1000
  ✓ INJECTED api_key: {{secret:stripe_key}}
  ✓ INJECTED merchant_id: {{secret:merchant_id}}
  ✓ INJECTED webhook_secret: {{secret:webhook_secret}}
```

All three injected as children of `payment`.

### Parent Path Requirements

<Warning>
  **Important:** When injecting into nested paths, the parent objects **must exist** in the incoming request or be defined in your payload structure.

  **Example:**

  * Injection path: `user.profile.token`
  * Incoming request **must** have `user.profile` object (even if empty)
  * Otherwise injection fails silently
</Warning>

The editor shows warnings for nested injections:

```text theme={"dark"}
profile
  ✓ INJECTED token: {{secret:token}}
  ⚠️ Parent key "user" must exist in request
```

## Combining with Method Configs

You can use visual body editor **per HTTP method**:

**GET method:** No body injection (GET has no body)

**POST method:**

* Payload: User creation structure
* Inject: `write_api_key`, `create_token`

**PUT method:**

* Payload: User update structure
* Inject: `update_api_key`, `version_token`

**DELETE method:**

* Payload: Deletion confirmation
* Inject: `delete_token`, `admin_key`

Each method gets its own visual body editor with separate:

* Payload structure
* Injection rules
* Drop zone assignments

See [Method-Specific Config](/advanced/method-specific-config) for details.

## Troubleshooting

### Issue: "Drag not working"

**Causes:**

* Browser compatibility (use Chrome/Edge/Firefox)
* JavaScript disabled
* Conflicting browser extensions

**Fix:**

* Try different browser
* Disable ad blockers temporarily
* Clear browser cache

### Issue: "Drop indicator not showing"

**Symptoms:** Can't see blue line or "DROP AS CHILD" badge

**Causes:**

* Not dragging an actual rule
* Dragging too fast
* CSS rendering issue

**Fix:**

* Drag slowly and hover over fields
* Wait for indicator to appear
* Refresh page

### Issue: "Rule not injected in requests"

**Symptoms:** Backend doesn't receive injected field

**Debug:**

1. Check rule is assigned (shows green with path)
2. Check rule appears in JSON structure (green ✓ INJECTED box)
3. Test route with Route Tester
4. View request details in logs
5. Verify secret exists if using `{{secret:name}}`

**Common cause:** Rule created but never dragged onto structure (unassigned).

### Issue: "Parent key must exist" warning

**Symptoms:** Injecting into nested path like `user.profile.token`

**Cause:** Incoming requests don't always have `user.profile` object

**Fix:**

1. Ensure incoming requests include parent object:
   ```json theme={"dark"}
   {
     "user": {
       "profile": {}
     }
   }
   ```
2. Or inject at root level instead of nested
3. Or use method configs to define base structure

### Issue: "Payload structure deleted my rules"

**Symptoms:** Recaptured payload and rules disappeared

**Actually:** Rules still exist but assignments cleared

**Fix:**

1. Rules are in top **Injection Rules** list
2. Drag them onto new payload structure
3. Save route
4. To prevent: Don't recapture unnecessarily

## Best Practices

### 1. Use Realistic Example Payloads

✅ **Good:**

```json theme={"dark"}
{
  "order": {
    "items": [{"id": 123, "qty": 2}],
    "total": 50.00,
    "currency": "USD"
  }
}
```

*Real structure with actual data types*

❌ **Bad:**

```json theme={"dark"}
{
  "order": {}
}
```

*Empty - won't show nested fields*

### 2. Name Rules Descriptively

✅ **Good:**

```text theme={"dark"}
stripe_api_key
sendgrid_auth_token
user_webhook_secret
```

❌ **Bad:**

```text theme={"dark"}
key1
secret
token
```

### 3. Test After Configuration

Always test with Route Tester:

1. Configure visual body editor
2. Click **Test Route**
3. Send test request
4. Verify injected fields in **Request Details** section
5. Check backend received correct values

### 4. Document Your Structure

In route description, note the payload structure:

```text theme={"dark"}
Stripe Payments Route

Body structure:
- payment.api_key → Stripe production key
- payment.webhook_secret → Webhook verification
- customer.id → From query param user_id
```

Helps team members understand the configuration.

### 5. Use Variables for Dynamic Values

Don't hardcode dynamic data:

❌ **Bad:**

```json theme={"dark"}
{
  "user_id": "12345"
}
```

✅ **Good:**

```json theme={"dark"}
{
  "user_id": "{{var:user_id}}"
}
```

*Inject from query parameter*

### 6. Organize Rules by Service

Group related rules:

```text theme={"dark"}
Injection Rules:
├─ Stripe:
│  ├─ stripe_api_key
│  └─ stripe_webhook_secret
├─ SendGrid:
│  └─ sendgrid_api_key
└─ Internal:
   └─ app_secret
```

## Limitations

### Arrays Not Fully Supported

The editor shows arrays but doesn't let you inject **into** array items:

**Structure:**

```json theme={"dark"}
{
  "items": [
    {"id": 1, "name": "Item 1"},
    {"id": 2, "name": "Item 2"}
  ]
}
```

**Can inject:** Root or `items` level
**Cannot inject:** Specific array item like `items[0].name`

**Workaround:** Use manual template editing for array injection.

### Max Nesting Depth: 10 Levels

Payloads deeper than 10 levels may not render properly:

```json theme={"dark"}
{
  "a": { "b": { "c": { "d": { "e": { "f": { "g": { "h": { "i": { "j": { "k": {} } } } } } } } } } }
}
```

*Level 11 and beyond not supported*

### No Conditional Injection

Rules are always injected. Cannot do:

* "Only inject if query param exists"
* "Inject different value based on environment"

**Workaround:** Use multiple method configs or environment overrides.

### Large Payloads (>1000 fields)

Very large JSON structures may slow down the editor.

**Workaround:** Break into multiple routes or use manual template editing.

## Related Features

* **Manual Body Templates**: Edit JSON directly without visual editor
* **Method Configs**: Different body per HTTP method
* **Secrets**: Encrypted credentials for injection
* **Variables**: Inject query parameters with `{{var:name}}`

## Next Steps

<CardGroup cols={2}>
  <Card title="Method Configs" icon="code-branch" href="/advanced/method-specific-config">
    Different body per HTTP method
  </Card>

  <Card title="Test Routes" icon="flask" href="/essentials/routes/testing-routes">
    Test your body injection
  </Card>

  <Card title="Secrets" icon="key" href="/getting-started/first-secret">
    Create secrets for injection
  </Card>

  <Card title="Advanced Config" icon="sliders" href="/advanced/advanced-route-configuration">
    Headers, transformations, and more
  </Card>
</CardGroup>

***

<CardGroup cols={2}>
  <Card title="📊 Statistics" icon="chart-line">
    * **Level**: intermediate
    * **Time**: 15 minutes
  </Card>

  <Card title="🏷️ Tags" icon="tags">
    `body-injection`, `visual-editor`, `drag-drop`, `json`, `configuration`
  </Card>
</CardGroup>
