Skip to main content

Incoming Webhooks

Receive real-time data from external systems and trigger workflows in Expedify when events occur in your other tools and platforms.

What are Incoming Webhooks?

Incoming webhooks allow external systems to push data into Expedify, enabling:

  • Receive form submissions from your website
  • Get notifications from payment processors (Stripe, Razorpay)
  • Sync data from other CRMs or tools
  • Trigger workflows from external events
  • Capture leads from marketing platforms

Use Cases:

  • Website contact form submissions → Create contacts
  • E-commerce orders → Create deals
  • Payment received → Update deal status
  • Support ticket created → Create task
  • Calendar event booked → Trigger workflow

Creating an Incoming Webhook

Step 1: Access Webhook Settings

  1. Go to SettingsWebhooks
  2. Click Incoming Webhooks tab
  3. Click Create Webhook button

Step 2: Configure Webhook

Basic Information:

  • Name: Descriptive name (e.g., "Contact Form Submissions")
  • Description: What this webhook receives
  • Status: Active/Inactive

Webhook URL Generated:

https://api.expedify.ai/webhooks/incoming/{webhook_id}

Security Settings:

  • Secret Key: Auto-generated for verification
  • IP Whitelist: Restrict to specific IPs (optional)
  • Rate Limit: Max requests per minute

Data Handling:

  • Target Entity: Contact/Company/Deal/Task
  • Field Mapping: Map webhook data to Expedify fields
  • Workflow Trigger: Optionally trigger workflow on receipt

Step 3: Copy Webhook URL

  1. Copy generated webhook URL
  2. Add to external system
  3. Configure external system to send POST requests
  4. Save incoming webhook settings

Field Mapping

Automatic Field Detection

Expedify can auto-detect fields from incoming data:

Example Incoming Data:

{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+1234567890",
"company": "Acme Corp"
}

Auto-Detected Mapping:

  • firstName → Contact First Name
  • lastName → Contact Last Name
  • email → Contact Email
  • phone → Contact Phone
  • company → Company Name

Manual Field Mapping

Map webhook fields to Expedify fields manually:

  1. Click Configure Mapping
  2. See webhook field on left
  3. Select Expedify field on right
  4. Example Mappings:
    • form_name → Contact First Name
    • form_email → Contact Email
    • form_phone → Contact Phone
    • form_message → Note Content
    • source → Tag

Transformation Rules

Apply transformations to incoming data:

Text Transformations:

  • Uppercase / Lowercase
  • Trim whitespace
  • Remove special characters
  • Format phone numbers

Data Transformations:

  • Parse dates (various formats)
  • Convert currency
  • Split full name → First/Last
  • Combine fields

Conditional Mapping:

  • Map based on conditions
  • Default values if empty
  • Skip if value matches pattern

Workflow Triggers

Auto-Trigger Workflows

Trigger workflows automatically when webhook receives data:

Setup:

  1. Enable Trigger Workflow option
  2. Select workflow from dropdown
  3. Map webhook data to workflow variables
  4. Save incoming webhook

How It Works:

  1. External system sends data
  2. Incoming webhook receives POST request
  3. Creates/updates Expedify record
  4. Automatically triggers selected workflow
  5. Workflow receives record data

Example Use Case:

  • Webhook receives form submission
  • Creates new contact
  • Triggers "Lead Nurture" workflow
  • Workflow sends welcome email
  • Creates follow-up task

Supported Data Formats

{
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@company.com",
"phone": "+1234567890",
"company": "Tech Corp",
"message": "Interested in your product"
}

Form URL-Encoded

first_name=Jane&last_name=Smith&email=jane@company.com&phone=+1234567890

XML

<?xml version="1.0"?>
<contact>
<first_name>Jane</first_name>
<last_name>Smith</last_name>
<email>jane@company.com</email>
<phone>+1234567890</phone>
</contact>

Content-Type Headers:

  • JSON: application/json
  • Form: application/x-www-form-urlencoded
  • XML: application/xml

Security

Webhook Secret

Verify incoming requests using webhook secret:

Request Header:

X-Webhook-Secret: your-secret-key

Verification:

