Transform webhook payloads and create dynamic URLs to match your system's exact requirements. Eliminate middleware with JSONata expressions.
Field Nation webhooks now support customizable payloads and dynamic URLs, giving you complete control over how webhook data is structured and delivered.
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.
Without customization, integrating with external systems requires:
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 |
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/workordersResult:
us.api.company.com/workordersuk.api.company.com/workordersca.api.company.com/workordersChallenge: 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.
JSONata is a powerful query and transformation language for JSON data.
Why JSONata? It's purpose-built for JSON transformation, has a concise syntax, and supports complex operations like filtering, sorting, and aggregation.
{
"order_id": $.workorder.id,
"title": $.workorder.title,
"status": $.workorder.status.name
}{
"technician_name": $.workorder.assignee.first_name & " " & $.workorder.assignee.last_name,
"location": $.workorder.location.city & ", " & $.workorder.location.state
}{
"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"
}{
"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
}{
"work_order_id": $string($.workorder.id),
"title_uppercase": $uppercase($.workorder.title),
"timestamp": $now(),
"scheduled_date": $substringBefore($.workorder.schedule.start.utc, "T")
}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.
Include values from the webhook payload in your endpoint URL using template expressions.
https://api.example.com/workorders/{{$.workorder.id}}/updatesTemplates use {{ expression }} syntax where expression is a JSONata path.
Restriction: Templates are not allowed in the domain/origin part of the URL for security reasons. https://{{$.malicious}}.example.com is not permitted.
All webhook events include these fields that you can use in transformations:
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
Navigate to Webhooks Dashboard and create a new webhook or edit an existing one.
Check the "Override default payload" option to enable customization.
Choose your transformation approach:
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
}If needed, update your webhook URL to include template expressions:
https://api.example.com/workorders/{{$.workorder.id}}Save the webhook configuration and trigger a test event to verify the transformation works correctly.
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
}Use the coalesce operator to provide defaults:
{
"assignee_name": $.workorder.assignee.first_name ?
($.workorder.assignee.first_name & " " & $.workorder.assignee.last_name) :
"Unassigned"
}Use the webhook test feature to validate transformations before enabling in production.
Original payloads are automatically preserved in Field Nation for debugging and re-delivery. You can access them through the delivery logs.
Debugging Tip: If a transformation fails, the original payload is still available in the delivery log details. Use this to diagnose and fix your script.
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
}
}'| Field | Type | Description |
|---|---|---|
scriptLanguage | string | "jsonata" or "json" |
script | string | The transformation script |
enabled | boolean | Toggle transformation on/off |
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.
Last updated on