Platform Data in Webhooks

Platform data filtering allows you to receive specific platform-native fields directly in webhook payloads using JSONPath expressions. This feature eliminates the need for additional API calls after receiving webhooks, reducing rate limit pressure and simplifying webhook-driven integrations.

Configure platform data filtering through the Configuration API to specify exactly which platform fields you need in your webhook payloads.

Overview

When you receive a webhook from Rutter, it typically includes standardized data in our universal API format. However, you might need access to platform-specific fields that aren't included in our standardized model, such as vendor display names, discount calculations, or specialized metadata.

Previously, you would need to make a separate API call to access platform_data after receiving a webhook. With platform data filtering, you can configure your webhooks to include exactly the platform-specific fields you need, delivered directly in the webhook payload.

This eliminates follow-up API calls and lets you process complete data changes in a single webhook handler. You define JSONPath expressions to extract specific fields, so webhook payloads only contain the platform data you actually need.

How It Works

Platform data filtering works by applying JSONPath expressions to the raw platform data before it's included in your webhook payload. You configure these expressions through Rutter's Configuration API, specifying exactly which fields you want to extract for each webhook type and platform combination.

Webhook Flow:

  1. A change occurs in the connected platform (e.g., new order created)
  2. Rutter receives the raw platform data
  3. Your configured JSONPath expressions are applied to extract specific fields
  4. The webhook is sent with both standardized data AND your filtered platform data
  5. You process the complete data in a single event handler

Configuration

Platform data filtering is configured through the Configuration API using basic authentication. This ensures you can manage webhook settings that apply across all connections within your organization.

Step 1: Get Your Current Webhook Configuration

First, retrieve your existing webhook configuration to see the current setup:

Get Current Configuration
1
curl "https://production.rutterapi.com/versioned/configs/webhooks" \
2
-H "X-Rutter-Version: 2023-03-14" \
3
-H "Authorization: Basic <YOUR_ENCODED_CLIENT_ID_AND_CLIENT_SECRET>"

Step 2: Configure Platform Data Filtering

Update your webhook configuration to include platform data filtering. You'll specify JSONPath expressions for each webhook type and platform combination:

Configure Platform Data Filtering
1
curl -X PATCH "https://production.rutterapi.com/versioned/configs/webhooks/webhook_config_123/platform_data_config" \
2
-H "X-Rutter-Version: 2023-03-14" \
3
-H "Authorization: Basic <YOUR_ENCODED_CLIENT_ID_AND_CLIENT_SECRET>" \
4
-H "Content-Type: application/json" \
5
-d '{
6
"platform_data_config": {
7
"ORDER_CREATED": {
8
"SHOPIFY": {
9
"customer_email": "$.customer.email",
10
"line_items": "$.line_items[*].title",
11
"total_amount": "$.total_price",
12
"shipping_address": "$.shipping_address.city"
13
},
14
"WOOCOMMERCE": {
15
"customer_id": "$.customer_id",
16
"order_total": "$.total",
17
"payment_method": "$.payment_method"
18
}
19
},
20
"INVOICE_CREATED": {
21
"QUICKBOOKS": {
22
"vendor_display_name": "$.Vendor.DisplayName",
23
"custom_fields": "$.CustomField[*].StringValue",
24
"line_descriptions": "$.Line[*].Description"
25
}
26
}
27
}
28
}'

Step 3: Verify Configuration

Check that your configuration was applied correctly:

Verify Configuration
1
curl "https://production.rutterapi.com/versioned/configs/webhooks/webhook_config_123/platform_data_config" \
2
-H "X-Rutter-Version: 2023-03-14" \
3
-H "Authorization: Basic <YOUR_ENCODED_CLIENT_ID_AND_CLIENT_SECRET>"

JSONPath Expression Guide

JSONPath expressions allow you to extract specific data from the raw platform response. All expressions must start with $ and follow JSONPath syntax.

Basic Expressions

Basic JSONPath Examples
1
// Extract a simple field
2
"customer_email": "$.customer.email"
3
4
// Extract from an array (first item)
5
"first_line_item": "$.line_items[0].title"
6
7
// Extract all items from an array
8
"all_line_items": "$.line_items[*].title"
9
10
// Extract nested object field
11
"shipping_city": "$.shipping_address.city"
12
13
// Extract with array index
14
"second_custom_field": "$.CustomField[1].StringValue"

Advanced Expressions

Advanced JSONPath Examples
1
// Extract multiple fields from array objects
2
"line_details": "$.line_items[*][title,price,quantity]"
3
4
// Extract based on array length
5
"has_multiple_items": "$.line_items[1:]"
6
7
// Extract nested array data
8
"custom_field_names": "$.CustomField[*].Name"
9
10
// Extract conditional data (if supported)
11
"paid_line_items": "$.line_items[?(@.status == 'paid')].title"

Platform-Specific Examples

Different platforms structure their data differently. Here are common patterns for popular platforms:

