Skip to main content

Introduction

Connected Sources is MoEngage’s flexible webhook integration framework that allows you to stream real-time data from any external platform directly into MoEngage. Integrate CRMs, e-commerce platforms, marketing tools, or custom applications with a standardized approach.

How It Works

Connect any external system using three simple steps:

Webhook POST

Your system sends JSON payload to MoEngage endpoint

Transform

Mapper extracts and validates data

Import

Data flows into events & profiles

Key Capabilities

Real-Time Events Stream user actions as they happen Profile Sync Update user attributes automatically Bulk Processing Handle batches in single call Flexible Mapping Transform complex JSON structures Date Merging Combine separate date/time fields Dynamic Attrs Auto-import custom fields

Use Cases

📝 Lead Capture Stream form submissions from Unbounce, Typeform, HubSpot for instant follow-ups 💳 Payment Events Track subscriptions from Stripe, Chargebee (created, failed, expiring) 🎫 Support Tickets Monitor Zendesk/Intercom interactions for satisfaction tracking 🛒 E-commerce Capture orders, carts, views from custom platforms 🛠️ Custom Apps Send events from proprietary systems without native SDKs

🚀 Build Your Integration

Follow these five steps to go from sample payload to live data flowing into MoEngage. 1 Prepare Prerequisites & Payloads 2 Create Build Your Mapper 3 Submit Send to MoEngage 4 Configure Add Webhook URL 5 Test Verify Data Flow

Prepare: Prerequisites & Sample Payloads

Before building your mapper, make sure you have everything ready.
You will need:
  • Webhook capability in your system (HTTP POST)
  • Authentication support (Basic Auth or custom headers)
  • Valid JSON webhook payloads
  • 2-3 sample payloads from your system
  • MoEngage credentials (Workspace ID, Data API Key from Settings → APIs)
⚡ Rate LimitsRecommended maximum: 200 requests/secondFor higher throughput, contact your Solutions Engineering team with: expected volume, use case description, peak/average patterns, and data center location.
💡 Validate early: Paste your sample payloads into JSONLint to confirm they are valid JSON before proceeding.

Create: Build Your Mapper Configuration

The mapper is a JSON configuration that tells MoEngage how to transform your incoming webhook data into events or user profiles. This is the core of your integration.

📋 Choose Your Mapping Type

Two sync types available:
  • mapping_type: "events" - Track events AND create/update user profiles
  • mapping_type: "users" - Create/Update user profiles ONLY (no events)
{
  "partner_name": "integration_name",
  "mapping_type": "events",
  "mappings": {
    "customer_id": "$.user_id",
    "event_name": "$.event_type",
    "user_time": "$.timestamp",
    "platform": "web",
    "app_version": "1.0.0",
    "attr": {
      "custom_field": "$.field_name"
    },
    "user_attributes": {
      "u_em": "$.email"
    }
  },
  "batching": false,
  "payload_validations": {}
}

Field Requirements by Mapping Type

FieldFor “events”For “users”
customer_idRequired - Unique user identifierRequired - Unique user identifier
event_nameRequired - Event nameNot used
user_timeRequired - Event timestampNot used
platformRequired - “web”, “android”, “ios”, “api”Not used
app_versionRequired - Static version stringNot used
user_attributesOptional - Update user profileOptional - Update user profile
attrOptional - Event attributesNot used

📍 JSONPath Quick Reference

Use JSONPath expressions to map fields from your payload to MoEngage fields. Here’s how to read them:
PayloadJSONPathResult
{"email": "user@example.com"}$.emailuser@example.com
{"user":{"email": "test@ex.com"}}$.user.emailtest@ex.com
{"items": [{"name": "A"}]}$.items[0].nameA
{"events": [{"id": 1}, {"id": 2}]}$.events[*].idIterates all (batching)

📌 Complete Field Reference

FieldTypeDescription
partner_nameStringUnique lowercase identifier (e.g., “typeform”)
mapping_typeString”events” OR “users”
customer_idJSONPath🔑 Path to unique user ID (email, phone, custom ID) - links events to profiles
event_nameJSONPath/StringEvent name path or static string. Required for “events” type only
user_timeJSONPath/“#MERGE”Timestamp path (epoch ms preferred) or “#MERGE” for split date/time. Required for “events” only
platformString”web”, “android”, “ios”, or “api”. Required for “events” type only
app_versionStringVersion string (default: “1.0.0”). Required for “events” type only
user_attributesObjectUser profile attributes: u_em (email), u_fn (first name), u_ln (last name), u_mb (mobile)
attrObjectEvent attributes (key-value pairs). Optional for “events” only
batchingBooleantrue for array payloads, false for single events

📋 Starter Template

