We are in official beta.

Destinations

Where a workflow's results can go — Dataverse rows, SQL tables, Azure blobs, S3 objects, SFTP files, SharePoint libraries, Service Bus messages, HTTP endpoints via connections, and email

15 endpoints in this category. All require X-API-Key header.


Dataverse: Create Rows

POST /api/DataverseCreateRows 1 token

Creates rows in a Dataverse (Dynamics 365 / Power Platform) table via a registry connection of type 'dataverse' owned by the calling client. The connection holds the org URL and credential — neither ever appears in the workflow definition.

As a pipeline step, connectionId passes through in the body and is resolved by the endpoint under the pipeline's run-as client (#1216). Rows land in the customer's CRM, and a plain create cannot be undone by repeating it — replaying one form submission is already prevented on our side (#1617), but a caller driving this endpoint directly should not blindly retry unless it sets idempotencyKeyColumn (#2326). With that column declared the response also carries idempotency: {keyColumn, mode}, mode is 'upsert' only when the call arrives with a platform idempotency key to address the record by, and a row the key says was already filed comes back ok with alreadyExists: true. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'dataverse', owned by the calling client (manage/connections)
entitySet string required Dataverse Web API entity set name — plural, lowercase (e.g. 'contacts', 'cr123_orders')
rows array required Non-empty array of row objects; keys are Dataverse logical attribute names
fieldMap object optional Maps submission field names to destination columns: {"surname": "lastname"}. When set, ONLY mapped fields are sent — unmapped keys are dropped, and a field a row does not carry contributes no attribute at all (never a null, which would clear the column). Omit it and rows pass through exactly as before.
lookupBinds object optional Sets LOOKUPS from an id the row already carries: {"parentcustomerid_account.accountid": "accounts"} reads the related record's id at that path and sends "parentcustomerid_account@odata.bind": "/accounts(<guid>)". A row with no id there gets no bind at all (never a null, which would clear the lookup), and the response names those navigations in 'skippedLookups'. It never creates the related record
idempotencyKeyColumn string optional OPT-IN idempotency. The logical name of a string column on this table that carries a PUBLISHED ALTERNATE KEY (e.g. "dbf_idempotencykey", at least 72 characters wide). Set it and each row is written as an alternate-key upsert addressed by that column instead of a plain create, so repeating the write produces one row rather than two; row i of a multi-row call is keyed distinctly. Omit it and rows are created exactly as before. It is never assumed — addressing the wrong column would overwrite an unrelated record, which is worse than the duplicate it would prevent
continueOnError boolean optional Keep creating remaining rows after one fails (result reports per-row errors) (default: false)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "contacts", "rows": [{"firstname": "Ada", "lastname": "Lovelace"}]}
Response Example
JSON
{"success": true, "created": 1, "failed": 0, "results": [{"index": 0, "ok": true, "id": "guid"}]}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/DataverseCreateRows" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "contacts", "rows": [{"firstname": "Ada", "lastname": "Lovelace"}]}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""entitySet"": ""contacts"", ""rows"": [{""firstname"": ""Ada"", ""lastname"": ""Lovelace""}]}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/DataverseCreateRows", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/DataverseCreateRows"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "contacts", "rows": [{"firstname": "Ada", "lastname": "Lovelace"}]}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/DataverseCreateRows
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "entitySet": "contacts",
│      "rows": [
│        {
│          "firstname": "Ada",
│          "lastname": "Lovelace"
│        }
│      ]
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/DataverseCreateRows"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Dataverse: Write File Column

POST /api/DataverseWriteFile 1 token

Writes a document into a Dataverse File (or Image) column, through a registry connection of type 'dataverse' owned by the calling client. This is the delivery end of the document drop point established by the child-table pattern: DocButterfly puts the finished document on the customer's record and their flow picks it up. Files above 4 MB are uploaded through Dataverse's chunked session automatically — the caller sends one request either way.