Shopify Platform Data
1
{
2
"ORDER_CREATED": {
3
"SHOPIFY": {
4
"customer_email": "$.customer.email",
5
"customer_phone": "$.customer.phone",
6
"line_item_titles": "$.line_items[*].title",
7
"line_item_prices": "$.line_items[*].price",
8
"discount_codes": "$.discount_codes[*].code",
9
"shipping_city": "$.shipping_address.city",
10
"total_discounts": "$.total_discounts",
11
"fulfillment_status": "$.fulfillment_status"
12
}
13
}
14
}
QuickBooks Platform Data
1
{
2
"INVOICE_CREATED": {
3
"QUICKBOOKS": {
4
"vendor_display_name": "$.Vendor.DisplayName",
5
"vendor_company_name": "$.Vendor.CompanyName",
6
"custom_field_values": "$.CustomField[*].StringValue",
7
"line_descriptions": "$.Line[*].Description",
8
"line_amounts": "$.Line[*].Amount",
9
"txn_date": "$.TxnDate",
10
"doc_number": "$.DocNumber"
11
}
12
}
13
}
NetSuite Platform Data
1
{
2
"INVOICE_CREATED": {
3
"NETSUITE": {
4
"internal_id": "$.internalId",
5
"transaction_number": "$.tranid",
6
"subsidiary_name": "$.subsidiary.name",
7
"custom_form": "$.customForm.name",
8
"memo": "$.memo",
9
"line_item_descriptions": "$.item[*].description"
10
}
11
}
12
}

Webhook Payload Structure

When platform data filtering is configured, your webhook payloads will include a filtered_platform_data field containing only the specific platform fields you've configured.

Standard Webhook (without platform data filtering)

Standard Webhook Payload
1
{
2
"type": "ORDER",
3
"code": "ORDER_CREATED",
4
"entity": {
5
"id": "order_123",
6
"total": 99.99,
7
"currency_code": "USD"
8
}
9
}

Webhook with Platform Data Filtering

Webhook with Platform Data Filtering
1
{
2
"type": "ORDER",
3
"code": "ORDER_CREATED",
4
"entity": {
5
"id": "order_123",
6
"total": 99.99,
7
"currency_code": "USD"
8
},
9
"filtered_platform_data": {
10
"ORDER_CREATED": {
11
"customer_email": ["customer@example.com"],
12
"line_items": ["Product A", "Product B"],
13
"total_amount": ["99.99"],
14
"shipping_address": ["San Francisco"]
15
}
16
}
17
}

Note: Filtered values are always returned as arrays, even for single values. This is because JSONPath expressions can potentially match multiple values.

Use Cases & Examples

Use Case 1: E-commerce Discount Processing

Scenario: You need to process platform-specific discount calculations that aren't standardized across platforms.

Discount Processing Configuration
1
{
2
"ORDER_CREATED": {
3
"SHOPIFY": {
4
"discount_codes": "$.discount_codes[*].code",
5
"discount_amounts": "$.discount_codes[*].amount",
6
"total_discounts": "$.total_discounts",
7
"discount_applications": "$.discount_applications[*].value"
8
},
9
"WOOCOMMERCE": {
10
"coupon_lines": "$.coupon_lines[*].code",
11
"coupon_amounts": "$.coupon_lines[*].discount",
12
"discount_total": "$.discount_total"
13
}
14
}
15
}

Webhook Processing:

Processing Discounts
1
function processOrderWebhook(webhook) {
2
const { entity, filtered_platform_data } = webhook;
3
4
if (filtered_platform_data?.ORDER_CREATED) {
5
const platformData = filtered_platform_data.ORDER_CREATED;
6
7
// Process discount information specific to the platform
8
const discountCodes = platformData.discount_codes || platformData.coupon_lines || [];
9
const discountAmounts = platformData.discount_amounts || platformData.coupon_amounts || [];
10
11
// Apply your business logic for discount handling
12
processDiscounts(entity.id, discountCodes, discountAmounts);
13
}
14
}

Use Case 2: Vendor Display Names for Fintech

Scenario: You need to show appropriate vendor names to end users, but the standardized vendor name doesn't match what users expect to see.

Vendor Name Configuration
1
{
2
"BILL_CREATED": {
3
"QUICKBOOKS": {
4
"vendor_display_name": "$.Vendor.DisplayName",
5
"vendor_company_name": "$.Vendor.CompanyName"
6
},
7
"NETSUITE": {
8
"vendor_display_name": "$.entity.entityid",
9
"vendor_company_name": "$.entity.companyname"
10
}
11
}
12
}

Processing Logic:

Processing Vendor Names
1
function processBillWebhook(webhook) {
2
const { entity, filtered_platform_data } = webhook;
3
4
if (filtered_platform_data?.BILL_CREATED) {
5
const platformData = filtered_platform_data.BILL_CREATED;
6
7
// Use platform-specific vendor display name
8
const vendorDisplayName = platformData.vendor_display_name?.[0] || entity.vendor.name;
9
10
// Show the appropriate name to your end users
11
updateUserInterface(entity.id, { vendorName: vendorDisplayName });
12
}
13
}

