Webhook Out Task¶
Overview¶
The Webhook Out Task sends data to external systems via HTTP/HTTPS. It's the universal integration tool for connecting BaseCloud to any web service, API, or application that accepts HTTP requests.
When to use this task:
- Send data to external CRMs, ERPs, or databases
- Trigger actions in third-party systems (Slack, Zapier, Make)
- Post to custom APIs and webhooks
- Sync data with external services
- Submit forms programmatically
- Update external databases
- Trigger serverless functions
Key Features:
- All HTTP methods (GET, POST, PUT, PATCH, DELETE)
- Custom headers and authentication
- JSON, XML, or form-encoded data
- Dynamic URL construction
- Response parsing and output fields
- Retry logic and error handling
- OAuth2 and API key support
How a call is retried. A short backoff is waited out in place; a long one hands the task back to the queue so it does not hold a worker open:
flowchart TD
A[Send request] --> B{Response}
B -->|2xx| C[Success]
B -->|"429, 5xx, network error"| D{Retries left?}
D -->|"Yes, short wait"| A
D -->|"Yes, long wait"| E[Reschedule to the queue]
D -->|No| F[Fail]
B -->|Other 4xx| F
Quick Start¶
Builder fields¶
The Field column is the label as it appears in the task builder; Key is the name the value is stored under and referenced by.
| Field | Key | Type | Default | Notes |
|---|---|---|---|---|
| Method | webhook_method |
select | POST |
Options: POST · Custom POST (raw body) · GET · Custom GET (raw body) · PUT · Custom PUT (raw body) |
| Authentication | app_connection_id |
app-connection | – | |
| URL | bc_webhook_url |
text | – | |
| Request Headers | headers |
dyn-rows | – | |
| Parameters | data |
dyn-rows | – | Only shown when webhook_method is POST, GET, PUT |
| Request Body | body |
custom-body | – |
- Add Webhook Out task to workflow
- Select HTTP method (GET or POST usually)
- Enter destination URL
- Add request body (for POST/PUT)
- Configure headers if needed
- Save and test
Simple Example:
Method: POST
URL: https://api.external-system.com/contacts
Headers:
Content-Type: application/json
Authorization: Bearer your_api_key
Body:
{
"email": "{{task_15001_email}}",
"name": "{{task_15001_full_name}}"
}
HTTP Methods¶
POST - Create New Data¶
Most common method for sending data to APIs.
When to use:
- Create new records
- Submit forms
- Send notifications
- Trigger actions
Configuration:
GET - Retrieve Data¶
Fetch information from external system.
When to use:
- Look up data
- Check status
- Retrieve records
Configuration:
Note: GET requests typically don't have body.
PUT - Update Existing Data (Complete)¶
Replace entire record with new data.
When to use:
- Update all fields of existing record
- Replace full document
Configuration:
Method: PUT
URL: https://api.system.com/contact/12345
Body: { "email": "new@email.com", "name": "New Name" }
PATCH - Update Existing Data (Partial)¶
Update specific fields only.
When to use:
- Update few fields
- Partial updates preferred by API
Configuration:
DELETE - Remove Data¶
Delete records from external system.
When to use:
- Remove contacts
- Cancel subscriptions
- Clean up data
Configuration:
URL Configuration¶
Static URL¶
Simple fixed endpoint:
Dynamic URL with Variables¶
Build URLs from workflow data:
https://api.system.com/contact/{{task_15001_contact_id}}
https://crm.example.com/deals/{{task_47001_deal_id}}/update
https://api.service.com/{{task_42001_endpoint}}
Query Parameters¶
Add parameters to URL:
Method 1 - In URL:
Method 2 - Separate fields:
URL: https://api.system.com/search
Query Parameters:
email: {{task_15001_email}}
status: active
limit: 10
URL Encoding¶
Special characters are automatically encoded:
Headers¶
Content-Type¶
Tells server what format you're sending:
JSON (Most Common):
Form Data:
XML:
Plain Text:
Authorization¶
API Key in Header:
Basic Auth:
Custom API Key Header:
Accept¶
Tell server what format you want back:
Custom Headers¶
Add any headers required by the API:
Request Body¶
JSON Body (Most Common)¶
Simple object:
{
"email": "{{task_15001_email}}",
"first_name": "{{task_15001_first_name}}",
"last_name": "{{task_15001_last_name}}",
"phone": "{{task_15001_phone}}"
}
Nested object:
{
"contact": {
"email": "{{task_15001_email}}",
"name": "{{task_15001_full_name}}"
},
"metadata": {
"source": "BaseCloud",
"created": "{{task_48001_current_datetime}}"
}
}
With arrays:
{
"email": "{{task_15001_email}}",
"tags": ["Customer", "VIP", "{{task_47001_source}}"],
"custom_fields": [
{
"field": "lead_score",
"value": "{{task_15001_custom_lead_score}}"
}
]
}
Form-Encoded Body¶
For application/x-www-form-urlencoded:
XML Body¶
<?xml version="1.0"?>
<contact>
<email>{{task_15001_email}}</email>
<name>{{task_15001_full_name}}</name>
<phone>{{task_15001_phone}}</phone>
</contact>
Raw Text Body¶
Sending Literal {{…}}¶
Before the request is sent, every {{…}} is filled in from the workflow, and any placeholder left
unmatched is removed. So a body meant to carry the braces through, such as a WhatsApp template
created via Picky Assist or Meta, arrives with its {{1}} blanked out.
Escape the braces with a backslash to send them as-is: \{\{1\}\} goes out as {{1}}. Escaped and
normal placeholders can be mixed in the same body:
{
"category": {{task_40008_value}},
"messages": [{ "message": "Dear \{\{1\}\}, your reference is \{\{2\}\}." }]
}
Sent as:
The backslashes are removed before the JSON is validated, so they never reach the endpoint. Escaping works in every Webhook Out field (URL, headers, parameters and body). Other task types don't support it.
Authentication¶
Bearer Token¶
API Key¶
In Header:
In URL:
Basic Authentication¶
Calculate Base64:
- Combine:
username:password - Encode to Base64
- Use in header
OAuth2¶
For OAuth2 APIs:
- Go to Settings → App Connections
- Configure OAuth2 app credentials
- Authorize connection
- Reference in task:
{{oauth2_token}}
Response Handling¶
Output Fields¶
| Field | Type | Example | Notes |
|---|---|---|---|
response |
object | {httpCode: 200, body: {...}} |
The whole response. Reach into it as {{task_<ID>_response_httpCode}} and {{task_<ID>_response_body_…}}. |
run |
boolean | true |
false when the call ultimately failed. |
run_text |
string | Webhook sent successfully. |
Carries the failure reason, including how many attempts were made. |
There is no response_code, response_body, response_time, success or error_message field —
everything the call returned is inside response.
A rate-limited call is rescheduled, not failed
If the far end asks the caller to wait, the task is put back on the queue and retried later
rather than reported as an error. run stays true and the workflow continues when it succeeds.
Parsing JSON Responses¶
Access response data using JSON path:
Response:
{
"id": 12345,
"status": "created",
"contact": {
"email": "john@example.com",
"crm_id": "CRM-789"
}
}
Access fields:
{{task_1001_response_body.JSON.id}} → 12345
{{task_1001_response_body.JSON.status}} → created
{{task_1001_response_body.JSON.contact.crm_id}} → CRM-789
Status Code Handling¶
Check if request succeeded:
If Task: {{task_1001_response_code}} Equals 200
True: Continue with success actions
False: Handle error
Common status codes:
- 200 OK - Success (GET)
- 201 Created - Success (POST)
- 204 No Content - Success (DELETE)
- 400 Bad Request - Invalid data sent
- 401 Unauthorized - Auth failed
- 404 Not Found - Endpoint/resource missing
- 500 Server Error - External system error
Real-World Examples¶
Push a new lead to another system¶
Notify a chat channel¶
Google Review Received
└─ If Statement {{task_63001_star_rating}} is 1 or 2
└─ Webhook Out post to the team's incoming webhook
Send data and act on the reply¶
Webhook In
└─ Webhook Out call the pricing API
└─ If Statement {{task_1001_response_httpCode}} is 200
└─ Email send the quote
Advanced Techniques¶
Retry Logic¶
Handle temporary failures:
1. Webhook Out - First attempt
2. If Task - Check {{task_1001_success}} = false
3. Delay - Wait 30 seconds
4. Webhook Out - Retry
Dynamic Endpoint Selection¶
Choose API endpoint based on data:
URL: https://api.system.com/{{task_42001_endpoint_name}}
Example:
- If Premium: endpoint_name = "premium/contacts"
- If Standard: endpoint_name = "contacts"
Batch Requests¶
Send multiple items in one request:
Body:
{
"contacts": [
{"email": "{{task_29001_email}}", "name": "{{task_29001_name}}"},
{"email": "{{task_29002_email}}", "name": "{{task_29002_name}}"}
]
}
Better to use Code task to build array dynamically.
Response-Driven Workflows¶
Use API response to determine next steps:
1. Webhook Out - Check if email exists in external system
2. If Task - Check {{task_1001_response_body.JSON.exists}} = true
- True: Update existing
- False: Create new
Best Practices¶
Security¶
- Never expose API keys - Store in secure settings, reference with variables
- Use HTTPS - Never send sensitive data over HTTP
- Validate responses - Check status codes before proceeding
- Rate limiting - Add delays in loops
- Timeout settings - Don't wait forever for responses
Reliability¶
- Error handling - Always check
{{task_x_success}} - Retry logic - Implement retries for transient failures
- Idempotency - Design webhooks that can safely retry
- Logging - Log webhook calls for debugging
- Test endpoints - Use test/sandbox APIs first
Performance¶
- Batch when possible - Send multiple items per request
- Async webhooks - Don't wait for response if not needed
- Minimize data - Send only required fields
- Cache tokens - Store auth tokens, don't re-auth every request
- Compression - Enable gzip if API supports it
Maintainability¶
- Document APIs - Comment webhook purpose and format
- Version control - Track API version in use
- Error messages - Include helpful context
- Consistent naming - Use clear task names
- Test thoroughly - Verify all scenarios
Troubleshooting¶
Request Timeout¶
Error: Request timeout after 30 seconds
Causes:
- External API slow/down
- Network issues
- Large payload
Solutions:
- Increase timeout setting
- Reduce payload size
- Check external API status
- Add retry logic
Authentication Failed (401)¶
Check:
- API key correct and active?
- Header format correct?
Authorization: Bearer key - Token expired? (refresh OAuth2)
- API permissions sufficient?
Bad Request (400)¶
Common causes:
- Invalid JSON format
- Missing required fields
- Wrong data types
- Invalid field values
Debug: View execution history:
- Check request body sent
- Read error response message
- Compare to API documentation
Not Found (404)¶
Check:
- URL correct?
- Endpoint exists?
- Dynamic URL variable empty?
- HTTP method correct?
Example issue:
URL: https://api.system.com/contact/{{task_15001_external_id}}
If external_id is empty:
https://api.system.com/contact/ → 404
Response Not Parsing¶
Ensure:
✓ Response is valid JSON
✓ Using correct JSON path syntax
✓ Field names match exactly (case-sensitive)
Access: {{task_1001_response_body.JSON.field_name}}
Not: {{task_1001_response_body.field_name}}
Frequently Asked Questions¶
Can I send files/attachments?¶
Not directly. Use multipart/form-data encoding or:
- Upload file to cloud storage first
- Send file URL in webhook
How do I handle pagination?¶
Use Loop task:
1. Webhook Out - Get page 1
2. Code - Extract next_page_url
3. Loop - While next_page_url exists
4. Webhook Out - Get next page
What's the timeout limit?¶
Default: 30 seconds Maximum: 120 seconds (configurable)
Can I make synchronous vs asynchronous requests?¶
All Webhook Out requests are synchronous - workflow waits for response.
For fire-and-forget: Configure external API to return 200 immediately.
How do I debug failed requests?¶
- View execution history
- Check request tab (URL, headers, body sent)
- Check response tab (status, body received)
- Compare with API documentation
- Test URL in Postman/curl first
Can I call SOAP APIs?¶
Yes, using XML:
What if API requires special encoding?¶
Most handled automatically. For special cases, use Code task to prepare data first.
Related Tasks¶
- Code Task - Prepare complex request bodies
- If Task - Handle response conditions
- Loop Task - Multiple webhook calls
- Delay Task - Rate limiting
- Variable Task - Store API responses