Webhooks
Send and receive webhooks to integrate Buildorado with any external service.
Webhooks let you connect Buildorado with any external service that supports HTTP callbacks, giving you unlimited integration possibilities beyond the 30+ built-in integrations. Outgoing webhooks send data from your workflows to external APIs when events occur -- a form is submitted, a payment is processed, or a workflow completes. Incoming webhooks let external services trigger Buildorado workflows by sending HTTP requests to a unique endpoint. Combined with the Respond to Webhook node, you can build complete request-response APIs on top of Buildorado's workflow engine. Whether you are syncing data to a custom CRM, triggering workflows from Stripe events, or connecting to Zapier, webhooks are the universal integration layer.
Outgoing Webhooks
Outgoing webhooks send HTTP requests from your Buildorado workflow to an external URL when a specific step in the workflow executes. Use them to push form submission data to your backend, notify third-party services, or call any REST API.
Configuration
Add an HTTP Request or Webhook action node to your workflow canvas and configure the following settings:
| Setting | Description |
|---|---|
| URL | The endpoint to call (must be HTTPS in production) |
| Method | GET, POST, PUT, PATCH, or DELETE |
| Headers | Custom HTTP headers as key-value pairs |
| Body | JSON payload with {{variableName.property}} template variables |
| Authentication | None, Bearer token, API key (header or query), or Basic auth |
| Timeout | Maximum wait time in milliseconds (default: 30,000ms, max: 120,000ms) |
Request Body with Dynamic Variables
Compose the JSON body using template variables from upstream form fields and nodes:
{
"name": "{{form.name}}",
"email": "{{form.email}}",
"company": "{{form.company}}",
"budget": {{form.budget}},
"source": "buildorado",
"workflow_id": "{{workflow.id}}",
"submission_id": "{{submission.id}}",
"submitted_at": "{{submission.createdAt}}"
}All {{variableName.property}} references are resolved at execution time with the actual values from the current workflow run.
Authentication Options for Outgoing Requests
| Auth Type | Configuration |
|---|---|
| None | No authentication header is added |
| Bearer Token | Sends Authorization: Bearer <token> header |
| API Key (Header) | Sends a custom header with your API key (e.g., X-API-Key: your-key) |
| API Key (Query) | Appends the API key as a query parameter (e.g., ?api_key=your-key) |
| Basic Auth | Sends Authorization: Basic <base64(username:password)> header |
Store sensitive values like API keys and tokens in your workflow's credential configuration rather than hardcoding them in the node. Buildorado encrypts stored credentials with AES-256 using AWS KMS.
Retry Behavior
If the outgoing webhook fails (network error, 5xx response, or timeout), Buildorado retries the request with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 5 seconds |
| 2nd retry | 30 seconds |
| 3rd retry | 2 minutes |
After 3 failed retries, the node is marked as failed. If you have an error handler node connected, it catches the failure and can trigger fallback logic -- such as sending an alert to Slack or logging the error.
Timeout Configuration
The default timeout is 30 seconds. If your external service needs more time to process (e.g., a slow API or heavy computation), increase the timeout up to 120 seconds. If the request exceeds the timeout, it is treated as a failure and enters the retry cycle.
For long-running operations, consider having your external service respond immediately with a 202 Accepted and then call back to Buildorado via an incoming webhook when processing completes.
Response Handling
The outgoing webhook node captures the HTTP response and makes it available as output variables for downstream nodes:
| Output Variable | Description |
|---|---|
statusCode | HTTP status code (e.g., 200, 201, 404) |
body | Response body parsed as JSON (if valid JSON) |
headers | Response headers as key-value pairs |
You can reference these in downstream nodes. For example, if your API returns a record ID:
New record created: {{httpRequest.body.id}}Use conditional logic to branch on the status code:
[HTTP Request] → [Branch: Status Code]
→ statusCode == 200 → [Email: Success confirmation]
→ statusCode != 200 → [Slack: #errors "Webhook failed with {{httpRequest.statusCode}}"]Incoming Webhooks (Triggers)
Incoming webhooks let external services start a Buildorado workflow by sending an HTTP request. This turns your workflow into an API endpoint that processes incoming data.
Setting Up an Incoming Webhook
- Open or create a workflow in the visual canvas.
- Add a Webhook Trigger node as the starting node of your workflow.
- Buildorado generates a unique webhook URL (e.g.,
https://api.buildorado.io/webhooks/wh_abc123def456). - Copy this URL and configure your external service to send events to it.
- Publish the workflow to activate the webhook endpoint.
The webhook URL is unique to each workflow and does not change when you edit or republish the workflow. Draft (unpublished) workflows do not accept incoming webhooks.
Supported HTTP Methods
The webhook trigger accepts POST, PUT, and PATCH requests by default. GET requests are supported for simple triggers that do not include a body.
Payload Parsing
Buildorado automatically parses the incoming request body based on the Content-Type header:
| Content-Type | Parsing |
|---|---|
application/json | Parsed as JSON -- fields are available as {{webhook.fieldName}} |
application/x-www-form-urlencoded | Parsed as form data |
text/plain | Available as {{webhook.body}} (raw string) |
multipart/form-data | Form fields and file uploads are parsed |
Accessing Webhook Data in Your Workflow
After the webhook trigger fires, all fields from the parsed payload are available as template variables throughout the workflow:
// Incoming payload:
{
"event": "order.created",
"customer_email": "[email protected]",
"amount": 149.99,
"items": [
{ "name": "Widget", "qty": 3 }
]
}Reference these fields in downstream nodes:
Customer: {{webhook.customer_email}}
Amount: ${{webhook.amount}}
First item: {{webhook.items[0].name}}Authentication for Incoming Webhooks
Incoming webhooks support three authentication modes to ensure only authorized services can trigger your workflows:
No Authentication
Accepts any request. Suitable for testing but not recommended for production. Any service or person with the webhook URL can trigger the workflow.
Secret Header
Validate a shared secret in a custom HTTP header. Configure the header name and expected value in the Webhook Trigger node settings.
| Setting | Example |
|---|---|
| Header Name | X-Webhook-Secret |
| Expected Value | your-secret-value-here |
The incoming request must include the header with the exact value. Requests without the header or with an incorrect value receive a 401 Unauthorized response.
JWT (JSON Web Token)
Validate a JSON Web Token passed in the Authorization: Bearer <token> header. Configure the JWT secret or public key in the Webhook Trigger node. Buildorado verifies the token signature and checks expiration (exp) and not-before (nbf) claims.
This is the most secure option and is recommended for production integrations where the calling service supports JWT.
Respond to Webhook Node
The Respond to Webhook logic node lets you send a custom HTTP response back to the service that triggered the incoming webhook. Without this node, Buildorado responds with a default 200 OK and a generic JSON acknowledgment. With it, you control the status code, headers, and body.
Configuration
| Setting | Description |
|---|---|
| Status Code | HTTP status code to return (e.g., 200, 201, 400) |
| Headers | Custom response headers (e.g., Content-Type: application/json) |
| Body | JSON or text response body with {{variableName.property}} variables |
Example: Return Processed Data
// Respond to Webhook configuration:
Status Code: 200
Body:
{
"status": "success",
"record_id": "{{salesforce.recordId}}",
"message": "Lead created in Salesforce"
}The calling service receives this response instead of the default acknowledgment. This is useful when the caller needs to know the result of the workflow processing.
Important: Placement in Workflow
The Respond to Webhook node should be placed at the point in your workflow where you want to send the response. Any nodes after it continue executing asynchronously. This means you can respond quickly (within seconds) and then perform long-running operations (AI processing, multiple API calls) without making the caller wait.
[Webhook Trigger] → [Validate Data] → [Respond to Webhook: 200 OK]
→ [CRM: Create Lead]
→ [Slack: Notify Team]
→ [Email: Welcome Email]Webhook Signatures
Verifying Outgoing Webhook Signatures
Every outgoing webhook from Buildorado includes a signature header that lets you verify the request is authentic and has not been tampered with. The signature is an HMAC-SHA256 hash of the request body using your webhook secret.
| Header | Value |
|---|---|
X-Buildorado-Signature | sha256=<hex-encoded HMAC-SHA256 hash> |
X-Buildorado-Timestamp | Unix timestamp of when the webhook was sent |
Verification Code Examples
JavaScript (Node.js)
const crypto = require('crypto');
function verifyWebhookSignature(body, signature, secret) {
const expectedSignature = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your Express handler:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-buildorado-signature'];
const body = req.rawBody; // raw request body as string
if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook...
const data = JSON.parse(body);
console.log('Verified webhook:', data);
res.status(200).json({ received: true });
});Python
import hmac
import hashlib
def verify_webhook_signature(body: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode('utf-8'),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your Flask handler:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Buildorado-Signature')
body = request.get_data()
if not verify_webhook_signature(body, signature, WEBHOOK_SECRET):
return jsonify({'error': 'Invalid signature'}), 401
data = request.get_json()
print(f'Verified webhook: {data}')
return jsonify({'received': True}), 200PHP
function verifyWebhookSignature(
string $body,
string $signature,
string $secret
): bool {
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
return hash_equals($expected, $signature);
}
// In your endpoint:
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_BUILDORADO_SIGNATURE'] ?? '';
if (!verifyWebhookSignature($body, $signature, $webhookSecret)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
$data = json_decode($body, true);
// Process the webhook...
http_response_code(200);
echo json_encode(['received' => true]);Timestamp Validation
To prevent replay attacks, check the X-Buildorado-Timestamp header and reject requests older than 5 minutes:
const timestamp = parseInt(req.headers['x-buildorado-timestamp'], 10);
const fiveMinutesAgo = Math.floor(Date.now() / 1000) - 300;
if (timestamp < fiveMinutesAgo) {
return res.status(401).json({ error: 'Webhook expired' });
}Common Webhook Patterns
Zapier Integration
Connect Buildorado to Zapier to access thousands of additional integrations:
- In Zapier, create a new Zap with a Webhooks by Zapier trigger (Catch Hook).
- Copy the Zapier webhook URL.
- In your Buildorado workflow, add an outgoing webhook node with the Zapier URL.
- Send test data from Buildorado so Zapier can detect the payload structure.
- Add Zapier actions (e.g., create a Mailchimp subscriber, add a Trello card, update an Asana task).
This lets you use any of Zapier's 5,000+ integrations without waiting for a native Buildorado connector.
Custom CRM Sync
Push form submissions to a custom CRM or internal database:
[Form: Lead Capture]
→ [HTTP Request: POST to CRM API]
URL: https://api.yourcrm.com/v1/contacts
Headers: Authorization: Bearer {{credential.crmApiKey}}
Body: {
"first_name": "{{form.first_name}}",
"last_name": "{{form.last_name}}",
"email": "{{form.email}}",
"phone": "{{form.phone}}",
"source": "buildorado_form",
"notes": "Submitted on {{submission.createdAt}}"
}
→ [Branch: CRM Response]
→ 201 Created → [Email: Welcome]
→ Error → [Slack: #errors "CRM sync failed for {{form.email}}"]Stripe Event Processing
Receive Stripe webhook events and trigger Buildorado workflows:
- Create a Buildorado workflow with a Webhook Trigger node.
- Copy the webhook URL.
- In Stripe Dashboard > Developers > Webhooks, add the URL and select events (e.g.,
invoice.paid,customer.subscription.deleted). - Process the event in your workflow:
[Webhook Trigger: Stripe Events]
→ [Branch: Event Type]
→ "invoice.paid" → [Google Sheets: Log payment] → [Slack: #payments]
→ "customer.subscription.deleted" → [Email: Cancellation survey]
→ "charge.disputed" → [Slack: #finance "Dispute on {{webhook.data.object.id}}"]GitHub / CI-CD Triggers
Trigger workflows from GitHub events like pull request merges or issue creation:
- Set up a Buildorado webhook trigger with secret header authentication.
- In GitHub, go to your repository Settings > Webhooks and add the Buildorado webhook URL.
- Set the Content type to
application/jsonand add your secret. - Select the events you want to trigger on (e.g., Pull requests, Issues).
Two-Way Sync Pattern
For services that need to both send and receive data:
Outgoing: [Buildorado Form] → [Webhook: POST to External Service]
Incoming: [External Service] → [Webhook Trigger: Buildorado] → [Update Records]This creates a bidirectional data sync where Buildorado pushes new submissions to the external service and the external service pushes updates back to trigger follow-up workflows.
Debugging Webhooks
Outgoing Webhook Debugging
- Check the execution log -- In your Buildorado dashboard, open the workflow's execution history. Each execution shows the request URL, headers, body, response status, and response body for every webhook node.
- Use a request inspector -- Services like webhook.site or RequestBin provide a temporary URL that logs all incoming requests. Point your outgoing webhook to a request inspector to see exactly what Buildorado sends.
- Verify URL accessibility -- Ensure the target URL is reachable from the internet. Buildorado cannot call localhost or private network addresses (blocked by SSRF protection).
- Check response codes -- A 4xx response means the target rejected the request (check authentication, headers, or payload format). A 5xx response means the target server had an error.
Incoming Webhook Debugging
- Publish the workflow -- Incoming webhooks only work on published workflows. Draft workflows do not accept webhook requests.
- Send a test request -- Use
curlor Postman to send a test payload:
curl -X POST https://api.buildorado.io/webhooks/wh_abc123def456 \
-H "Content-Type: application/json" \
-H "X-Webhook-Secret: your-secret" \
-d '{"test": true, "name": "Test User"}'- Check the execution log -- After sending the test, check the workflow execution history to verify the webhook triggered and the data was parsed correctly.
- Verify authentication -- If using secret header auth, ensure the header name and value match exactly. Header names are case-insensitive but values are case-sensitive.
Security Best Practices
For Outgoing Webhooks
- Always use HTTPS for production webhook URLs. HTTP endpoints expose data in transit.
- Authenticate requests using Bearer tokens, API keys, or Basic auth. Never send sensitive data to unauthenticated endpoints.
- Validate responses -- branch on status codes to detect and handle failures.
- Set appropriate timeouts -- do not let a slow external service block your workflow indefinitely.
- Store credentials securely -- use Buildorado's credential store instead of hardcoding secrets in webhook configurations.
For Incoming Webhooks
- Enable authentication -- use secret header or JWT validation for all production webhooks. Never leave incoming webhooks unauthenticated in production.
- Validate the payload -- use branch nodes to check for required fields before processing.
- Keep webhook URLs private -- treat your webhook URL like a password. Do not publish it in public repositories or documentation.
- Use the Respond to Webhook node -- return appropriate status codes (200 for success, 400 for bad requests) so calling services can detect issues.
- Monitor for abuse -- check your workflow execution logs for unexpected triggers that might indicate your webhook URL has been leaked.
For Webhook Signatures
- Always verify signatures in your receiving endpoint for outgoing Buildorado webhooks.
- Use timing-safe comparison functions (
crypto.timingSafeEqualin Node.js,hmac.compare_digestin Python,hash_equalsin PHP) to prevent timing attacks. - Check timestamps to reject replayed requests older than 5 minutes.
- Rotate secrets periodically and update both sides (Buildorado and your receiving endpoint).
Frequently Asked Questions
What happens if my external service is down when Buildorado sends a webhook?
Buildorado retries failed outgoing webhooks up to 3 times with exponential backoff (5 seconds, 30 seconds, 2 minutes). If all retries fail, the webhook node is marked as failed. You can attach an error handler node to catch failures and trigger fallback logic, such as queueing the data for manual review or sending an alert to Slack.
Can I send webhooks to localhost or internal network addresses?
No. Buildorado blocks requests to private IP ranges (10.x.x.x, 172.16-31.x.x, 192.168.x.x) and localhost as an SSRF protection measure. For development, use a tunneling service like ngrok to expose your local server with a public URL, or use a request inspector service like webhook.site.
How do I test incoming webhooks without publishing the workflow?
You need to publish the workflow for the incoming webhook endpoint to be active. However, you can publish the workflow in a non-discoverable state (no public link) and send test requests using curl or Postman. Check the execution logs in the dashboard to verify the data was received and processed correctly.
Can I use webhooks with Zapier, Make (Integromat), or n8n?
Yes. Any automation platform that supports sending or receiving webhooks can integrate with Buildorado. For outgoing webhooks, configure the target URL in the webhook node. For incoming webhooks, copy the Buildorado webhook URL and paste it into the automation platform's webhook action. See the Zapier integration pattern above for a step-by-step example.