Use Case 3: Custom Fields Access

Scenario: You need to access custom fields that vary by platform and aren't included in the universal model.

Custom Fields Configuration
1
{
2
"INVOICE_CREATED": {
3
"QUICKBOOKS": {
4
"custom_fields": "$.CustomField[*].StringValue",
5
"custom_field_names": "$.CustomField[*].Name"
6
},
7
"NETSUITE": {
8
"custom_fields": "$.customFieldList.customField[*].value",
9
"custom_field_names": "$.customFieldList.customField[*].scriptId"
10
}
11
}
12
}

Best Practices

Design Efficient Filters

Keep payloads lightweight - Only extract fields you actually use in your webhook processing logic.

Efficient Filtering
1
// Good: Extract only needed fields
2
{
3
"ORDER_CREATED": {
4
"SHOPIFY": {
5
"customer_email": "$.customer.email",
6
"order_total": "$.total_price"
7
}
8
}
9
}
10
11
// Avoid: Extracting entire complex objects
12
{
13
"ORDER_CREATED": {
14
"SHOPIFY": {
15
"entire_customer": "$.customer",
16
"all_line_items": "$.line_items[*]"
17
}
18
}
19
}

Handle Missing Data Gracefully

Not all webhook events will have the fields you're filtering for. Always check if filtered data exists before processing.

Defensive Processing
1
function processWebhook(webhook) {
2
const platformData = webhook.filtered_platform_data?.ORDER_CREATED;
3
4
// Always check if filtered data exists
5
if (!platformData) {
6
console.log('No filtered platform data available');
7
return;
8
}
9
10
// Check for specific fields and provide fallbacks
11
const customerEmail = platformData.customer_email?.[0] || webhook.entity.customer?.email || 'N/A';
12
const total = platformData.order_total?.[0] || webhook.entity.total || 0;
13
14
processOrder(customerEmail, total);
15
}

Test Your JSONPath Expressions

Before deploying to production, test your JSONPath expressions against sample platform data to ensure they extract the expected values.

Testing JSONPath
1
// Example platform data from Shopify
2
const sampleShopifyData = {
3
customer: { email: "test@example.com" },
4
line_items: [
5
{ title: "Product A", price: "29.99" },
6
{ title: "Product B", price: "39.99" }
7
],
8
total_price: "69.98"
9
};
10
11
// Test your expressions
12
const customerEmail = jsonPath.query(sampleShopifyData, "$.customer.email");
13
const lineItems = jsonPath.query(sampleShopifyData, "$.line_items[*].title");
14
const total = jsonPath.query(sampleShopifyData, "$.total_price");
15
16
console.log('Customer Email:', customerEmail); // ["test@example.com"]
17
console.log('Line Items:', lineItems); // ["Product A", "Product B"]
18
console.log('Total:', total); // ["69.98"]

Limitations & Constraints

Size Limitations

Filtered platform data is subject to a 500KB size limit per webhook payload. If the filtered data exceeds this limit, the webhook will be sent without the filtered_platform_data field and a WEBHOOK_PLATFORM_DATA_SIZE_EXCEEDED error will be logged to your webhook delivery logs with details about the payload size.

Field Name Constraints

  • 64 character maximum - Field names in your filtering configuration cannot exceed 64 characters
  • No special characters - Avoid using special characters in field names; stick to alphanumeric characters and underscores

JSONPath Requirements

  • Must start with $ - All JSONPath expressions must begin with the root selector $
  • Invalid expressions ignored - If a JSONPath expression is invalid, it will be ignored during filtering
  • Array results - All filtered values are returned as arrays, even single values

Platform Considerations

  • Platform data structure varies - Each platform structures their data differently, so expressions must be platform-specific
  • Field availability - Not all platforms provide the same fields; some expressions may return empty results
  • Data types - Platform data types may vary (strings, numbers, booleans) and are preserved in the filtered results

Troubleshooting

Webhook Missing Filtered Data

If your webhook doesn't include the expected filtered_platform_data field:

  1. Check configuration - Verify your platform data filtering is configured correctly
  2. Verify webhook type - Ensure you've configured filtering for the specific webhook type you're receiving
  3. Confirm platform - Make sure you've configured filtering for the correct platform
  4. Review size limits - Check if your filtered data exceeds the 500KB limit

Empty Filtered Results

If your filtered platform data contains empty arrays:

  1. Test JSONPath expressions - Verify your expressions work with sample platform data
  2. Check platform data structure - The raw platform data structure might differ from your expectations
  3. Review field availability - Some fields may not be present in all webhook events

Performance Impact

Platform data filtering is designed to be lightweight, but consider:

  • Multiple complex expressions - Avoid extremely complex JSONPath expressions that might slow down webhook delivery
  • Large arrays - Be cautious when extracting large arrays using [*] selectors
  • Nested filtering - Deep nested extractions may impact performance

For more information, visit our Configuration API Reference and Webhook Documentation.