6.6 KiB
6.6 KiB
n8n Webhook Request Format
How Data is Sent to n8n
Backend Request Format
Our backend sends data like this:
// URL with query parameters
const url = 'https://workflows.tech4bizsolutions.com/webhook-test/04e677f5-ec57-4772-bf12-96f2610d4b9c?per_page=100&page=1'
// POST body sent directly (not wrapped)
const body = {
provider: "zoho",
service: "crm",
module: "leads",
acces_token: "1000.xxxxx",
instance_url: null
}
// Send to n8n
axios.post(url, body, {
headers: { 'Content-Type': 'application/json' }
})
What n8n Receives
n8n automatically structures the incoming data as:
{
body: {
provider: "zoho",
service: "crm",
module: "leads",
acces_token: "1000.xxxxx",
instance_url: null
},
query: {
per_page: "100",
page: "1"
},
headers: {
"content-type": "application/json"
}
}
How n8n Workflow Accesses Data
Provider/Service/Module (for routing)
$json.body.provider // "zoho" or "salesforce"
$json.body.service // "crm", "books", "people", "projects"
$json.body.module // "leads", "contacts", "accounts", etc.
Access Token (for API calls)
$json.body.acces_token // "1000.xxxxx" or "00DdN00000ne1xG!..."
Instance URL (for Salesforce)
$json.body.instance_url // "https://yourinstance.salesforce.com"
Query Parameters (for pagination/filters)
$json.query // Full query object
$json.query.per_page // "100"
$json.query.page // "1"
$json.query.instance_url // Also available here for Salesforce
Provider-Specific Examples
Zoho Request
Backend Sends:
POST https://workflows.tech4bizsolutions.com/webhook-test/04e677f5-ec57-4772-bf12-96f2610d4b9c?per_page=200&page=1
Content-Type: application/json
{
"provider": "zoho",
"service": "crm",
"module": "leads",
"acces_token": "1000.a1b2c3d4e5f6...",
"instance_url": null
}
n8n Workflow Uses:
// Switch routing
$json.body.provider // "zoho"
$json.body.service // "crm"
$json.body.module // "leads"
// HTTP Request to Zoho API
URL: https://www.zohoapis.com/crm/v2/Leads
Headers:
Authorization: Zoho-oauthtoken {{ $json.body.acces_token }}
Query:
{{ $json.query.toJsonString() }} // {"per_page":"200","page":"1"}
Salesforce Request
Backend Sends:
POST https://workflows.tech4bizsolutions.com/webhook-test/04e677f5-ec57-4772-bf12-96f2610d4b9c?instance_url=https%3A%2F%2Fability-computing-5372.my.salesforce.com
Content-Type: application/json
{
"provider": "salesforce",
"service": "crm",
"module": "leads",
"acces_token": "00DdN00000ne1xG!AQEAQN0M3b...",
"instance_url": "https://ability-computing-5372.my.salesforce.com"
}
n8n Workflow Uses:
// Switch routing
$json.body.provider // "salesforce"
$json.body.service // "crm"
$json.body.module // "leads"
// HTTP Request to Salesforce API
URL: {{ $json.query.instance_url }}/services/data/v59.0/query/?q=SELECT+Id,FirstName...
Headers:
Authorization: Bearer {{ $json.body.acces_token }}
Testing with cURL
Test Zoho
curl --location 'https://workflows.tech4bizsolutions.com/webhook-test/04e677f5-ec57-4772-bf12-96f2610d4b9c?per_page=100&page=1' \
--header 'Content-Type: application/json' \
--data '{
"provider": "zoho",
"service": "crm",
"module": "leads",
"acces_token": "1000.your_zoho_token_here"
}'
Test Salesforce
curl --location 'https://workflows.tech4bizsolutions.com/webhook-test/04e677f5-ec57-4772-bf12-96f2610d4b9c?instance_url=https%3A%2F%2Fability-computing-5372.my.salesforce.com' \
--header 'Content-Type: application/json' \
--data '{
"provider": "salesforce",
"service": "crm",
"module": "leads",
"acces_token": "00DdN00000ne1xG!your_sf_token_here"
}'
Implementation in Backend
src/integrations/n8n/client.js
async callWebhook(payload) {
// 1. Build URL with query parameters
const queryParams = new URLSearchParams(payload.query || {}).toString();
const url = `${this.baseUrl}/${this.webhookPath}/${this.webhookId}${queryParams ? '?' + queryParams : ''}`;
// 2. Prepare POST body (sent directly, not wrapped)
const requestBody = {
provider: payload.provider,
service: payload.service,
module: payload.module,
acces_token: payload.acces_token,
instance_url: payload.instance_url || null
};
// 3. Send to n8n
const response = await axios.post(url, requestBody, {
headers: { 'Content-Type': 'application/json' }
});
return response.data;
}
Key Points
- Direct POST Body: We send the data object directly, not wrapped in another object
- Query Parameters in URL: Pagination and other params go in the URL query string
- n8n Auto-wraps: n8n automatically makes it available as
$json.bodyand$json.query - Same Format for All Providers: Zoho, Salesforce, and others use the same structure
Debugging
View Raw Request in n8n
In your n8n workflow, add a "Set" or "Edit Fields" node right after the webhook to see exactly what you're receiving:
// Add this as a Set node to debug
{
"received_body": "{{ $json.body }}",
"received_query": "{{ $json.query }}",
"provider": "{{ $json.body.provider }}",
"service": "{{ $json.body.service }}",
"module": "{{ $json.body.module }}",
"has_token": "{{ $json.body.acces_token ? 'yes' : 'no' }}"
}
Backend Logs
Check backend logs for:
Calling n8n webhook: { url: '...', provider: 'zoho', service: 'crm', module: 'leads' }
Sending to n8n: { url: '...', body: { provider: 'zoho', ... } }
n8n webhook response received: { provider: 'zoho', status: 200 }
Common Issues
Issue: "$json.body.provider is undefined"
Cause: Data not being sent in POST body
Solution: Ensure axios is sending the object directly:
axios.post(url, requestBody) // ✅ Correct
// NOT
axios.post(url, { body: requestBody }) // ❌ Wrong (double wrapping)
Issue: "$json.query is empty"
Cause: Query parameters not in URL
Solution: Append query params to URL:
const queryString = new URLSearchParams(payload.query).toString();
const url = `${baseUrl}?${queryString}`; // ✅ Correct
Issue: "Invalid token"
Cause: Token not being passed correctly
Solution: Verify token is in $json.body.acces_token:
// In n8n HTTP Request node
Authorization: Zoho-oauthtoken {{ $json.body.acces_token }}
// or
Authorization: Bearer {{ $json.body.acces_token }}
Last Updated: October 9, 2025
Version: 1.0.0