Up to 33554432 bytes (32 MB) decoded per call — larger is refused with 413 and the size, and nothing is written. There is deliberately no contentType parameter: Dataverse accepts only application/octet-stream on a file column and remembers no media type at all, so a contentType would be a value we accepted and dropped. Put the extension in fileName instead — DataverseReadFile derives the type from it. The write is addressed to one column on one record, so a replay overwrites rather than duplicating; it still lands in the customer's CRM. The column's own Maximum file size (MaxSizeInKB, set on the column in Dataverse) is the real limit: a file within this endpoint's 32 MB but over the column's limit is refused by Dataverse, and the error gives the file's size. Raise that limit on the column before sending a large document set. A File column you have just created is not on any form: the record page shows no file until someone adds the column to a form and publishes it, even though the write landed. Confirm a write with DataverseReadFile, not by opening the record. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'dataverse', owned by the calling client (manage/connections)
entitySet string required Dataverse Web API entity set name — plural, lowercase (e.g. 'dbf_documentdrops', 'contacts')
recordId string required The record's GUID, plain 8-4-4-4-12 form with no braces. The record must already exist — this writes a column, it does not create rows (see DataverseCreateRows)
column string required The File column's attribute logical name (e.g. 'dbf_file')
fileName string required The file's name, e.g. 'proposal-bundle.zip'. REQUIRED, and it carries the extension: Dataverse stores no media type, so the name is the only thing that tells a later read what the file is. Printable ASCII, no path separators, no '..'
contentBase64 string required The file's bytes, base64-encoded. Up to 33554432 bytes (32 MB) decoded
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file", "fileName": "proposal-bundle.zip", "contentBase64": "UEsDBBQ…"}
Response Example
JSON
{"success": true, "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file", "fileName": "proposal-bundle.zip", "sizeBytes": 236544, "transferMode": "single", "chunks": 1, "timing": {"total": 940}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/DataverseWriteFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file", "fileName": "proposal-bundle.zip", "contentBase64": "UEsDBBQ…"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""entitySet"": ""dbf_documentdrops"", ""recordId"": ""be83416a-45a9-f111-aaac-70a8a5b10a05"", ""column"": ""dbf_file"", ""fileName"": ""proposal-bundle.zip"", ""contentBase64"": ""UEsDBBQ…""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/DataverseWriteFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/DataverseWriteFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file", "fileName": "proposal-bundle.zip", "contentBase64": "UEsDBBQ…"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/DataverseWriteFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "entitySet": "dbf_documentdrops",
│      "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05",
│      "column": "dbf_file",
│      "fileName": "proposal-bundle.zip",
│      "contentBase64": "UEsDBBQ\u2026"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/DataverseWriteFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Dataverse: Clear File Column

POST /api/DataverseDeleteFile 1 token

Clears the file out of a Dataverse File (or Image) column, through a registry connection of type 'dataverse' owned by the calling client. The third operation of the drop-point pattern: a flow drains the document and then empties the column so the next one is unambiguous. It clears a COLUMN — the record itself is untouched.

This deletes the FILE, not the row. The record, and every other column on it, is untouched — deleting the record is a different operation and this endpoint cannot do it. Clearing an already-empty column succeeds rather than failing: Dataverse's file delete is idempotent (measured, not assumed), which is what lets a drain-and-delete flow re-clear safely. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'dataverse', owned by the calling client (manage/connections)
entitySet string required Dataverse Web API entity set name — plural, lowercase (e.g. 'dbf_documentdrops')
recordId string required The record's GUID, plain 8-4-4-4-12 form with no braces
column string required The File column's attribute logical name (e.g. 'dbf_file')
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file"}
Response Example
JSON
{"success": true, "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file", "deleted": true, "timing": {"total": 260}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/DataverseDeleteFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""entitySet"": ""dbf_documentdrops"", ""recordId"": ""be83416a-45a9-f111-aaac-70a8a5b10a05"", ""column"": ""dbf_file""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/DataverseDeleteFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/DataverseDeleteFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "entitySet": "dbf_documentdrops", "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05", "column": "dbf_file"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/DataverseDeleteFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "entitySet": "dbf_documentdrops",
│      "recordId": "be83416a-45a9-f111-aaac-70a8a5b10a05",
│      "column": "dbf_file"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/DataverseDeleteFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Dataverse: Replace Draft Email Attachment

POST /api/DataverseWriteEmailAttachment 1 token

Replaces the placeholder attachment on a DRAFT email in Dataverse (Dynamics 365) with your document, through a registry connection of type 'dataverse' owned by the calling client. Built for the proposal path: the CRM creates the draft email and a placeholder attachment at the right sales stage, a workflow fills the proposal, and this puts it in the placeholder's place, so the email is ready to go with the real document on it.

DRAFT EMAILS ONLY. The attachment must belong to an email (one on an email template is refused with 400 NOT_AN_EMAIL_ATTACHMENT) whose status is Draft. A sent, queued, failed or canceled email's attachment is refused with 409 EMAIL_NOT_DRAFT and nothing is written, because it is the record of what went out. It replaces the attachment in place and never creates one: a missing attachment is 404 DATAVERSE_RECORD_NOT_FOUND, and one that changed between the check and the write is 409 ATTACHMENT_CHANGED. The placeholder's own bytes are never downloaded. Up to 33554432 bytes (32 MB) decoded per call; larger is refused with 413 and nothing is written, and the org's own attachment size limit and blocked file extensions still apply (400 DATAVERSE_ATTACHMENT_REJECTED). Sending the email, or marking it complete, is the CRM's step afterwards, not this one. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'dataverse', owned by the calling client (manage/connections)
attachmentId string required The email attachment's GUID (its activitymimeattachmentid), plain 8-4-4-4-12 form with no braces. It must belong to an email that is still a Draft
fileName string required The name the recipient sees on the attachment, with its extension, e.g. 'proposal-Q-01042.pdf'. Printable ASCII, no path separators, no '..'
contentBase64 string required The document's bytes, base64-encoded. Up to 33554432 bytes (32 MB) decoded
mimeType string optional The media type stored on the attachment, e.g. 'application/pdf'. Leave it out and it is worked out from the bytes, then from the file name's extension; mimeTypeSource in the response says which
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "attachmentId": "5d1c2b3a-9f8e-4d7c-a6b5-0123456789ab", "fileName": "proposal-Q-01042.pdf", "contentBase64": "JVBERi0xLjcK…"}
Response Example
JSON
{"success": true, "attachmentId": "5d1c2b3a-9f8e-4d7c-a6b5-0123456789ab", "emailId": "8a7b6c5d-4e3f-4a1b-9c8d-7e6f5a4b3c2d", "fileName": "proposal-Q-01042.pdf", "mimeType": "application/pdf", "mimeTypeSource": "signature", "sizeBytes": 48213, "replacedFileName": "proposal-placeholder.txt", "timing": {"total": 610}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/DataverseWriteEmailAttachment" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "attachmentId": "5d1c2b3a-9f8e-4d7c-a6b5-0123456789ab", "fileName": "proposal-Q-01042.pdf", "contentBase64": "JVBERi0xLjcK…"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""attachmentId"": ""5d1c2b3a-9f8e-4d7c-a6b5-0123456789ab"", ""fileName"": ""proposal-Q-01042.pdf"", ""contentBase64"": ""JVBERi0xLjcK…""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/DataverseWriteEmailAttachment", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/DataverseWriteEmailAttachment"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "attachmentId": "5d1c2b3a-9f8e-4d7c-a6b5-0123456789ab", "fileName": "proposal-Q-01042.pdf", "contentBase64": "JVBERi0xLjcK…"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/DataverseWriteEmailAttachment
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "attachmentId": "5d1c2b3a-9f8e-4d7c-a6b5-0123456789ab",
│      "fileName": "proposal-Q-01042.pdf",
│      "contentBase64": "JVBERi0xLjcK\u2026"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/DataverseWriteEmailAttachment"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

SQL: Insert Rows

POST /api/SqlInsertRows 1 token

Inserts rows into a SQL table via a registry connection of type 'sqlserver', 'postgresql', or 'mysql' owned by the calling client. The dialect comes from the connection — the request is identical for all three. The connection holds the host, database, and credential; none of them ever appear in the workflow definition.

As a pipeline step, connectionId passes through in the body and is resolved by the endpoint under the pipeline's run-as client. The target database must be reachable from Azure. Inserts are a side effect — a retry duplicates rows, so callers should not blindly retry. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'sqlserver', 'postgresql', or 'mysql', owned by the calling client (manage/connections)
table string required Target table name, optionally schema-qualified (e.g. 'invoices', 'dbo.Invoices', 'public.orders')
rows array required Non-empty array of row objects (max 100 per call); keys are column names
fieldMap object optional Maps submission field names to destination columns: {"Full Name": "full_name"}. When set, ONLY mapped fields are sent — unmapped keys are dropped, and a field a row does not carry contributes no column at all (never a null). Omit it and rows pass through exactly as before.
continueOnError boolean optional Keep inserting remaining rows after one fails (result reports per-row errors) (default: false)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "table": "dbo.Invoices", "rows": [{"customer": "Acme Corp", "total": 582.62}]}
Response Example
JSON
{"success": true, "created": 1, "failed": 0, "results": [{"index": 0, "ok": true}]}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/SqlInsertRows" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "table": "dbo.Invoices", "rows": [{"customer": "Acme Corp", "total": 582.62}]}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""table"": ""dbo.Invoices"", ""rows"": [{""customer"": ""Acme Corp"", ""total"": 582.62}]}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/SqlInsertRows", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/SqlInsertRows"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "table": "dbo.Invoices", "rows": [{"customer": "Acme Corp", "total": 582.62}]}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/SqlInsertRows
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "table": "dbo.Invoices",
│      "rows": [
│        {
│          "customer": "Acme Corp",
│          "total": 582.62
│        }
│      ]
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/SqlInsertRows"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Blob: Write File

POST /api/BlobWriteFile 1 token

Writes a file into an Azure Blob Storage container via a registry connection of type 'blob' owned by the calling client. The connection holds the account URL and the SAS token or storage connection string — neither ever appears in the workflow definition.

The returned URL never carries the SAS — the query string is stripped before it leaves. The connection's accountUrl is the authority: a credential naming a different account is refused, so the address an admin can review in the registry is the address we write to. Writing is a side effect — a retry re-writes the blob. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'blob', owned by the calling client (manage/connections)
path string required Blob name, optionally with folder segments (e.g. 'invoices/2026/inv-1.pdf'). Max 1024 characters; no leading slash, no '..', no control characters
contentBase64 string required The file's bytes, base64-encoded (max 32 MB per call)
container string optional Overrides the connection's default container. Azure naming rules: 3-63 lowercase alphanumerics and single dashes
contentType string optional MIME type stored on the blob (default: application/octet-stream)
overwrite boolean optional Replace an existing blob at that path instead of failing with 409 (default: false)
createContainer boolean optional Create the container if it does not exist (default: false)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "invoices/2026/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}
Response Example
JSON
{"success": true, "container": "invoices", "path": "invoices/2026/inv-1.pdf", "url": "https://acmedocs.blob.core.windows.net/invoices/2026/inv-1.pdf", "etag": "\"0x8DC…\"", "sizeBytes": 20481, "contentType": "application/pdf", "timing": {"total": 142}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/BlobWriteFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "invoices/2026/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""path"": ""invoices/2026/inv-1.pdf"", ""contentBase64"": ""JVBERi0xLjcK..."", ""contentType"": ""application/pdf""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/BlobWriteFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/BlobWriteFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "invoices/2026/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/BlobWriteFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "path": "invoices/2026/inv-1.pdf",
│      "contentBase64": "JVBERi0xLjcK...",
│      "contentType": "application/pdf"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/BlobWriteFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

SFTP: Upload File

POST /api/SftpUploadFile 1 token

Uploads a file to an SFTP server via a registry connection of type 'sftp' owned by the calling client. The connection holds the host and the password or private key — neither ever appears in the workflow definition.

Host key: when the connection sets config.hostKeyFingerprint it is ENFORCED — a mismatch aborts BEFORE authentication, so a man in the middle never sees the credential. When it is not set the connection still succeeds and the observed fingerprint comes back, so it can be pinned from a real observation rather than a guess. Uploading is a side effect — a retry re-uploads. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'sftp', owned by the calling client (manage/connections)
path string required Remote path relative to the connection's rootPath (e.g. 'inbox/inv-1.pdf'). Max 1024 characters; absolute paths, '..', backslashes, empty segments and control characters are refused
contentBase64 string required The file's bytes, base64-encoded (max 32 MB per call)
overwrite boolean optional Replace an existing file at that path instead of failing with 409 (default: false)
createDirectories boolean optional Create the parent directories if they do not exist (default: false)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "inbox/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "createDirectories": true}
Response Example
JSON
{"success": true, "path": "/upload/inbox/inv-1.pdf", "sizeBytes": 20481, "host": "sftp.acme.example", "port": 22, "hostKeyFingerprint": "SHA256:9x…", "hostKeyPinned": true, "timing": {"total": 704}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/SftpUploadFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "inbox/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "createDirectories": true}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""path"": ""inbox/inv-1.pdf"", ""contentBase64"": ""JVBERi0xLjcK..."", ""createDirectories"": true}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/SftpUploadFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/SftpUploadFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "inbox/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "createDirectories": true}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/SftpUploadFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "path": "inbox/inv-1.pdf",
│      "contentBase64": "JVBERi0xLjcK...",
│      "createDirectories": true
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/SftpUploadFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

SFTP: Move File

POST /api/SftpMoveFile 1 token

Moves (renames) one file on an SFTP server via a registry connection of type 'sftp' owned by the calling client — for example filing a dropped job zip into its own job folder once a workflow has picked it up. No file bytes pass through DocButterfly.

Both paths are held to the same confinement rule as SftpUploadFile and SftpDownloadFile, so a move can climb out of the connection's rootPath no more than an upload can. fromPath and toPath come back as you sent them, so the next step can use them directly; remoteFromPath and remoteToPath are the full server paths. The parent folders of toPath are created. An existing file at toPath is a 409 unless overwrite is true, and then it is deleted before the rename, which is two steps and not atomic — if the rename fails, the file is still at fromPath. Moving is a side effect: inside a workflow a retried step is recognized and answered with the first result instead of being sent again. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'sftp', owned by the calling client (manage/connections)
fromPath string required The file to move, relative to the connection's rootPath (e.g. 'inbound/job0001.zip'). Absolute paths, '..', backslashes, empty segments and control characters are refused
toPath string required Where the file should end up, relative to the connection's rootPath (e.g. 'job0001/input/job0001.zip'). Same rules as fromPath. Missing parent folders are created
overwrite boolean optional Replace an existing FILE at toPath instead of failing with 409. A folder at toPath is never replaced (default: false)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "fromPath": "inbound/job0001.zip", "toPath": "job0001/input/job0001.zip"}
Response Example
JSON
{"success": true, "fromPath": "inbound/job0001.zip", "toPath": "job0001/input/job0001.zip", "remoteFromPath": "/upload/inbound/job0001.zip", "remoteToPath": "/upload/job0001/input/job0001.zip", "overwritten": false, "host": "sftp.acme.example", "port": 22, "hostKeyFingerprint": "SHA256:9x…", "hostKeyPinned": true, "timing": {"total": 390}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/SftpMoveFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "fromPath": "inbound/job0001.zip", "toPath": "job0001/input/job0001.zip"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""fromPath"": ""inbound/job0001.zip"", ""toPath"": ""job0001/input/job0001.zip""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/SftpMoveFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/SftpMoveFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "fromPath": "inbound/job0001.zip", "toPath": "job0001/input/job0001.zip"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/SftpMoveFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "fromPath": "inbound/job0001.zip",
│      "toPath": "job0001/input/job0001.zip"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/SftpMoveFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Storage: Upload File

POST /api/StorageUploadFile 1 token

Writes one file into the DocButterfly folder in a person's own Dropbox, Google Drive, OneDrive or Box, through a registry connection of type 'dropbox', 'googledrive', 'msgraphdrive' or 'box' owned by the calling client. One generic step serves all four providers: the connection decides which one, so the same workflow delivers to whichever the customer connected.

NOTHING IS EVER OVERWRITTEN. Every provider renames on a name clash: Dropbox and OneDrive do it themselves; on Google Drive, which would otherwise accept two files with the same name, and on Box, which refuses a taken name, the ladder ' (1)' to ' (99)' is applied. A file somebody already had is never replaced. SINGLE-SHOT, CAPPED AT 4 MB per call, which is Graph's own ceiling for a one-request upload and the lowest of the four; the chunked upload session is a later wave. The grant reaches one folder and nothing else: the app folder on Dropbox, Files.ReadWrite.AppFolder on OneDrive, drive.file on Google Drive. On Box the grant is the whole account and the one-folder rule is ours: the file is written into the DocButterfly folder and nowhere else. Uploading is a side effect, so a retry leaves a second, renamed copy. Uses a saved storage connection, so it is not available in the anonymous playground or the interactive builder Run.
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'dropbox', 'googledrive', 'msgraphdrive' or 'box', owned by the calling client (manage/connections). Any other type is refused by name with STORAGE_BAD_CONNECTION_TYPE before a token is spent
path string required The FILE NAME to write, not a path. Everything lands in the DocButterfly folder itself; separators, control characters and leading or trailing dots are removed rather than refused, and the name is shortened to 200 characters
contentBase64 string required The file's bytes, base64-encoded (max 4 MB per call)
contentType string optional The media type to store the file as (default: application/octet-stream)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "invoice-9.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}
Response Example
JSON
{"success": true, "provider": "dropbox", "connectionId": "conn_0123456789abcdef0123456789abcdef", "fileId": "id:aBcD1234", "name": "invoice-9.pdf", "sizeBytes": 20481}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/StorageUploadFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "invoice-9.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""path"": ""invoice-9.pdf"", ""contentBase64"": ""JVBERi0xLjcK..."", ""contentType"": ""application/pdf""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/StorageUploadFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/StorageUploadFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "path": "invoice-9.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/StorageUploadFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "path": "invoice-9.pdf",
│      "contentBase64": "JVBERi0xLjcK...",
│      "contentType": "application/pdf"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/StorageUploadFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Service Bus: Send Messages

POST /api/ServiceBusSendMessages 1 token

Sends a batch of messages to an Azure Service Bus queue or topic via a registry connection of type 'servicebus' owned by the calling client. The connection holds the namespace and the connection string or SAS token — neither ever appears in the workflow definition.

The whole batch goes in one Service Bus REST send, so the call is all-or-nothing: either every message is queued or none is. The batch is capped at 1 MB here and your namespace's own tier may cap it lower (256 KB on standard). Send only — this endpoint does not receive, and does not do sessions, transactions or dead-letter handling. Sending is a side effect — a retry puts a second copy on the queue. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'servicebus', owned by the calling client (manage/connections)
messages array required 1-100 messages. Each is either a plain string, or an object { body, contentType?, timeToLiveSeconds?, properties?, messageId?, correlationId?, sessionId?, label?, partitionKey?, replyTo?, to? }. An object body is sent as JSON text
queueOrTopic string optional Overrides the connection's default entity. May be hierarchical (e.g. 'orders/eu')
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "queueOrTopic": "orders", "messages": [{"body": {"orderId": 42}, "label": "order-created", "contentType": "application/json", "properties": {"source": "docbutterfly"}}]}
Response Example
JSON
{"success": true, "sent": 1, "namespace": "acme.servicebus.windows.net", "entity": "orders", "sizeBytes": 118, "timing": {"total": 92}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/ServiceBusSendMessages" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "queueOrTopic": "orders", "messages": [{"body": {"orderId": 42}, "label": "order-created", "contentType": "application/json", "properties": {"source": "docbutterfly"}}]}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""queueOrTopic"": ""orders"", ""messages"": [{""body"": {""orderId"": 42}, ""label"": ""order-created"", ""contentType"": ""application/json"", ""properties"": {""source"": ""docbutterfly""}}]}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/ServiceBusSendMessages", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/ServiceBusSendMessages"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "queueOrTopic": "orders", "messages": [{"body": {"orderId": 42}, "label": "order-created", "contentType": "application/json", "properties": {"source": "docbutterfly"}}]}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/ServiceBusSendMessages
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "queueOrTopic": "orders",
│      "messages": [
│        {
│          "body": {
│            "orderId": 42
│          },
│          "label": "order-created",
│          "contentType": "application/json",
│          "properties": {
│            "source": "docbutterfly"
│          }
│        }
│      ]
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/ServiceBusSendMessages"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

S3: Put Object

POST /api/S3PutObject 1 token

Writes an object into an Amazon S3 bucket — or any S3-compatible store (MinIO, Cloudflare R2, Wasabi, Backblaze B2, Google Cloud Storage's interoperability API) — via a registry connection of type 's3' owned by the calling client. The connection holds the bucket, region, optional endpoint, and the access key pair; none of them ever appear in the workflow definition.

OVERWRITE DEFAULTS TRUE HERE, A DELIBERATE DIVERGENCE FROM BlobWriteFile, which defaults false. Azure Blob has always had an atomic 'only if absent', so it can promise not to destroy a colliding document; S3 only gained conditional writes in late 2024 and the S3-compatible providers this same connector serves are inconsistent about supporting them. Defaulting to false would promise a guarantee we cannot deliver on half the targets, and a provider that ignores the header overwrites silently — the worst of both. So the default is S3's own PutObject semantics (replace), which every implementation agrees on, and overwrite:false is an OPT-IN that sends If-None-Match: * — a clean 409 on real S3, R2 and current MinIO, and the provider's own error elsewhere. Writing is a side effect: a retry re-writes the object. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 's3', owned by the calling client (manage/connections)
key string required Object key, optionally with folder-style segments (e.g. 'invoices/2026/inv-1.pdf'). Max 1024 characters; no leading slash, no '..', no control characters
contentBase64 string required The file's bytes, base64-encoded (max 32 MB per call)
bucket string optional Overrides the connection's default bucket. S3 naming rules: 3-63 lowercase alphanumerics, dots and dashes
contentType string optional MIME type stored on the object (default: application/octet-stream)
overwrite boolean optional Replace an existing object at that key. See the notes — this defaults TRUE, unlike BlobWriteFile (default: true)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "key": "invoices/2026/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}
Response Example
JSON
{"success": true, "bucket": "acme-docs", "key": "invoices/2026/inv-1.pdf", "url": "https://acme-docs.s3.us-east-1.amazonaws.com/invoices/2026/inv-1.pdf", "etag": "\"9b2c…\"", "sizeBytes": 20481, "contentType": "application/pdf", "timing": {"total": 208}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/S3PutObject" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "key": "invoices/2026/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""key"": ""invoices/2026/inv-1.pdf"", ""contentBase64"": ""JVBERi0xLjcK..."", ""contentType"": ""application/pdf""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/S3PutObject", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/S3PutObject"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "key": "invoices/2026/inv-1.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/S3PutObject
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "key": "invoices/2026/inv-1.pdf",
│      "contentBase64": "JVBERi0xLjcK...",
│      "contentType": "application/pdf"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/S3PutObject"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

SharePoint: Upload File

POST /api/SpUploadFile 1 token

Files a document into a SharePoint or OneDrive document library via a registry connection of type 'sharepoint' owned by the calling client. Authentication is app-only Microsoft Graph with Sites.Selected, so the app reaches only the sites your administrator granted it — one at a time, never the tenant. The connection holds the tenant, the app registration and its secret, and may carry a default site, library and folder that a call overrides.

Missing folders on folderPath are created one segment at a time, and the ones that were created come back in foldersCreated — Graph has no mkdir -p, and two workflows racing for the same new folder re-read it rather than making a second one. A file that had to be renamed reports renamedFrom, because the path you asked for is not the path the document is at. Setting fields is best-effort AFTER the upload: if the columns cannot be set the answer is still 200, with partial:true and metadata.applied:false carrying the reason, because the file IS in the library at that point and a 502 would invite a retry that uploads it twice. Two refusals that look alike and are not: HTTP 401 means the app registration has no admin consent yet, HTTP 403 means it has consent but THIS site was never granted to it. Uploading is a side effect and Graph has no idempotency header — a retry under 'rename' can leave a second copy, so use 'replace' or 'fail' when a replay must converge. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'sharepoint', owned by the calling client (manage/connections)
fileName string required The file's name inside the library (e.g. 'invoice-1042.pdf'). SharePoint refuses < > : " | ? * \ / and control characters, and names that end in a period
contentBase64 string required The file's bytes, base64-encoded (max 100 MB per call). Anything over 4 MB is uploaded through a Graph upload session automatically
siteUrl string optional The site's browser address (https://contoso.sharepoint.com/sites/Finance). Overrides the connection's site
libraryName string optional The library's display name (e.g. 'Documents'), matched within the site. Use it instead of driveId
folderPath string optional Folder inside the library, '/'-separated (e.g. 'Invoices/2026'). Omit to write to the library root; overrides the connection's folder
conflictBehavior string optional What to do when a file of that name is already there: 'rename' keeps both, 'replace' overwrites the existing one, 'fail' refuses with 409 and changes nothing (default: rename)
siteId string optional Graph site id, if you already have one. Overrides the connection's site
driveId string optional Graph drive id of the target library. Overrides the connection's library
createFolders boolean optional Create the folders on folderPath if they are missing. Set false to require the folder to exist (404 naming it) (default: true)
contentType string optional MIME type sent with the bytes (default: application/octet-stream)
fields object optional Library column values to set on the new item in the same call, validated exactly as SpSetMetadata validates them: {"Vendor": "Acme", "InvoiceTotal": 582.62}
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "siteUrl": "https://contoso.sharepoint.com/sites/Finance", "libraryName": "Documents", "folderPath": "Invoices/2026", "fileName": "invoice-1042.pdf", "contentBase64": "JVBERi0xLjcK...", "conflictBehavior": "rename"}
Response Example
JSON
{"success": true, "siteId": "contoso.sharepoint.com,4a1…,9c2…", "driveId": "b!x9…", "itemId": "01ABC…", "name": "invoice-1042.pdf", "path": "Invoices/2026/invoice-1042.pdf", "webUrl": "https://contoso.sharepoint.com/sites/Finance/Shared%20Documents/Invoices/2026/invoice-1042.pdf", "sizeBytes": 20481, "uploadMode": "simple", "conflictBehavior": "rename", "foldersCreated": ["Invoices/2026"], "timing": {"total": 812}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/SpUploadFile" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "siteUrl": "https://contoso.sharepoint.com/sites/Finance", "libraryName": "Documents", "folderPath": "Invoices/2026", "fileName": "invoice-1042.pdf", "contentBase64": "JVBERi0xLjcK...", "conflictBehavior": "rename"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""siteUrl"": ""https://contoso.sharepoint.com/sites/Finance"", ""libraryName"": ""Documents"", ""folderPath"": ""Invoices/2026"", ""fileName"": ""invoice-1042.pdf"", ""contentBase64"": ""JVBERi0xLjcK..."", ""conflictBehavior"": ""rename""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/SpUploadFile", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/SpUploadFile"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "siteUrl": "https://contoso.sharepoint.com/sites/Finance", "libraryName": "Documents", "folderPath": "Invoices/2026", "fileName": "invoice-1042.pdf", "contentBase64": "JVBERi0xLjcK...", "conflictBehavior": "rename"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/SpUploadFile
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "siteUrl": "https://contoso.sharepoint.com/sites/Finance",
│      "libraryName": "Documents",
│      "folderPath": "Invoices/2026",
│      "fileName": "invoice-1042.pdf",
│      "contentBase64": "JVBERi0xLjcK...",
│      "conflictBehavior": "rename"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/SpUploadFile"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

SharePoint: Set Metadata

POST /api/SpSetMetadata 1 token

Writes library column values onto one document in a SharePoint or OneDrive library, via a registry connection of type 'sharepoint'. This is the second half of 'extract it, then tag it': the values Document AI reads off an invoice become the columns the library's own views, filters and retention rules run on.

VALUES ARE CHECKED AGAINST THE LIBRARY'S OWN COLUMN DEFINITIONS FIRST, and that is the point of this endpoint over a raw PATCH: Graph answers a mistyped column with 'HTTP 400: the request is malformed' and names nothing, so a 400 here names the column, what it wanted and what it got. Text that will not fit, a choice that is not on the list, a date that cannot be read, a read-only or SharePoint-maintained column: each is refused by name, and nothing is written when any value is wrong. Coercion is limited to representations of the SAME value — "42" into a number column, "yes" into a yes/no column, a parseable date into ISO 8601 — never to meaning, so an unknown choice is refused rather than snapped to the nearest one. PEOPLE AND LOOKUPS ARE ADDRESSED BY ID, which is Graph's rule and not ours: pass the target's numeric id (or {"lookupId": 12}) and it is written as <Column>LookupId; a display name or an email in the plain column is accepted by neither Graph nor SharePoint. Managed-metadata (taxonomy) columns are refused with that sentence rather than half-written. If the column definitions cannot be READ the values are sent as given and the response says validated:false — refusing to write because a schema read failed would turn a degraded read into an outage. Writing is a side effect. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'sharepoint', owned by the calling client (manage/connections)
fields object required The columns to set, by INTERNAL name: {"Vendor": "Acme", "InvoiceTotal": 582.62, "Status": "Open"}. An explicit null clears a column
itemId string optional Graph drive item id — what SpUploadFile and SpGetFile return. Use this or path
path string optional The document's location inside the library (e.g. 'Invoices/2026/invoice-1042.pdf'). Use this or itemId
siteUrl string optional The site's browser address. Overrides the connection's site
siteId string optional Graph site id. Overrides the connection's site
driveId string optional Graph drive id of the library. Overrides the connection's library
libraryName string optional The library's display name (e.g. 'Documents'), matched within the site
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "siteUrl": "https://contoso.sharepoint.com/sites/Finance", "libraryName": "Documents", "path": "Invoices/2026/invoice-1042.pdf", "fields": {"Vendor": "Acme", "InvoiceTotal": 582.62, "Status": "Open"}}
Response Example
JSON
{"success": true, "itemId": "01ABC…", "name": "invoice-1042.pdf", "validated": true, "fields": {"Vendor": "Acme", "InvoiceTotal": 582.62, "Status": "Open"}, "timing": {"total": 512}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/SpSetMetadata" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "siteUrl": "https://contoso.sharepoint.com/sites/Finance", "libraryName": "Documents", "path": "Invoices/2026/invoice-1042.pdf", "fields": {"Vendor": "Acme", "InvoiceTotal": 582.62, "Status": "Open"}}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""siteUrl"": ""https://contoso.sharepoint.com/sites/Finance"", ""libraryName"": ""Documents"", ""path"": ""Invoices/2026/invoice-1042.pdf"", ""fields"": {""Vendor"": ""Acme"", ""InvoiceTotal"": 582.62, ""Status"": ""Open""}}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/SpSetMetadata", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/SpSetMetadata"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "siteUrl": "https://contoso.sharepoint.com/sites/Finance", "libraryName": "Documents", "path": "Invoices/2026/invoice-1042.pdf", "fields": {"Vendor": "Acme", "InvoiceTotal": 582.62, "Status": "Open"}}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/SpSetMetadata
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "siteUrl": "https://contoso.sharepoint.com/sites/Finance",
│      "libraryName": "Documents",
│      "path": "Invoices/2026/invoice-1042.pdf",
│      "fields": {
│        "Vendor": "Acme",
│        "InvoiceTotal": 582.62,
│        "Status": "Open"
│      }
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/SpSetMetadata"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Azure DevOps: Upload Attachment

POST /api/AdoUploadAttachment 1 token

Uploads one file to Azure DevOps as a work item attachment, through a registry connection of type 'rest' pointing at https://dev.azure.com/<organization> and owned by the calling client. It answers with the attachment's url, which is what a work item create or update then relates as an AttachedFile. There is deliberately no separate create-work-item endpoint: a work item is created by RestRequest against the same connection, and the fields, the parent link and the attachment relations all ride in ONE JSON Patch document on that call.

Up to 33554432 bytes (32 MB) decoded per call — larger is refused with 413 and the size, and nothing is uploaded. That is our limit, not one Azure DevOps sets: the file travels base64-encoded inside the request body, so it is bounded by the body this route accepts rather than by anything at the far end. attachmentUrl comes back exactly as Azure DevOps returned it, including the fileName it appends, and that is the value to put in a /relations/- AttachedFile operation. An upload with no relation is kept by Azure DevOps as an unreferenced attachment, so this is a side-effect write: a blind retry would leave a second copy, and a form-engine delivery is protected on our side because Azure DevOps honors no idempotency header. Not available in the anonymous playground or interactive builder Run (connection steps execute server-side via webhooks/form submissions).
Parameters
NameTypeRequiredDescription
connectionId string required Registry connection id (conn_…) of type 'rest' whose baseUrl is your Azure DevOps organization, owned by the calling client (manage/connections)
project string required The Azure DevOps project the attachment belongs to, by name or id. Spaces and hyphens are fine; '/', '\', '?' and '#' are refused because they would retarget the call
fileName string required The name the file appears under on the work item, e.g. 'inspection-report.pdf'. Azure DevOps stores no media type, so the extension here is what tells a reader what the file is. No path separators and no '..'
contentBase64 string required The file's bytes, base64-encoded. Up to 33554432 bytes (32 MB) decoded
ext string optional Replaces fileName's extension. It exists for one case: a compose step that had to fall back to HTML reports the format it actually produced, and attaching HTML bytes under a .pdf name hands the reader a file their viewer refuses to open
apiVersion string optional Azure DevOps api-version for this call. It is mandatory on every Azure DevOps request and rides as a query parameter (default: 7.1)
Request Example
JSON
{"connectionId": "conn_0123456789abcdef0123456789abcdef", "project": "Fabrikam Fiber", "fileName": "inspection-report.pdf", "contentBase64": "JVBERi0xLjcK..."}
Response Example
JSON
{"success": true, "attachmentId": "098a279a-60b9-4b73-8e82-6db0f5669d4e", "attachmentUrl": "https://dev.azure.com/fabrikam/_apis/wit/attachments/098a279a-60b9-4b73-8e82-6db0f5669d4e?fileName=inspection-report.pdf", "fileName": "inspection-report.pdf", "project": "Fabrikam Fiber", "sizeBytes": 20481, "timing": {"total": 640}}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/AdoUploadAttachment" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"connectionId": "conn_0123456789abcdef0123456789abcdef", "project": "Fabrikam Fiber", "fileName": "inspection-report.pdf", "contentBase64": "JVBERi0xLjcK..."}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""connectionId"": ""conn_0123456789abcdef0123456789abcdef"", ""project"": ""Fabrikam Fiber"", ""fileName"": ""inspection-report.pdf"", ""contentBase64"": ""JVBERi0xLjcK...""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/AdoUploadAttachment", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/AdoUploadAttachment"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"connectionId": "conn_0123456789abcdef0123456789abcdef", "project": "Fabrikam Fiber", "fileName": "inspection-report.pdf", "contentBase64": "JVBERi0xLjcK..."}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/AdoUploadAttachment
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "connectionId": "conn_0123456789abcdef0123456789abcdef",
│      "project": "Fabrikam Fiber",
│      "fileName": "inspection-report.pdf",
│      "contentBase64": "JVBERi0xLjcK..."
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/AdoUploadAttachment"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed

Send with FlyaDoc

POST /api/SendWithFlyaDoc 1 token

Sends one file to a FlyaDoc address from a workflow. The file is locked to the recipient's own published keys before it is stored, the same way the FlyaDoc page locks it in a browser, and it arrives, notifies the recipient and is received exactly like a file sent by hand, with the same receipt once they open it. Pair it with a folder watcher to send every new file in an SFTP or cloud folder to someone's FlyaDoc address.

TWO CHARGES, KEPT APART. This step is billed like any other step. The FlyaDoc itself is charged to your account at the same price a file sent by hand costs: it is set aside before anything is locked or uploaded, so an account that cannot pay is refused with 402 and nothing is sent, and it is returned in full if the send is withdrawn or the recipient never receives the file. If anything fails after the price is set aside, the step withdraws the send and the response says whether the tokens are already back (reservation: returned) or on their way (reservation: pending). In the rare case that the service never confirmed the send and it could not be withdrawn either, the answer says outcomeUnknown: check your sent FlyaDocs before sending it again. The refusals a person sending by hand would see come back the same way, with the same codes: 404 NO_INBOX for an address nobody has, 409 NOT_ACCEPTING when that box cannot take a file right now, 402 INSUFFICIENT_TOKENS, 429 RATE_LIMITED. A file type the box does not accept answers 422 FILE_TYPE_REFUSED before anything is charged. waitingForApproval is true when the box holds files from new senders until its owner approves them. This is a side effect: a second send is a second file in somebody's box and a second charge, so a workflow replaying a step it already completed gets the first send's answer back and nothing is sent again. One file per call. Not available in the anonymous playground or interactive builder Run (it sends from your account and is charged to it).
Parameters
NameTypeRequiredDescription
address string required The FlyaDoc address to send to: name@flyadoc.com, @name or name. An email address at any other domain is refused
fileName string required The name the recipient sees on the file, e.g. 'invoice-1042.pdf'. Up to 255 characters, with no slashes, colons, asterisks, question marks, quotation marks, angle brackets or vertical bars
contentBase64 string required The file's bytes, base64-encoded. Up to 33554432 bytes (32 MB) decoded
contentType string optional The file's media type, e.g. application/pdf. Defaults to application/octet-stream
safetyCode string optional The safety code the recipient publishes with their address: 10 letters and digits, in any letter case (a 20-digit code from before still works). When given, the send is refused if the address's keys no longer match it, for example after the recipient reset their box
coverAnswers object optional Answers to the box's cover sheet, by field name: {"case_number": "2026-CV-0142"}. A field the box does not ask for is refused
Request Example
JSON
{"address": "acme-records@flyadoc.com", "fileName": "invoice-1042.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}
Response Example
JSON
{"success": true, "itemId": "EX_01JA2B3C4D5E6F7G8H9J0K1M2N", "address": "acme-records@flyadoc.com", "status": "uploaded", "sizeBytes": 20481, "deleteAfter": "2026-11-05T23:59:59.999Z", "waitingForApproval": false}
Code Examples
curl -X POST "https://api.docbutterfly.com/api/SendWithFlyaDoc" \
  -H "X-API-Key: df_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"address": "acme-records@flyadoc.com", "fileName": "invoice-1042.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}'
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "df_your_api_key_here");

var json = @"{""address"": ""acme-records@flyadoc.com"", ""fileName"": ""invoice-1042.pdf"", ""contentBase64"": ""JVBERi0xLjcK..."", ""contentType"": ""application/pdf""}";
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://api.docbutterfly.com/api/SendWithFlyaDoc", content);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
import requests
import json

url = "https://api.docbutterfly.com/api/SendWithFlyaDoc"
headers = {
    "X-API-Key": "df_your_api_key_here",
    "Content-Type": "application/json"
}
payload = json.loads('{"address": "acme-records@flyadoc.com", "fileName": "invoice-1042.pdf", "contentBase64": "JVBERi0xLjcK...", "contentType": "application/pdf"}')

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()

data = response.json()
print(json.dumps(data, indent=2))
┌─────────────────────────────────────────────┐
│  Power Automate - HTTP Action               │
├─────────────────────────────────────────────┤
│                                             │
│  Method:  POST                              │
│  URI:     https://api.docbutterfly.com/api/SendWithFlyaDoc
│                                             │
│  Headers:                                   │
│    X-API-Key:    df_your_api_key_here       │
│    Content-Type: application/json           │
│                                             │
│  Body:                                      │
│    {
│      "address": "acme-records@flyadoc.com",
│      "fileName": "invoice-1042.pdf",
│      "contentBase64": "JVBERi0xLjcK...",
│      "contentType": "application/pdf"
│    }
│                                             │
└─────────────────────────────────────────────┘

Steps:
1. Add an HTTP action to your flow
2. Set Method to "POST"
3. Set URI to "https://api.docbutterfly.com/api/SendWithFlyaDoc"
4. Add the headers shown above
5. Paste the Body JSON into the Body field
6. Replace placeholder values with dynamic content as needed
Try in Testbed