REST API
API Reference
All endpoints accept and return JSON. Base URL: https://mdfy.app
Rate limit: 10 requests/min per IP. Max document size: 500KB.
/api/docsCreate a new document. Returns document ID, edit token, and creation timestamp.
Parameters
markdownREQUIREDstringThe Markdown content of the document.titlestringDocument title. If not provided, extracted from the first heading.isDraftbooleanDraft status. Default: false. Draft documents are only visible to the owner.sourcestringSource identifier: api, web, vscode, mcp, cli.passwordstringPassword-protect the document. Readers must provide this to view.expiresInstringTime until document expires: 1h, 1d, 7d, 30d. Omit for permanent.editModestringWho can edit: token (default, requires editToken), anyone, authenticated.folderIdstringPlace the document in a specific folder.Request - curl
curl -X POST https://mdfy.app/api/docs \
-H "Content-Type: application/json" \
-d '{
"markdown": "# Hello World\nThis is my document.",
"title": "My Document",
"isDraft": false
}'Request - JavaScript
const res = await fetch("https://mdfy.app/api/docs", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
markdown: "# Hello World\nThis is my document.",
title: "My Document",
isDraft: false,
}),
});
const data = await res.json();Request - Python
import requests
res = requests.post("https://mdfy.app/api/docs", json={
"markdown": "# Hello World\nThis is my document.",
"title": "My Document",
"isDraft": False,
})
data = res.json()Response 200
{
"id": "abc123",
"editToken": "tok_aBcDeFgHiJkLmNoP",
"created_at": "2026-04-15T00:00:00Z"
}/api/docs/{id}Read a document by ID. Draft documents require owner authentication. Password-protected documents require the x-document-password header.
Headers (optional)
x-user-idstringUser UUID for ownership verification.x-document-passwordstringPassword for protected documents.x-user-emailstringUser email for identification.AuthorizationstringBearer token for OAuth-authenticated requests.Request - curl
curl https://mdfy.app/api/docs/abc123
# With password:
curl https://mdfy.app/api/docs/abc123 \
-H "x-document-password: mysecret"Request - JavaScript
const res = await fetch("https://mdfy.app/api/docs/abc123");
const doc = await res.json();Request - Python
import requests
res = requests.get("https://mdfy.app/api/docs/abc123")
doc = res.json()Response 200
{
"id": "abc123",
"title": "My Document",
"markdown": "# Hello World\nThis is my document.",
"created_at": "2026-04-15T00:00:00Z",
"updated_at": "2026-04-15T01:00:00Z",
"view_count": 42,
"is_draft": false,
"editMode": "token",
"isOwner": true,
"editToken": "tok_...",
"hasPassword": false
}/api/docs/{id}Update a document. Requires edit token or owner authentication. Supports multiple actions: update content, soft-delete, rotate-token, change-edit-mode.
Parameters
editTokenREQUIREDstringThe edit token returned at creation (required for token mode).markdownstringNew Markdown content.titlestringNew document title.isDraftbooleanToggle between draft and published state.actionstringSpecial action: soft-delete, rotate-token.changeSummarystringVersion note describing the change.editModestringChange edit mode: token, anyone, authenticated.Request - curl (update content)
curl -X PATCH https://mdfy.app/api/docs/abc123 \
-H "Content-Type: application/json" \
-d '{
"editToken": "tok_aBcDeFgH",
"markdown": "# Updated Content",
"changeSummary": "Fixed typos"
}'Request - curl (soft delete)
curl -X PATCH https://mdfy.app/api/docs/abc123 \
-H "Content-Type: application/json" \
-d '{
"editToken": "tok_aBcDeFgH",
"action": "soft-delete"
}'Request - JavaScript
const res = await fetch("https://mdfy.app/api/docs/abc123", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
editToken: "tok_aBcDeFgH",
markdown: "# Updated Content",
}),
});Request - Python
import requests
res = requests.patch("https://mdfy.app/api/docs/abc123", json={
"editToken": "tok_aBcDeFgH",
"markdown": "# Updated Content",
})Response 200
{
"success": true,
"id": "abc123",
"updated_at": "2026-04-15T02:00:00Z"
}/api/docs/{id}Check when a document was last updated. Returns x-updated-at response header. Useful for sync polling without downloading full content.
Request - curl
curl -I https://mdfy.app/api/docs/abc123
# Response headers:
# x-updated-at: 2026-04-15T01:00:00Z
# x-content-length: 1234Request - JavaScript
const res = await fetch("https://mdfy.app/api/docs/abc123", {
method: "HEAD",
});
const updatedAt = res.headers.get("x-updated-at");Request - Python
import requests
res = requests.head("https://mdfy.app/api/docs/abc123")
updated_at = res.headers["x-updated-at"]/api/user/documentsList all documents owned by a user. Requires user identification via header.
Headers
x-user-idREQUIREDstringUser UUID. Alternatively use x-user-email or Authorization: Bearer.Request - curl
curl https://mdfy.app/api/user/documents \
-H "x-user-id: user-uuid-here"Request - JavaScript
const res = await fetch("https://mdfy.app/api/user/documents", {
headers: { "x-user-id": "user-uuid-here" },
});
const { documents } = await res.json();Request - Python
import requests
res = requests.get("https://mdfy.app/api/user/documents",
headers={"x-user-id": "user-uuid-here"})
documents = res.json()["documents"]Response 200
{
"documents": [
{
"id": "abc123",
"title": "My Document",
"created_at": "2026-04-15T00:00:00Z",
"updated_at": "2026-04-15T01:00:00Z",
"is_draft": false,
"view_count": 42
}
]
}/api/uploadUpload an image file. Returns a public URL. Accepts multipart form-data with a file field.
Request - curl
curl -X POST https://mdfy.app/api/upload \
-F "file=@screenshot.png"Request - JavaScript
const form = new FormData();
form.append("file", fileBlob, "screenshot.png");
const res = await fetch("https://mdfy.app/api/upload", {
method: "POST",
body: form,
});
const { url } = await res.json();Request - Python
import requests
with open("screenshot.png", "rb") as f:
res = requests.post("https://mdfy.app/api/upload",
files={"file": f})
url = res.json()["url"]Response 200
{
"url": "https://storage.mdfy.app/uploads/screenshot.png"
}Authentication
mdfy.app uses progressive authentication. Basic operations require no auth. Advanced features use edit tokens or user identity.
No auth required
POST /api/docs and GET /api/docs/{id} work without authentication. The returned editToken is your proof of ownership.
Edit tokens
Every document gets an editToken at creation. Include it in PATCH requests to update or delete. MCP server and CLI manage tokens automatically.
User identity
For user-scoped actions (list, ownership), provide x-user-id header, x-user-email header, or Authorization: Bearer JWT token.
MCP / CLI auth
Both MCP server and CLI use JWT from mdfy login. Run: npm install -g mdfy-cli && mdfy login
Rate Limits
All endpoints are rate-limited to 10 requests per minute per IP. Exceeding the limit returns 429 Too Many Requests. The response includes Retry-After header indicating seconds to wait. Maximum document size is 500KB.
Errors
400errorBad Request. Missing required fields or invalid parameters.401errorUnauthorized. Invalid or missing edit token / credentials.403errorForbidden. Password required or wrong password.404errorNot Found. Document does not exist or has been deleted.410errorGone. Document has expired.429errorToo Many Requests. Rate limit exceeded.500errorInternal Server Error. Please retry or contact support.Error Response Format
{
"error": "Document not found",
"status": 404
}