Copy this template and replace the JSONPath expressions with paths from your actual payload:
{
  "partner_name": "your_integration_name",
  "mapping_type": "events",
  "mappings": {
    "customer_id": "$.user_id",
    "event_name": "$.event_type",
    "user_time": "$.timestamp",
    "platform": "web",
    "app_version": "1.0.0",
    "attr": {
      "custom_field": "$.field_name"
    },
    "user_attributes": {
      "u_em": "$.email",
      "u_fn": "$.first_name"
    }
  },
  "batching": false,
  "payload_validations": {
    "$.event_type": "string"
  }
}

💡 See It in Action: Real-World Examples

Click each example to see the payload and its corresponding mapper configuration side by side.
Scenario: Lead form sends contact info on submission
{
  "email": "john@example.com",
  "first_name": "John",
  "last_name": "Doe",
  "phone": "+14155551234",
  "form_name": "Contact Us",
  "submitted_at": 1704067200000,
  "utm_source": "google"
}
Key Points: Email as unique ID • Static event name • Epoch timestamp • Updates user profile
Scenario: System sends multiple orders in single webhook
{
  "orders": [
    {
      "order_id": "ORD-001",
      "customer_email": "alice@ex.com",
      "order_total": 99.99,
      "currency": "USD",
      "order_date": 1704067200000
    },
    {
      "order_id": "ORD-002",
      "customer_email": "bob@ex.com",
      "order_total": 149.50,
      "currency": "USD",
      "order_date": 1704070800000
    }
  ]
}
✅ Key Points: batching=true for arrays • [*] wildcard iterates • Creates separate event per order
Scenario: Separate date and time fields need combining
{
  "user_email": "user@example.com",
  "event_type": "Webinar Registration",
  "webinar_name": "Product Demo",
  "date_registered": "2024-10-25",
  "time_registered": "14:30:00"
}
✅ Key Points: user_time="#MERGE" signals merging • #MERGE section defines fields • formats specifies pattern
Scenario: CRM sends profile updates without event tracking
{
  "email": "sarah@example.com",
  "first_name": "Sarah",
  "last_name": "Williams",
  "phone": "+14155559999",
  "subscription_tier": "Premium",
  "account_status": "Active"
}
✅ Key Points: mapping_type="users" • No event created • No event_name/user_time/platform needed
Scenario: Track pre-login behavior, merge after identification
{
  "session_id": "anon_abc123xyz",
  "event": "Product Viewed",
  "product_id": "PROD-001",
  "product_name": "Wireless Headphones",
  "timestamp": 1704067200000
}
🔄 Merging Flow: After login, send event with both customer_id and anon_id. MoEngage auto-merges anonymous history to identified profile.
Pro Tip: Using create_all The create_all attribute allows you to iterate through all keys within a specified object from your payload. This is highly recommended when dealing with objects whose keys are dynamic, frequently changing, or constantly expanding. Instead of mapping every new field manually, create_all grabs them all at once!
Scenario: Syncing user profiles from a CRM where custom fields are constantly added to a user_attributes object.
{
  "customer_id": "CUST-8890",
  "first_name": "Alex",
  "last_name": "Taylor",
  "email": "alex.t@example.com",
  "phone": "+1234567890",
  "user_attributes": {
    "modified_time": "25-10-2024 14:30:00",
    "lead_score": 85,
    "industry": "Software",
    "lifecycle_stage": "MQL"
  }
}
✅ Key Points: Standard fields are mapped directly (e.g., u_fn) • create_all automatically pulls in lead_score, industry, and lifecycle_stage without explicit mapping.
Scenario: A CRM sends an event where both the user properties and the event details contain dynamic, unpredictable keys.
{
  "customer_id": "CUST-8890",
  "event_name": "Deal Advanced",
  "user_attributes": {
    "account_manager": "Sarah Jenkins",
    "region": "EMEA"
  },
  "event_attributes": {
    "modified_time": "26-10-2024 09:15:00",
    "deal_value": 50000,
    "previous_stage": "Demo",
    "new_stage": "Negotiation"
  }
}
✅ Key Points: create_all works inside both user_attributes and event attr objects simultaneously • Perfect for heavily customized CRM payloads.
Timestamps: Use epoch milliseconds (integer) when possible — no format specification needed! If your payload uses string timestamps, specify the format in the formats section.
Format StringExample
yyyy-MM-dd2024-10-25
yyyy/MM/dd2024/10/25
dd/MM/yyyy25/10/2024
dd-MM-yyyy25-10-2024
yyyy-MM-dd HH:mm:ss2024-10-25 14:30:00
dd-MM-yyyy HH:mm:ss25-10-2024 14:30:00
dd/MM/yyyy HH:mm:ss25/10/2024 14:30:00
yyyy/MM/dd HH:mm:ss2024/10/25 14:30:00
yyyy-MM-dd'T'HH:mm:ssZ2024-10-25T14:30:00+0530
yyyy-MM-dd HH:mm:ss.SSSSSS2024-10-25 14:30:00.123456
yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'2024-10-25T14:30:00.123456Z
Also supported: dd/MM/yyyy and dd-MM-yyyy variants with T, Z, and microsecond suffixes.
🎨 Prefer a visual tool? Use the Visual Mapper Generator to build your JSON configuration with a guided interface.

