Portal Community

Example 1: Parse and Transform a Complex JSON Payload

Scenario: An upstream HTTP Request node returns a deeply nested API response. Flatten and reshape it into the exact structure needed for a downstream MongoDB insert.

// Script property:
const raw = context.input;

// Flatten the nested order response into a flat document
const order = raw.data.order;
const customer = raw.data.order.customer;
const items = raw.data.order.line_items;

return {
  order_id: order.id,
  order_date: order.created_at,
  customer_id: customer.id,
  customer_email: customer.email,
  customer_name: `${customer.first_name} ${customer.last_name}`.trim(),
  total_amount: order.total_price,
  currency: order.currency,
  item_count: items.length,
  items: items.map(item => ({
    sku: item.variant_id,
    title: item.title,
    quantity: item.quantity,
    unit_price: item.price,
    subtotal: (item.quantity * parseFloat(item.price)).toFixed(2)
  })),
  fulfillment_status: order.fulfillment_status ?? "pending",
  tags: order.tags ? order.tags.split(",").map(t => t.trim()) : []
};
Expected outcome: The deeply nested Shopify-style order response is transformed into a clean, flat MongoDB document. The downstream MongoDB/insertOne node receives exactly the structure required — no additional DataMapping needed.

Example 2: Custom Business Logic Calculation (Pricing Engine)

Scenario: Calculate the final price for a customer order by applying tier-based discounts, promotional codes, and tax rules in one place.

// Script property:
const cart = context.vars.cart_items;
const pricingTier = context.vars.customer_tier; // "bronze", "silver", "gold", "platinum"
const promoCode = context.vars.promo_code;
const region = context.vars.customer_region;

// Tier discount rates
const tierDiscounts = { bronze: 0, silver: 0.05, gold: 0.10, platinum: 0.15 };
const tierDiscount = tierDiscounts[pricingTier] ?? 0;

// Calculate subtotal
const subtotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);

// Apply tier discount
let discountAmount = subtotal * tierDiscount;

// Apply promo code (if applicable)
const promoCodes = { "SAVE10": 0.10, "LAUNCH20": 0.20, "VIP30": 0.30 };
const promoDiscount = promoCodes[promoCode] ?? 0;
const promoAmount = subtotal * promoDiscount;

// Total discount (capped at 40% to prevent stacking abuse)
const totalDiscountRate = Math.min(tierDiscount + promoDiscount, 0.40);
const totalDiscount = subtotal * totalDiscountRate;

// Tax rates by region
const taxRates = { "US-CA": 0.0975, "US-NY": 0.08875, "UK": 0.20, "EU": 0.21 };
const taxRate = taxRates[region] ?? 0;
const discountedSubtotal = subtotal - totalDiscount;
const taxAmount = discountedSubtotal * taxRate;
const finalTotal = discountedSubtotal + taxAmount;

return {
  subtotal: parseFloat(subtotal.toFixed(2)),
  tier_discount_pct: (tierDiscount * 100).toFixed(0) + "%",
  promo_discount_pct: (promoDiscount * 100).toFixed(0) + "%",
  total_discount: parseFloat(totalDiscount.toFixed(2)),
  discounted_subtotal: parseFloat(discountedSubtotal.toFixed(2)),
  tax_rate: taxRate,
  tax_amount: parseFloat(taxAmount.toFixed(2)),
  final_total: parseFloat(finalTotal.toFixed(2)),
  currency: "USD",
  pricing_tier: pricingTier,
  promo_applied: promoCode || null
};
Expected outcome: A complete price breakdown object is returned. The downstream order creation node receives data.final_total as the charge amount. All discount and tax logic is encapsulated in one testable script, making it easy to update pricing rules without modifying the workflow structure.

Example 3: Data Validation with Multiple Rules Returning Structured Errors

Scenario: Before inserting a customer record, validate all required fields and business rules. Return a structured error list rather than failing the workflow.

// Script property:
const data = context.input;
const errors = [];

// Required field checks
if (!data.email || !data.email.includes("@")) {
  errors.push({ field: "email", code: "INVALID_EMAIL", message: "A valid email address is required." });
}
if (!data.first_name || data.first_name.trim().length < 2) {
  errors.push({ field: "first_name", code: "TOO_SHORT", message: "First name must be at least 2 characters." });
}
if (!data.phone) {
  errors.push({ field: "phone", code: "MISSING", message: "Phone number is required." });
}

// Business rule checks
if (data.age !== undefined && (data.age < 18 || data.age > 120)) {
  errors.push({ field: "age", code: "OUT_OF_RANGE", message: "Age must be between 18 and 120." });
}
if (data.country && !["US", "UK", "CA", "AU"].includes(data.country)) {
  errors.push({ field: "country", code: "UNSUPPORTED_REGION", message: `Country '${data.country}' is not supported.` });
}
if (data.credit_limit !== undefined && data.credit_limit > 50000 && data.account_type !== "premium") {
  errors.push({ field: "credit_limit", code: "LIMIT_EXCEEDED", message: "Credit limits above $50,000 require a premium account type." });
}

return {
  valid: errors.length === 0,
  error_count: errors.length,
  errors: errors,
  validated_at: new Date().toISOString()
};
Expected outcome: The script always routes to the success port — the validation result is returned as structured data. A downstream IfCondition node checks data.valid === true to decide whether to proceed with the insert or route to a rejection handler that sends the data.errors array back to the user.

Example 4: String Manipulation and Regex Extraction

Scenario: Parse a free-text delivery address entered by a user into structured fields (street, city, state, postal code) using regex patterns.

// Script property:
const rawAddress = context.input.address_text || "";

// Normalise whitespace
const cleaned = rawAddress.replace(/\s+/g, " ").trim();

// Extract US ZIP code (5 or 9 digit)
const zipMatch = cleaned.match(/\b(\d{5}(?:-\d{4})?)\b/);
const postalCode = zipMatch ? zipMatch[1] : null;

// Extract US state abbreviation (2 uppercase letters before ZIP)
const stateMatch = cleaned.match(/\b([A-Z]{2})\s+\d{5}/);
const state = stateMatch ? stateMatch[1] : null;

// Extract city (word(s) before state abbreviation)
const cityMatch = state
  ? cleaned.match(new RegExp(`([A-Za-z\\s]+?)\\s*,?\\s*${state}\\b`))
  : null;
const city = cityMatch ? cityMatch[1].trim() : null;

// Remainder is street address (everything before city)
const streetEnd = city ? cleaned.indexOf(city) : cleaned.length;
const street = cleaned.slice(0, streetEnd).replace(/,$/, "").trim();

// Generate URL-safe slug from company name (for subdomain use)
const companySlug = (context.vars.company_name || "")
  .toLowerCase()
  .replace(/[^a-z0-9]+/g, "-")
  .replace(/^-|-$/g, "");

return {
  raw: rawAddress,
  street: street || null,
  city: city || null,
  state: state || null,
  postal_code: postalCode || null,
  parsed: !!(street && city && state && postalCode),
  company_slug: companySlug
};
Expected outcome: A free-text address like "123 Main St, Springfield, IL 62701" is parsed into { street: "123 Main St", city: "Springfield", state: "IL", postal_code: "62701", parsed: true }. The parsed boolean lets downstream nodes detect incomplete addresses and route to a data-quality review step.