Payload Customization
Transform webhook payloads and create dynamic URLs to match your system's exact requirements. Eliminate middleware with JSONata expressions.
Overview
Field Nation webhooks now support customizable payloads and dynamic URLs, giving you complete control over how webhook data is structured and delivered.
What You Can Do
| Capability | Description |
|---|---|
| Transform Payloads | Restructure webhook data to match your system's expected format using JSONata expressions. |
| Dynamic URLs | Include event data in webhook URLs for intelligent routing (e.g., route by region or company). |
| Filter Fields | Send only the fields you need — reduce payload size and processing overhead. |
| Rename Fields | Match your system's naming conventions without building middleware. |
Why Customize Payloads?
The Problem
Without customization, integrating with external systems requires:
- Middleware servers to transform Field Nation's payload format
- Extra development time to map fields between systems
- Infrastructure costs to maintain translation services
- Processing delays from additional network hops
The Solution
With payload customization, transformations happen at the source:
| Before | After |
|---|---|
| Build middleware to transform | Transform at delivery |
| Maintain translation servers | No extra infrastructure |
| One fixed payload format | Unlimited custom formats |
| Static webhook URLs | Dynamic, data-driven URLs |
Real-World Use Cases
- ServiceNow
- Multi-Region Routing
- Slack Notifications
- Legacy Systems
- Analytics Pipeline
Challenge: ServiceNow expects incident tickets in a specific format with custom field names.
JSONata Script:
{
"u_external_ticket_id": $string($.workorder.id),
"short_description": $.workorder.title,
"state": $.workorder.status.name = "Work Done" ? "6" : "2",
"assignment_group": "Field Services",
"u_technician": $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name,
"u_client_company": $.workorder.company.name,
"work_notes": "Status updated via Field Nation at " & $.timestamp
}
Result: Direct webhook delivery to ServiceNow without middleware.
Challenge: Route work orders to region-specific endpoints automatically.
Dynamic URL Template:
https://{{$.workorder.location.country}}.api.company.com/workorders
Result:
- US work orders →
us.api.company.com/workorders - UK work orders →
uk.api.company.com/workorders - CA work orders →
ca.api.company.com/workorders
Challenge: Send formatted notifications to Slack when work orders complete.
JSONata Script:
{
"text": "Work Order #" & $string($.workorder.id) & " - " & $.workorder.status.name,
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*" & $.workorder.title & "*\nStatus: " & $.workorder.status.name & "\nTechnician: " & $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name
}
}
]
}
Result: Native Slack notifications without a middleware service.
Challenge: A 15-year-old ERP only accepts flat JSON with uppercase field names.
JSONata Script:
{
"WORK_ORDER_ID": $.workorder.id,
"WORK_ORDER_TITLE": $.workorder.title,
"COMPANY_NAME": $.workorder.company.name,
"TECHNICIAN_NAME": $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name,
"STATUS": $.workorder.status.name
}
Result: Direct integration with legacy systems that can't be modified.
Challenge: Data team needs webhook events in a format optimized for their data warehouse.
JSONata Script:
{
"event_type": $.event.name,
"event_timestamp": $.timestamp,
"workorder_id": $.workorder.id,
"company_id": $.workorder.company.id,
"status": $.workorder.status.name,
"location_state": $.workorder.location.state
}
Result: Webhook data flows directly into analytics pipeline without ETL processing.
Transformation Options
JSONata Expressions (Recommended)
JSONata is a powerful query and transformation language for JSON data.
It's purpose-built for JSON transformation, has a concise syntax, and supports complex operations like filtering, sorting, and aggregation.
Basic Field Selection
{
"order_id": $.workorder.id,
"title": $.workorder.title,
"status": $.workorder.status.name
}
Concatenating Fields
{
"technician_name": $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name,
"location": $.workorder.location.city & ", " & $.workorder.location.state
}
Conditional Logic
{
"order_id": $.workorder.id,
"is_complete": $.workorder.status.name = "Work Done",
"priority": $.workorder.status.name = "At Risk" ? "high" : "normal",
"state_code": $.workorder.status.name = "Work Done" ? "6" :
$.workorder.status.name = "Approved" ? "7" : "2"
}
Accessing Arrays
{
"work_order_id": $.workorder.id,
"po_number": $.workorder.custom_fields.results[name="PO Number"].value,
"tags": $.workorder.tags.results.name,
"has_priority_tag": "Priority" in $.workorder.tags.results.name
}
Built-in Functions
{
"work_order_id": $string($.workorder.id),
"title_uppercase": $uppercase($.workorder.title),
"timestamp": $now(),
"scheduled_date": $substringBefore($.workorder.schedule.start.utc, "T")
}
Static JSON Merge
For simpler use cases, merge static fields into every webhook payload:
{
"source": "field-nation",
"environment": "production",
"api_version": "3.0",
"integration_id": "your-integration-id"
}
This adds the static fields to the original payload without transforming it.
Dynamic URL Templates
Include values from the webhook payload in your endpoint URL using template expressions.
Template Syntax
https://api.example.com/workorders/{{$.workorder.id}}/updates
Templates use {{ expression }} syntax where expression is a JSONata path.
Common Patterns
Route by Work Order ID
https://api.example.com/workorders/{{$.workorder.id}}/webhooks
Delivers to: https://api.example.com/workorders/12345/webhooks
Route by Company
https://api.example.com/clients/{{$.workorder.company.id}}/events
Delivers to: https://api.example.com/clients/100/events
Route by Region
https://{{$.workorder.location.country}}.api.example.com/webhooks
Delivers to: https://us.api.example.com/webhooks
Multiple Templates
https://api.example.com/{{$.workorder.company.id}}/workorders/{{$.workorder.id}}
Delivers to: https://api.example.com/100/workorders/12345
Templates are not allowed in the domain/origin part of the URL for security reasons. https://{{$.malicious}}.example.com is not permitted.
Payload Field Reference
All webhook events include these fields that you can use in transformations:
Root Level
| Path | Type | Description |
|---|---|---|
$.event.name | string | Event name (e.g., workorder.status.work_done) |
$.event.params | object | Event-specific parameters |
$.timestamp | string | ISO 8601 timestamp when event occurred |
$.triggered_by_user.id | number | User ID who triggered the event |
Work Order Core
| Path | Type | Description |
|---|---|---|
$.workorder.id | number | Unique work order ID |
$.workorder.title | string | Work order title |
$.workorder.description | string | Detailed description |
$.workorder.status.id | number | Status ID |
$.workorder.status.name | string | Status name |
Company & People
| Path | Type | Description |
|---|---|---|
$.workorder.company.id | number | Buyer company ID |
$.workorder.company.name | string | Buyer company name |
$.workorder.manager.first_name | string | Manager first name |
$.workorder.manager.last_name | string | Manager last name |
$.workorder.assignee.id | number | Assigned provider ID |
$.workorder.assignee.first_name | string | Provider first name |
$.workorder.assignee.last_name | string | Provider last name |
Location
| Path | Type | Description |
|---|---|---|
$.workorder.location.city | string | City |
$.workorder.location.state | string | State/Province |
$.workorder.location.zip | string | ZIP/Postal code |
$.workorder.location.country | string | Country code |
Schedule & Pay
| Path | Type | Description |
|---|---|---|
$.workorder.schedule.start.utc | string | Scheduled start (UTC) |
$.workorder.schedule.end.utc | string | Scheduled end (UTC) |
$.workorder.pay.type | string | Pay type (fixed, hourly, etc.) |
$.workorder.pay.base.amount | number | Base pay amount |
Custom Fields & Tags
| Path | Type | Description |
|---|---|---|
$.workorder.custom_fields.results | array | Custom field objects |
$.workorder.custom_fields.results[n].name | string | Field name |
$.workorder.custom_fields.results[n].value | string | Field value |
$.workorder.tags.results | array | Tag objects |
$.workorder.tags.results[n].name | string | Tag name |
Setting Up Payload Customization
Step 1: Create or Edit a Webhook
Navigate to Webhooks Dashboard and create a new webhook or edit an existing one.
Step 2: Enable Payload Override
Check the "Override default payload" option to enable customization. This reveals a preview panel showing your custom payload configuration.

