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:
- A change occurs in the connected platform (e.g., new order created)
- Rutter receives the raw platform data
- Your configured JSONPath expressions are applied to extract specific fields
- The webhook is sent with both standardized data AND your filtered platform data
- 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:
1curl "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:
1curl -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:
1curl "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
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
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:
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}
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}
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)
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
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.
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:
1function 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.
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:
1function 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.
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.
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.
1function 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.
1// Example platform data from Shopify
2const 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
12const customerEmail = jsonPath.query(sampleShopifyData, "$.customer.email");
13const lineItems = jsonPath.query(sampleShopifyData, "$.line_items[*].title");
14const total = jsonPath.query(sampleShopifyData, "$.total_price");
15
16console.log('Customer Email:', customerEmail); // ["test@example.com"]
17console.log('Line Items:', lineItems); // ["Product A", "Product B"]
18console.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:
- Check configuration - Verify your platform data filtering is configured correctly
- Verify webhook type - Ensure you've configured filtering for the specific webhook type you're receiving
- Confirm platform - Make sure you've configured filtering for the correct platform
- Review size limits - Check if your filtered data exceeds the 500KB limit
Empty Filtered Results
If your filtered platform data contains empty arrays:
- Test JSONPath expressions - Verify your expressions work with sample platform data
- Check platform data structure - The raw platform data structure might differ from your expectations
- 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.