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.

If it can make an HTTPS request, it can use DocButterfly. Power Automate, Logic Apps, Zapier, Make, n8n, UiPath, GitHub Actions, cURL, PowerShell, Python, a Raspberry Pi — anything.

How It Works

  1. Build — assemble a pipeline in the Orchestrator (e.g. HTML → PDF → watermark → email). Each step's output feeds the next.
  2. Publish — click Publish. You get a unique webhook URL like /api/Webhook/invoice-pipeline-3f9a1c.
  3. Call — POST to that URL with your API key. The JSON body you send becomes $input, available to every step in the pipeline.
  4. 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

https://docbutterfly.com

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

  1. Open Portal → Orchestrator and drag operation blocks onto the canvas. Connect them so each step consumes the previous step's output.
  2. Use the $input block 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.
  3. 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:

PartValue
Method / URLPOST /api/Webhook/{your-slug}
Auth headerX-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
HTTP
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
200 OK — application/json
{
  "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 run
  • X-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

  1. Add an HTTP action (premium connector) to your flow.
  2. Configure it:
    MethodPOST
    URIyour webhook URL
    HeadersX-API-Key : your key  •  Content-Type : application/json
    BodyJSON using dynamic content, e.g. { "html": ..., "customerEmail": ... }
  3. 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

  1. Add a Webhooks by Zapier action → Custom Request.
  2. Method POST, URL = your webhook URL, Data = your JSON, Headers: X-API-Key and Content-Type: application/json.
  3. 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

YAML
- 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
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

StatusMeaningWhat to do
401Missing or invalid API keySend the key in X-API-Key; check for whitespace/truncation. Regenerate from Portal → API Key if compromised.
402Insufficient tokensThe response body includes required and available. Top up your balance.
403Account deactivatedContact support.
404Webhook not found or unpublishedCheck the slug; re-publish the workflow in the Orchestrator if you unpublished it.
500A pipeline step failedThe 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.