// Node.js example
app.post('/your-middleware', (req, res) => {
const secret = req.headers['x-webhook-secret'];

if (secret !== EXPEDIFY_WEBHOOK_SECRET) {
return res.status(401).send('Unauthorized');
}

// Forward to Expedify
await fetch(EXPEDIFY_WEBHOOK_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Secret': secret
},
body: JSON.stringify(req.body)
});

res.status(200).send('OK');
});

IP Whitelisting

Restrict webhook access to specific IP addresses:

Configure IPs:

  1. Edit incoming webhook
  2. Go to Security section
  3. Add Allowed IP Addresses
  4. Save changes

Format:

  • Single IP: 192.168.1.1
  • CIDR range: 192.168.1.0/24
  • Multiple IPs: One per line

Rejected Requests:

  • Returns 403 Forbidden
  • Logged in webhook activity
  • Does not consume rate limit

Rate Limiting

Protect against abuse with rate limits:

Settings:

  • Requests per minute: Default 60
  • Burst allowance: Allow temporary spikes
  • Blocking: Temporary block on exceed

Headers in Response:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1642345678

Rate Limit Exceeded:

  • Returns 429 Too Many Requests
  • Retry-After header included
  • Request blocked but logged

Webhook Activity Logs

Viewing Incoming Requests

Track all incoming webhook activity:

Log Entries Show:

  • Timestamp: When request received
  • Source IP: Request origin
  • Status: Success/Failed
  • Action: Created/Updated contact
  • Payload Size: Request size
  • Response Time: Processing duration
  • Error: Failure reason (if failed)

Filtering Logs

Filter by:

  • Status: Success, Failed, Blocked
  • Date Range: Time period
  • Source IP: Specific IPs
  • Action: Create/Update/Skip

Payload Inspection

View full request details:

  • Headers: All request headers
  • Raw Payload: Exact data received
  • Mapped Data: How fields were mapped
  • Result: Created/updated record
  • Error Details: Stack trace if failed

Common Integration Examples

Website Contact Form

HTML Form:

<form action="https://api.expedify.ai/webhooks/incoming/abc123" method="POST">
<input type="text" name="first_name" required>
<input type="text" name="last_name" required>
<input type="email" name="email" required>
<input type="tel" name="phone">
<textarea name="message"></textarea>
<button type="submit">Submit</button>
</form>

JavaScript Form Submission:

const form = document.getElementById('contact-form');

form.addEventListener('submit', async (e) => {
e.preventDefault();

const formData = {
first_name: form.first_name.value,
last_name: form.last_name.value,
email: form.email.value,
phone: form.phone.value,
message: form.message.value
};

await fetch('https://api.expedify.ai/webhooks/incoming/abc123', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Secret': 'your-secret-key'
},
body: JSON.stringify(formData)
});

alert('Form submitted!');
});

Stripe Payment Webhook

Stripe Webhook Setup:

  1. Go to Stripe Dashboard → Webhooks
  2. Add endpoint: https://api.expedify.ai/webhooks/incoming/xyz789
  3. Select events: payment_intent.succeeded
  4. Copy webhook secret

Middleware to Transform:

// Middleware to transform Stripe data to Expedify format
app.post('/stripe-webhook', (req, res) => {
const { type, data } = req.body;

if (type === 'payment_intent.succeeded') {
const payment = data.object;

// Transform to Expedify format
const expedifyData = {
email: payment.receipt_email,
amount: payment.amount / 100,
currency: payment.currency,
payment_id: payment.id,
status: 'paid'
};

// Forward to Expedify webhook
await fetch(EXPEDIFY_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(expedifyData)
});
}

res.status(200).send('OK');
});

Zapier Integration

Zapier Setup:

  1. Create Zap
  2. Choose trigger app (e.g., Google Forms)
  3. Action: Webhooks by Zapier
  4. Action Type: POST
  5. URL: Your Expedify webhook URL
  6. Payload: Map form fields
  7. Test and activate

Zapier Payload:

{
"first_name": "{{First Name}}",
"last_name": "{{Last Name}}",
"email": "{{Email}}",
"source": "Google Forms"
}

