docubend
Documentation

Quickstart

From nothing to a PDF on your disk. Three steps, and the third one is the one that makes the file.

1. Make a credential#

Go to API access, name a credential and choose what it may do. You are shown a client id and a secret once — what we store is a SHA-256 of the secret, so nobody here can read it back to you, including us.

The API is part of Pro and Enterprise. If your account is on Free the page still explains all of this; the credential is what it will not make.

A credential can hold documents:read, documents:write, or both. Scope is checked by HTTP method, so a read credential is refused on every POST, PUT, PATCH and DELETE — including routes that do not exist yet.

2. Exchange it for a token#

Standard OAuth 2.0 client credentials. Any OAuth library does this without being told anything about us. The token lasts one hour — ask for one when you need one and keep it until it expires.

curl
export DOCUBEND_CLIENT_ID=dbc_…
export DOCUBEND_SECRET=dbs_…

TOKEN=$(curl -s https://docubend.com/auth/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=$DOCUBEND_CLIENT_ID \
  -d client_secret=$DOCUBEND_SECRET | jq -r .access_token)
JavaScript
const BASE = "https://docubend.com";

const auth = await fetch(`${BASE}/auth/oauth/token`, {
  method: "POST",
  body: new URLSearchParams({
    grant_type: "client_credentials",
    client_id: process.env.DOCUBEND_CLIENT_ID,
    client_secret: process.env.DOCUBEND_SECRET,
  }),
});
const { access_token: TOKEN } = await auth.json();
Python
import os, requests

BASE = "https://docubend.com"

auth = requests.post(f"{BASE}/auth/oauth/token", data={
    "grant_type": "client_credentials",
    "client_id": os.environ["DOCUBEND_CLIENT_ID"],
    "client_secret": os.environ["DOCUBEND_SECRET"],
}, timeout=30)
auth.raise_for_status()
TOKEN = auth.json()["access_token"]

3. Make a document, and download it as a PDF#

Two calls. POST /api/v1/pdfs sets your Markdown as real, selectable text and keeps the result as a document; GET /api/v1/documents/<id>.pdf renders that document as it stands right now.

The second call is not a download of a file we are holding — there is no file. Ask again after an edit and you get a different PDF, which is the right behaviour for a document and would be a bug for a blob.

curl
ID=$(curl -s https://docubend.com/api/v1/pdfs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Invoice 1042","markdown":"# Invoice 1042\n\n**Due 30 September.**\n\n| Item | Amount |\n| --- | --- |\n| Retainer | $2,400 |"}' \
  | jq -r .document.id)

curl -s https://docubend.com/api/v1/documents/$ID.pdf \
  -H "Authorization: Bearer $TOKEN" -o invoice.pdf

open invoice.pdf
JavaScript
import { writeFile } from "node:fs/promises";

const made = await fetch(`${BASE}/api/v1/pdfs`, {
  method: "POST",
  headers: { Authorization: `Bearer ${TOKEN}`,
             "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "Invoice 1042",
    markdown: "# Invoice 1042\n\n**Due 30 September.**",
  }),
});
if (!made.ok) throw new Error(`docubend: ${made.status}`);
const { document: doc } = await made.json();

const pdf = await fetch(doc.links.pdf,
  { headers: { Authorization: `Bearer ${TOKEN}` } });
await writeFile("invoice.pdf", Buffer.from(await pdf.arrayBuffer()));

console.log(doc.links.open);   // a person can open this one in a browser
Python
made = requests.post(f"{BASE}/api/v1/pdfs",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={
        "title": "Invoice 1042",
        "markdown": "# Invoice 1042\n\n**Due 30 September.**",
    }, timeout=60)
made.raise_for_status()
doc = made.json()["document"]

pdf = requests.get(doc["links"]["pdf"],
    headers={"Authorization": f"Bearer {TOKEN}"}, timeout=60)
open("invoice.pdf", "wb").write(pdf.content)

print(doc["links"]["open"])    # a person can open this one in a browser

Response

201
{
  "ok": true,
  "document": {
    "id": "ba59b6ce5221411285daea90f4be16b6",
    "title": "Invoice 1042",
    "kind": "pdf",
    "pages": 1,
    "shapes": 11,
    "version": 2,
    "your_role": "owner",
    "links": {
      "self": "https://docubend.com/api/v1/documents/ba59b6ce5221411285daea90f4be16b6",
      "pdf": "https://docubend.com/api/v1/documents/ba59b6ce5221411285daea90f4be16b6.pdf",
      "open": "https://docubend.com/d/ba59b6ce5221411285daea90f4be16b6",
      "…": "svg, png, model, mermaid"
    }
  }
}

Where to go next#

What else that document can doIt is an ordinary docubend document: it opens in the editor, takes annotations and diagrams, can be shared, searched and versioned.
The other four things a PDF can be made fromHTML, a PNG or JPEG, somebody else's PDF, or a document model of your own.
Turn it into a formPut fields on any document, send it to be filled in, and read the answers back as rows or as a spreadsheet.