Documents
Everything the API makes is a document. These are the calls that read one back, in whatever shape the far end can take.
.pdf is a rendering, not a
file we are holding. Ask for it twice with an edit in between and you
get two different files, which is the right behavior for a document and
would be a bug for a blob.List documents#
GET
/api/v1/documents
documents:read
Everything this account can open, what it owns and what has been shared with it, in the order the workspace shows them.
kind | optional | pdf or diagram. |
limit | optional | Up to 200. 50 by default. |
offset | optional | Where to start. total in the response is the count before the window is applied. |
curl -s "https://docubend.com/api/v1/documents?kind=diagram&limit=2" \
-H "Authorization: Bearer $TOKEN"
const r = await fetch(
`${BASE}/api/v1/documents?kind=diagram&limit=2`,
{ headers: { Authorization: `Bearer ${TOKEN}` } });
const { documents } = await r.json();
docs = requests.get(f"{BASE}/api/v1/documents",
headers={"Authorization": f"Bearer {TOKEN}"},
params={"kind": "diagram", "limit": 2},
timeout=30).json()["documents"]
for d in docs:
print(d["updated"], d["kind"], d["title"])
Response
{
"ok": true,
"total": 2,
"documents": [
{
"id": "6b35e4159e2e4b0e80ebae85f41cd6fd",
"title": "Release pipeline",
"kind": "diagram",
"pages": 1,
"shapes": 4,
"updated": 1786717599.9,
"created": 1786717599.5,
"version": 2,
"your_role": "owner",
"links": {
"…": "as above"
}
}
]
}
One document#
GET
/api/v1/documents/{id}
documents:read
What it is, how big it is and when it changed. Add
?include=model for the document's own JSON as well, left
out by default because it can be megabytes and a list view that wanted a
title should not pay for one.
include | optional | model to include the document's JSON under data. |
curl -s https://docubend.com/api/v1/documents/ba59b6ce5221411285daea90f4be16b6 \
-H "Authorization: Bearer $TOKEN"
const r = await fetch(`${BASE}/api/v1/documents/${docId}`,
{ headers: { Authorization: `Bearer ${TOKEN}` } });
const { document: doc } = await r.json();
doc = requests.get(f"{BASE}/api/v1/documents/{doc_id}",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30).json()["document"]
print(doc["kind"], doc["pages"], "pages, version", doc["version"])
Response
{
"ok": true,
"document": {
"id": "ba59b6ce5221411285daea90f4be16b6",
"title": "Nightly build report",
"kind": "pdf",
"pages": 1,
"shapes": 11,
"version": 2,
"created": 1786717599.3359814,
"updated": 1786717599.4855263,
"your_role": "owner",
"links": {
"…": "as above"
}
}
}
Download it in any format#
GET
/api/v1/documents/{id}.{format}
documents:read
The document, said differently. Rendered at the moment you ask, so it always matches the document as it stands, including changes somebody made by hand in the editor after your software created it.
If a PDF could not be drawn exactly, characters outside what the
standard PDF fonts can set, or a picture that could not be read. It is
said in an X-Docubend-Warning header rather than left for
you to notice. Mermaid exports carry
X-Docubend-Shapes, X-Docubend-Dropped and
X-Docubend-Loose-Connectors, because not everything on a
page has a spelling in mermaid.
.pdf | application/pdf | The whole document, rendered now. ?page=2 for one page. |
.png | image/png | One page as a picture. ?page=, and ?dpi= up to 200 (110 by default). |
.svg | image/svg+xml | One page as vector SVG. ?page=. |
.mmd | text/vnd.mermaid | A diagram as mermaid text. Only what mermaid can say. The rest is counted in the response headers. |
.drawio | application/xml | A diagram as a .drawio file, openable in diagrams.net. |
.json | application/json | The document's own model. The same JSON the editor works on. |
# a PDF of the whole document
curl -s https://docubend.com/api/v1/documents/ba59b6ce5221411285daea90f4be16b6.pdf \
-H "Authorization: Bearer $TOKEN" -o report.pdf
# page 1 as a picture, at 150 dpi
curl -s "https://docubend.com/api/v1/documents/ba59b6ce5221411285daea90f4be16b6.png?page=1&dpi=150" \
-H "Authorization: Bearer $TOKEN" -o page-1.png
import { writeFile } from "node:fs/promises";
const r = await fetch(`${BASE}/api/v1/documents/${docId}.pdf`,
{ headers: { Authorization: `Bearer ${TOKEN}` } });
const warning = r.headers.get("x-docubend-warning");
if (warning) console.warn("note:", warning);
await writeFile("report.pdf", Buffer.from(await r.arrayBuffer()));
pdf = requests.get(f"{BASE}/api/v1/documents/{doc_id}.pdf",
headers={"Authorization": f"Bearer {TOKEN}"}, timeout=120)
if pdf.headers.get("X-Docubend-Warning"):
print("note:", pdf.headers["X-Docubend-Warning"])
open("report.pdf", "wb").write(pdf.content)
png = requests.get(f"{BASE}/api/v1/documents/{doc_id}.png",
headers={"Authorization": f"Bearer {TOKEN}"},
params={"page": 1, "dpi": 150}, timeout=120)
open("page-1.png", "wb").write(png.content)
Response
%PDF-1.4
…3,184 bytes of PDF…
A diagram back as mermaid#
GET
/api/v1/documents/{id}.mmd
documents:read
Anything drawn as boxes and arrows comes back out as mermaid text, for a README, a ticket, or a diff that a human can read. What has no spelling in mermaid (a pen stroke, a picture, a connector with a loose end) is counted in the headers rather than dropped silently.
A round trip through mermaid keeps the structure and not the arrangement, because the format has no coordinates to keep.
curl -s https://docubend.com/api/v1/documents/6b35e4159e2e4b0e80ebae85f41cd6fd.mmd \
-H "Authorization: Bearer $TOKEN" -D headers.txt
const r = await fetch(`${BASE}/api/v1/documents/${docId}.mmd`,
{ headers: { Authorization: `Bearer ${TOKEN}` } });
console.log(await r.text());
console.log(r.headers.get("x-docubend-shapes"), "shapes");
r = requests.get(f"{BASE}/api/v1/documents/{doc_id}.mmd",
headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30)
print(r.text)
print(r.headers["X-Docubend-Shapes"], "shapes,",
r.headers["X-Docubend-Dropped"], "could not be said in mermaid")
Response
flowchart TD
Build[Build]
Tests_pass{Tests pass?}
Ship[(Ship)]
Fix[Fix]
Build --> Tests_pass
Tests_pass -->|yes| Ship
Tests_pass -->|no| Fix
Fix --> Build
Delete one#
DELETE
/api/v1/documents/{id}
documents:write
To the bin, where the account's retention setting keeps it, thirty days by default, and from where a person can put it back. Nothing here destroys a document immediately, on purpose.
curl -s -X DELETE https://docubend.com/api/v1/documents/ba59b6ce5221411285daea90f4be16b6 \
-H "Authorization: Bearer $TOKEN"
await fetch(`${BASE}/api/v1/documents/${docId}`, {
method: "DELETE",
headers: { Authorization: `Bearer ${TOKEN}` },
});
requests.delete(f"{BASE}/api/v1/documents/{doc_id}",
headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30).json()
Response
{
"ok": true,
"binned": "ba59b6ce5221411285daea90f4be16b6"
}