Submit: Send Your Mapper to MoEngage

Once your mapper JSON is ready, email support@moengage.com with:
  • Completed mapper JSON (attached)
  • Sample webhook payload(s)
  • Integration details: partner name, Workspace ID, Data Center, use case

Configure: Add the Webhook URL

MoEngage will provide you a unique webhook URL. Add it to your source system with Basic Auth credentials (Workspace ID as username, Data API Key as password). For events: https://api-0X.moengage.com/v1/partner/<partner_name>/events/?configName=<config_name> For users: https://api-0X.moengage.com/v1/partner/<partner_name>/users/?configName=<config_name>

Test: Verify Your Data Flow

Use Postman to send your sample payload to the webhook URL. Verify a 200 OK response, save the request_id, then check MoEngage Dashboard → Analytics → Events (allow 1-2 minutes for processing).

✅ Understanding API Responses

Different response codes indicate different outcomes:
Status: Your request was successfully received and queued for processing.
{
  "request_id": "uhdvtjxa",
  "name": "integration_name",
  "description": "Successfully submitted for processing"
}
Next Steps: Save the request_id. Your data should appear in MoEngage within 1-2 minutes.
Cause: A field defined as mandatory in your mapper is missing from the payload.
{
  "error": {
    "code": "e_9004",
    "message": "Required field 'Request.data.actions.action' is missing in the payload",
    "target": "payload_validation",
    "details": [{ "code": "e_9004", "target": "payload_validation", "message": "Required field 'Request.data.actions.action' is missing in the payload" }]
  }
}
🔧 How to Fix: Verify JSONPath expressions match your payload structure and ensure all required fields are present.
Cause: Your JSON payload is malformed or doesn’t match the expected structure.
{
  "error": {
    "code": "e_9004",
    "message": "The provided payload is invalid",
    "target": "payload_validation",
    "details": [{ "code": "e_9004", "target": "payload_validation", "message": "The provided payload is invalid" }]
  }
}
🔧 How to Fix: Validate JSON using JSONLint and check for missing braces, brackets, or commas.
Cause: Invalid Basic Auth credentials or missing Authorization header.
{
  "status": "fail",
  "error": { "message": "Invalid authorization format. Expected Basic authentication", "type": "Authentication required", "request_id": "70e2fd" }
}
🔧 How to Fix: In Postman, select Basic Auth and enter your Workspace ID as username and Data API Key as password.
If you encounter an error response not covered above, contact MoEngage Solutions Engineering with:
  • Complete error response (JSON)
  • Your mapper configuration (JSON)
  • Sample payload you were testing (JSON)
  • Expected behavior vs actual behavior

🔧 Common Issues

Events not appearing Verify 200 OK response • Check customer_id path • Confirm timestamp format • Wait 2-3 min • Contact MoEngage with request_id 🔀 Wrong attributes Test JSONPath at jsonpath.com • Verify payload structure • Check field name typos (case-sensitive) Timestamp errors Match format string exactly • Use epoch ms when possible • Include timezone for ISO format 📦 Bulk not processing Set batching=true • Use [*] in all paths • Check array location in payload create_all issues Verify path points to object • Ensure key-value pairs • Check nesting (works one level deep)

🛠️ Helpful Tools

✅ JSONLint Validate syntax
Visit jsonlint.com →
🗺️ JSONPath Test expressions Visit jsonpath.com → 🪝 Webhook.site Inspect payloads Visit webhook.site → 📮 Postman Test API calls Visit postman.com → ⏰ Epoch Converter Date conversions Visit epochconverter.com → 🎨 Mapper Generator Visual config tool Open Tool →

❓ FAQ

Yes. Include both user_attributes and attr in your mapper. Profile updates and event creation happen simultaneously.
A new profile is created automatically. If customer_id already exists, the event associates with the existing profile.
Yes. Contact MoEngage with the updated JSON. They’ll deploy a new version with a new config_name. Your old URL continues working with the previous mapper.
Maximum 1MB recommended. For bulk requests, batch 100-500 events per call for optimal performance.
Use JSONPath notation: $.orders[0].items[0].name for specific items or $.orders[*].items[*].name for batching. Complex nesting may require flattening first.

🆘 Support

Need Help?
  • 💬 General Questions: Contact your MoEngage Customer Success Manager
  • 🔧 Technical Support: Email support@moengage.com with:
    • Mapper JSON (attached)
    • Sample webhook payload
    • Request ID from response
    • Issue description
  • 🎨 Mapper Help: Share your payload & requirements - our team will assist