Make.com (Integromat)

Make Scenario:

  1. Add webhook module
  2. Create webhook
  3. Copy webhook URL
  4. Paste Expedify incoming webhook URL
  5. Add HTTP Request module
  6. Configure POST to Expedify
  7. Map fields
  8. Activate scenario

Response Handling

Success Response

{
"success": true,
"message": "Contact created successfully",
"record_id": "contact_abc123",
"entity": "contact",
"action": "created"
}

HTTP Status: 200 OK

Validation Error

{
"success": false,
"error": "Validation failed",
"details": {
"email": "Invalid email format",
"phone": "Required field missing"
}
}

HTTP Status: 400 Bad Request

Authentication Error

{
"success": false,
"error": "Unauthorized",
"message": "Invalid webhook secret"
}

HTTP Status: 401 Unauthorized

Rate Limit Error

{
"success": false,
"error": "Rate limit exceeded",
"retry_after": 60
}

HTTP Status: 429 Too Many Requests

Testing Incoming Webhooks

Using cURL

curl -X POST https://api.expedify.ai/webhooks/incoming/abc123 \
-H "Content-Type: application/json" \
-H "X-Webhook-Secret: your-secret-key" \
-d '{
"first_name": "Test",
"last_name": "User",
"email": "test@example.com"
}'

Using Postman

  1. Create new POST request
  2. URL: Your webhook URL
  3. Headers:
    • Content-Type: application/json
    • X-Webhook-Secret: your-secret-key
  4. Body: Raw JSON
  5. Send request
  6. Check response

Using Test Data

  1. Go to incoming webhook settings
  2. Click Test button
  3. Enter test JSON payload
  4. Click Send Test
  5. View result and created record

Deduplication

Prevent Duplicate Records

Email-Based Deduplication:

  • Check if contact with email exists
  • Update existing record instead of creating new
  • Configurable per webhook

Custom Field Deduplication:

  • Use custom field as unique identifier
  • Example: External system ID
  • Match on custom field value

Deduplication Rules:

  1. Skip: Don't create if exists
  2. Update: Update existing record
  3. Create Anyway: Allow duplicates

Best Practices

  1. Use Secret Keys

    • Always include webhook secret in requests
    • Rotate secrets periodically
    • Don't commit secrets to version control
  2. Validate Data

    • Check required fields exist
    • Validate email/phone formats
    • Sanitize input data
  3. Handle Errors

    • Check response status codes
    • Implement retry logic
    • Log failed requests
  4. Monitor Activity

    • Review webhook logs weekly
    • Check for failed requests
    • Investigate anomalies
  5. Test Thoroughly

    • Test with sample data first
    • Verify field mapping is correct
    • Check workflow triggers work

Troubleshooting

Not receiving webhooks?

  • Check webhook is Active
  • Verify URL is correct
  • Check source system is sending data
  • Review activity logs for errors

Data not mapping correctly?

  • Review field mapping configuration
  • Check incoming data format
  • Use payload inspection in logs
  • Verify field names match exactly

Rate limit errors?

  • Reduce request frequency
  • Implement request queuing
  • Contact support for limit increase
  • Check for duplicate requests

Authentication failing?

  • Verify webhook secret is correct
  • Check header name (X-Webhook-Secret)
  • Ensure secret isn't URL-encoded
  • Regenerate secret if compromised

Webhook Limits

Free Plan:

  • 3 incoming webhooks
  • 500 requests/month
  • 60 requests/minute rate limit

Professional Plan:

  • 10 incoming webhooks
  • 5,000 requests/month
  • 120 requests/minute rate limit

Enterprise Plan:

  • Unlimited incoming webhooks
  • Unlimited requests/month
  • Custom rate limits
  • Outgoing Webhooks: Send data to external systems
  • Workflows: Automate actions on webhook receipt
  • API: Alternative integration method

Next Steps

  1. Create Webhook: Set up incoming webhook
  2. Configure Mapping: Map fields correctly
  3. Test Webhook: Send test data
  4. Add Security: Configure secret and IP whitelist
  5. Monitor: Check activity logs

Need help? Contact support through Settings → Support.