Webhooks & Integrations
Trigger entire DocButterfly document pipelines with a single HTTPS request — from Power Automate, Logic Apps, Zapier, n8n, a cron job, a script, or any system that can make an HTTP call.
What Are DocButterfly Webhooks?
There are two ways to use the DocFlow API:
- Direct endpoint calls — POST to any of our 127+ endpoints (e.g.
/api/ConvertHtmlToPdf) and get a result back. One operation per call. See the API Reference. - Webhooks (published orchestrations) — build a multi-step pipeline visually in the Orchestrator, publish it, and get a unique URL. One HTTPS POST runs the whole pipeline server-side and returns the final result.
Webhooks are the fastest way to integrate: your calling system doesn't need to chain calls, handle intermediate files, or know anything about our API beyond one URL, one header, one JSON body.
How It Works
- Build — assemble a pipeline in the Orchestrator (e.g. HTML → PDF → watermark → email). Each step's output feeds the next.
- Publish — click Publish. You get a unique webhook URL like
/api/Webhook/invoice-pipeline-3f9a1c. - Call — POST to that URL with your API key. The JSON body you send becomes
$input, available to every step in the pipeline. - Receive — the response contains the final step's output plus execution metadata (steps run, tokens used, duration).
The whole pipeline is billed as one token charge (the sum of the step costs), checked up front and deducted only on success. Failed runs are never billed.
Prerequisites
- A DocButterfly account — free trial includes 100 tokens.
- Your API key, from Portal → API Key. Keys look like
df_...and are shown once at creation — store them in a secret manager (Azure Key Vault, environment variable, Zapier/Make connection field), never in source code. - A published orchestration (for webhook calls) — or just pick an endpoint from the API Reference for direct calls.
Base URL
All paths on this page are relative to this base URL. Your full webhook URL (including its unique slug) is shown in the Orchestrator's webhook bar after publishing — use the copy button there.
Step 1 — Build and Publish an Orchestration
- Open Portal → Orchestrator and drag operation blocks onto the canvas. Connect them so each step consumes the previous step's output.
- Use the
$inputblock wherever you want data supplied by the caller at run time — for example, the HTML for a PDF, a recipient email address, or a watermark label. - Save the workflow, then click Publish. A webhook URL appears in the yellow bar at the top:
Your webhook URL
https://docbutterfly.com/api/Webhook/invoice-pipeline-3f9a1c
The slug (invoice-pipeline-3f9a1c) is unique to your workflow and stays stable across re-publishes, so callers never need updating when you edit the pipeline. Unpublishing deactivates the URL immediately (callers get 404).
Step 2 — Call the Webhook
One POST request. Three things matter:
| Part | Value |
|---|---|
| Method / URL | POST /api/Webhook/{your-slug} |
| Auth header | X-API-Key: df_your_api_key (or Authorization: Bearer df_...) |
| Body (optional) | Any JSON object — exposed to the pipeline as $input. Omit it if your pipeline takes no input. |
Request
POST /api/Webhook/invoice-pipeline-3f9a1c HTTP/1.1
Host: docbutterfly.com
X-API-Key: df_your_api_key
Content-Type: application/json
{
"html": "<h1>Invoice #1042</h1><p>Amount due: $250.00</p>",
"customerEmail": "billing@contoso.com",
"watermarkText": "PAID"
}
Response
{
"success": true,
"pipeline": "Invoice Pipeline",
"steps": 3,
"totalTokens": 3,
"duration": 4182,
"result": {
"data": "JVBERi0xLjcKJeLjz9...", // base64 output of the final step
"contentType": "application/pdf"
}
}
result is whatever the last step of your pipeline produces. For file-producing steps that's base64 data plus a content type (decode it on your side — examples below). For data steps (text extraction, AI extraction, etc.) it's that step's JSON.
Every successful response also includes billing headers:
X-Tokens-Used— tokens charged for the whole pipeline runX-Tokens-Remaining— your balance after this run
Call It From Anywhere
The same request in common languages and tools:
curl -X POST "https://docbutterfly.com/api/Webhook/invoice-pipeline-3f9a1c" \
-H "X-API-Key: $DOCBUTTERFLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Invoice #1042</h1>", "watermarkText": "PAID"}'$response = Invoke-RestMethod `
-Method Post `
-Uri "https://docbutterfly.com/api/Webhook/invoice-pipeline-3f9a1c" `
-Headers @{ "X-API-Key" = $env:DOCBUTTERFLY_API_KEY } `
-ContentType "application/json" `
-Body (@{ html = "<h1>Invoice #1042</h1>"; watermarkText = "PAID" } | ConvertTo-Json)
# Save the resulting PDF
[IO.File]::WriteAllBytes("invoice.pdf", [Convert]::FromBase64String($response.result.data))import os, base64, requests
resp = requests.post(
"https://docbutterfly.com/api/Webhook/invoice-pipeline-3f9a1c",
headers={"X-API-Key": os.environ["DOCBUTTERFLY_API_KEY"]},
json={"html": "<h1>Invoice #1042</h1>", "watermarkText": "PAID"},
)
resp.raise_for_status()
body = resp.json()
with open("invoice.pdf", "wb") as f:
f.write(base64.b64decode(body["result"]["data"]))
print(f"Tokens used: {resp.headers['X-Tokens-Used']}, remaining: {resp.headers['X-Tokens-Remaining']}")const resp = await fetch(
"https://docbutterfly.com/api/Webhook/invoice-pipeline-3f9a1c",
{
method: "POST",
headers: {
"X-API-Key": process.env.DOCBUTTERFLY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ html: "<h1>Invoice #1042</h1>", watermarkText: "PAID" }),
}
);
if (!resp.ok) throw new Error(`Webhook failed: ${resp.status}`);
const body = await resp.json();
// Node: save the PDF
await require("fs/promises").writeFile(
"invoice.pdf",
Buffer.from(body.result.data, "base64")
);using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key",
Environment.GetEnvironmentVariable("DOCBUTTERFLY_API_KEY"));
var resp = await http.PostAsJsonAsync(
"https://docbutterfly.com/api/Webhook/invoice-pipeline-3f9a1c",
new { html = "<h1>Invoice #1042</h1>", watermarkText = "PAID" });
resp.EnsureSuccessStatusCode();
var body = await resp.Content.ReadFromJsonAsync<JsonElement>();
var pdfBytes = Convert.FromBase64String(
body.GetProperty("result").GetProperty("data").GetString()!);
await File.WriteAllBytesAsync("invoice.pdf", pdfBytes);Platform Recipes
Step-by-step setup for popular automation platforms. They all reduce to the same thing: an HTTP action pointed at your webhook URL.
Power Automate
- Add an HTTP action (premium connector) to your flow.
- Configure it:
Method POSTURI your webhook URL Headers X-API-Key: your key •Content-Type:application/jsonBody JSON using dynamic content, e.g. { "html": ..., "customerEmail": ... } - To save a returned file to SharePoint/OneDrive, add a Create file action with file content:
Power Automate expression
base64ToBinary(body('HTTP')?['result']?['data'])
Tip: store the API key in an environment variable or Azure Key Vault reference rather than pasting it into the flow definition.
Azure Logic Apps
Identical to Power Automate: add an HTTP action with method POST, your webhook URI, the X-API-Key header, and a JSON body. Use base64ToBinary() on result.data for downstream file connectors. In Logic Apps Standard, keep the key in app settings and reference it with parameters().
Zapier
- Add a Webhooks by Zapier action → Custom Request.
- Method
POST, URL = your webhook URL, Data = your JSON, Headers:X-API-KeyandContent-Type: application/json. - Downstream steps can read
result data(base64) and metadata fields from the parsed response.
Make (Integromat)
Add an HTTP → Make a request module: method POST, your webhook URL, header X-API-Key, body type Raw / JSON. Enable Parse response to map result.data into later modules (e.g. a Tools → Compose + base64 decode, or straight into an email attachment module that accepts base64).
n8n
Add an HTTP Request node: method POST, your webhook URL, authentication Generic → Header Auth (name X-API-Key), and JSON body. Follow with a Move Binary Data / Convert to File node using the base64 in result.data.
GitHub Actions / CI pipelines
- name: Generate release notes PDF
run: |
curl -sf -X POST "$WEBHOOK_URL" \
-H "X-API-Key: ${{ secrets.DOCBUTTERFLY_API_KEY }}" \
-H "Content-Type: application/json" \
-d "{\"html\": \"<h1>Release ${{ github.ref_name }}</h1>\"}" \
| jq -r '.result.data' | base64 -d > release-notes.pdf
env:
WEBHOOK_URL: https://docbutterfly.com/api/Webhook/your-slug
Everything else
UiPath, Workato, Tray, Pipedream, Salesforce Apex, SAP, a bash cron job, an ESP32 — if it can send an HTTPS POST with a header and a JSON body, it works. There is no SDK to install and no OAuth dance: one URL, one header, one body.
Single Operations Without a Webhook
If you only need one operation, skip the Orchestrator and call the endpoint directly — same authentication, same response headers:
curl -X POST "https://docbutterfly.com/api/ConvertHtmlToPdf" \
-H "X-API-Key: $DOCBUTTERFLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Hello</h1>", "returnBase64": true}'
Browse all endpoints in the API Reference, or try them live in the API Testbed. Use a webhook instead when you chain two or more operations — it saves round-trips, bandwidth (no shuttling intermediate files), and caller-side complexity.
Errors & Troubleshooting
| Status | Meaning | What to do |
|---|---|---|
401 | Missing or invalid API key | Send the key in X-API-Key; check for whitespace/truncation. Regenerate from Portal → API Key if compromised. |
402 | Insufficient tokens | The response body includes required and available. Top up your balance. |
403 | Account deactivated | Contact support. |
404 | Webhook not found or unpublished | Check the slug; re-publish the workflow in the Orchestrator if you unpublished it. |
500 | A pipeline step failed | The body includes message identifying the failing step. Failed runs are not billed. Test the pipeline in the Orchestrator, then retry. |
Timeouts and cold starts
The first call after a quiet period can take 10–30 seconds extra while browser-based steps (HTML to PDF, web capture) warm up. Set your HTTP client timeout to at least 120 seconds for pipelines containing those steps, and add one retry on timeout in your caller.
Idempotency
Each call executes the pipeline and bills tokens once. If your platform retries automatically (Power Automate and Zapier both do on 5xx), be aware that a retry of a successful but slow call will run — and bill — the pipeline again. Prefer retrying only on network errors and 5xx responses.
Security Best Practices
- Treat webhook URLs as semi-secret. The URL alone can't be used without an API key, but don't post it publicly.
- Never embed API keys in client-side code (browser JavaScript, mobile apps). Call webhooks from a backend or automation platform.
- Use HTTPS only (the API does not serve plain HTTP).
- Rotate keys from Portal → API Key if a key may have leaked — the old key stops working immediately.
- Unpublish unused webhooks. Unpublishing returns 404 to all callers instantly and is reversible.
- Monitor usage in Portal → Usage — every call is logged with operation, tokens, caller IP, and duration.