The payload customization workflow is identical whether you're creating a new webhook or editing an existing one. The only difference is clicking Create Webhook versus Update Webhook to save your changes.
Step 3: Open the Payload Editor
Click Edit Payload to open the side drawer where you can write your transformation script.

Step 4: Select Script Language
Choose your transformation approach:
- JSONata (recommended) — Dynamic expressions for complex transformations
- JSON — Static field merge for simple additions
Step 5: Write Your Transformation Script
Enter your JSONata expression or JSON object:
{
"ticket_id": $.workorder.id,
"title": $.workorder.title,
"status": $.workorder.status.name,
"technician": $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name
}
Step 6: Preview Your Payload
After saving in the side drawer, your transformation script appears in the preview panel. This shows what you've configured but hasn't been saved to the webhook yet.

The preview only shows your local changes. You must click Create Webhook (for new webhooks) or Update Webhook (for existing webhooks) to persist your payload customization.
Step 7: Add Dynamic URL (Optional)
If needed, update your webhook URL to include template expressions:
https://api.example.com/workorders/{{$.workorder.id}}
Step 8: Save and Test
Save the webhook configuration and trigger a test event to verify the transformation works correctly.
Best Practices
Start Simple
Begin with basic field selection, then add complexity as needed:
// Start here
{ "id": $.workorder.id, "status": $.workorder.status.name }
// Then expand
{
"id": $.workorder.id,
"status": $.workorder.status.name,
"company": $.workorder.company.name,
"technician": $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name
}
Handle Missing Fields
Use the coalesce operator to provide defaults:
{
"assignee_name": $.workorder.assignee.first_name ?
($.workorder.assignee.first_name & " " & $.workorder.assignee.last_name) :
"Unassigned"
}
Test Before Production
Use the webhook test feature to validate transformations before enabling in production.
Keep Original Payloads
Original payloads are automatically preserved in Field Nation for debugging and re-delivery. You can access them through the delivery logs.
If a transformation fails, the original payload is still available in the delivery log details. Use this to diagnose and fix your script.
Troubleshooting
Transformation produces empty payload
Cause: JSONata expression doesn't match payload structure.
Solution:
- Check field paths match the actual payload structure
- Use
$.workorder.idnot$.data.id - Verify the event includes the fields you're accessing
URL template not resolving
Cause: Template expression returns undefined or null.
Solution:
- Verify the field exists in the payload
- Check for typos in the path
- Use a fallback:
{{$.workorder.id ? $.workorder.id : 'default'}}
Script validation error
Cause: Invalid JSONata syntax.
Solution:
- Check for missing quotes around strings
- Verify bracket matching
- Test your expression at try.jsonata.org
Fields appear as null
Cause: Accessing fields that don't exist for this event.
Solution:
- Not all events include all fields (e.g.,
assigneeis null before assignment) - Use conditional logic to handle missing data
API Configuration
When creating or updating webhooks via API, include the webhookScript field:
curl -X POST https://api.fieldnation.com/api/v1/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com/workorders/{{$.workorder.id}}",
"method": "post",
"status": "active",
"events": ["workorder.status.work_done"],
"webhookScript": {
"scriptLanguage": "jsonata",
"script": "{ \"id\": $.workorder.id, \"status\": $.workorder.status.name }",
"enabled": true
}
}'
webhookScript Fields
| Field | Type | Description |
|---|---|---|
scriptLanguage | string | "jsonata" or "json" |
script | string | The transformation script |
enabled | boolean | Toggle transformation on/off |
Summary
Payload customization eliminates the need for middleware by transforming data at the source:
| Capability | Benefit |
|---|---|
| JSONata transformations | Restructure data to match any system |
| Dynamic URLs | Route webhooks based on event content |
| Enable/disable toggle | Test without deleting configurations |
| Original payload storage | Debug with full context |
Bottom line: Your webhooks, your format. No middleware required.