Skip to content

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 –
  1. Add Webhook Out task to workflow
  2. Select HTTP method (GET or POST usually)
  3. Enter destination URL
  4. Add request body (for POST/PUT)
  5. Configure headers if needed
  6. 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:

Method: POST
URL: https://api.system.com/contacts
Body: { "email": "{{task_15001_email}}" }

GET - Retrieve Data

Fetch information from external system.

When to use:

  • Look up data
  • Check status
  • Retrieve records

Configuration:

Method: GET
URL: https://api.system.com/contact?email={{task_15001_email}}

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:

Method: PATCH
URL: https://api.system.com/contact/12345
Body: { "phone": "{{task_15001_phone}}" }

DELETE - Remove Data

Delete records from external system.

When to use:

  • Remove contacts
  • Cancel subscriptions
  • Clean up data

Configuration:

Method: DELETE
URL: https://api.system.com/contact/12345

URL Configuration

Static URL

Simple fixed endpoint:

https://api.system.com/webhook

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:

https://api.system.com/search?email={{task_15001_email}}&status=active

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:

{{task_15001_company}} = "ABC & Co."
Result: ABC%20%26%20Co.

Headers

Content-Type

Tells server what format you're sending:

JSON (Most Common):

Content-Type: application/json

Form Data:

Content-Type: application/x-www-form-urlencoded

XML:

Content-Type: application/xml

Plain Text:

Content-Type: text/plain

Authorization

API Key in Header:

Authorization: Bearer your_api_key_here

Basic Auth:

Authorization: Basic base64(username:password)

Custom API Key Header:

X-API-Key: your_api_key
Api-Token: your_token

Accept

Tell server what format you want back:

Accept: application/json

Custom Headers

Add any headers required by the API:

X-Custom-Header: value
User-Agent: BaseCloud/1.0
X-Request-ID: {{task_48001_timestamp}}

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:

email={{task_15001_email}}&name={{task_15001_full_name}}&phone={{task_15001_phone}}

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

Contact: {{task_15001_full_name}}
Email: {{task_15001_email}}
Message: {{task_55001_message}}

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:

{
  "category": 3,
  "messages": [{ "message": "Dear {{1}}, your reference is {{2}}." }]
}

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

Headers:
  Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

API Key

In Header:

Headers:
  X-API-Key: sk_live_abc123xyz789

In URL:

URL: https://api.system.com/endpoint?api_key=your_key_here

Basic Authentication

Headers:
  Authorization: Basic base64_encoded_credentials

Calculate Base64:

  1. Combine: username:password
  2. Encode to Base64
  3. Use in header

OAuth2

For OAuth2 APIs:

  1. Go to Settings → App Connections
  2. Configure OAuth2 app credentials
  3. Authorize connection
  4. 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

Form Submission
  └─ Webhook Out   POST the submission to the other system's endpoint

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

  1. Never expose API keys - Store in secure settings, reference with variables
  2. Use HTTPS - Never send sensitive data over HTTP
  3. Validate responses - Check status codes before proceeding
  4. Rate limiting - Add delays in loops
  5. Timeout settings - Don't wait forever for responses

Reliability

  1. Error handling - Always check {{task_x_success}}
  2. Retry logic - Implement retries for transient failures
  3. Idempotency - Design webhooks that can safely retry
  4. Logging - Log webhook calls for debugging
  5. Test endpoints - Use test/sandbox APIs first

Performance

  1. Batch when possible - Send multiple items per request
  2. Async webhooks - Don't wait for response if not needed
  3. Minimize data - Send only required fields
  4. Cache tokens - Store auth tokens, don't re-auth every request
  5. Compression - Enable gzip if API supports it

Maintainability

  1. Document APIs - Comment webhook purpose and format
  2. Version control - Track API version in use
  3. Error messages - Include helpful context
  4. Consistent naming - Use clear task names
  5. 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:

  1. API key correct and active?
  2. Header format correct? Authorization: Bearer key
  3. Token expired? (refresh OAuth2)
  4. API permissions sufficient?

Bad Request (400)

Common causes:

  1. Invalid JSON format
  2. Missing required fields
  3. Wrong data types
  4. Invalid field values

Debug: View execution history:

  • Check request body sent
  • Read error response message
  • Compare to API documentation

Not Found (404)

Check:

  1. URL correct?
  2. Endpoint exists?
  3. Dynamic URL variable empty?
  4. 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:

  1. Upload file to cloud storage first
  2. 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?

  1. View execution history
  2. Check request tab (URL, headers, body sent)
  3. Check response tab (status, body received)
  4. Compare with API documentation
  5. Test URL in Postman/curl first

Can I call SOAP APIs?

Yes, using XML:

Method: POST
Content-Type: text/xml
Body: <soap:Envelope>...</soap:Envelope>

What if API requires special encoding?

Most handled automatically. For special cases, use Code task to prepare data first.


  • 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