REST API

API Reference

All endpoints accept and return JSON. Base URL: https://mdfy.cc

Rate limit: 10 requests/min per IP. Max document size: 500KB.

POST/api/docs

Create 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

bash
curl -X POST https://mdfy.cc/api/docs \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Hello World\nThis is my document.",
    "title": "My Document",
    "isDraft": false
  }'

Request - JavaScript

javascript
const res = await fetch("https://mdfy.cc/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

python
import requests

res = requests.post("https://mdfy.cc/api/docs", json={
    "markdown": "# Hello World\nThis is my document.",
    "title": "My Document",
    "isDraft": False,
})
data = res.json()

Response 200

json
{
  "id": "abc123",
  "editToken": "tok_aBcDeFgHiJkLmNoP",
  "created_at": "2026-04-15T00:00:00Z"
}
GET/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

bash
curl https://mdfy.cc/api/docs/abc123

# With password:
curl https://mdfy.cc/api/docs/abc123 \
  -H "x-document-password: mysecret"

Request - JavaScript

javascript
const res = await fetch("https://mdfy.cc/api/docs/abc123");
const doc = await res.json();

Request - Python

python
import requests

res = requests.get("https://mdfy.cc/api/docs/abc123")
doc = res.json()

Response 200

json
{
  "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
}
PATCH/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)

bash
curl -X PATCH https://mdfy.cc/api/docs/abc123 \
  -H "Content-Type: application/json" \
  -d '{
    "editToken": "tok_aBcDeFgH",
    "markdown": "# Updated Content",
    "changeSummary": "Fixed typos"
  }'

Request - curl (soft delete)

bash
curl -X PATCH https://mdfy.cc/api/docs/abc123 \
  -H "Content-Type: application/json" \
  -d '{
    "editToken": "tok_aBcDeFgH",
    "action": "soft-delete"
  }'

Request - JavaScript

javascript
const res = await fetch("https://mdfy.cc/api/docs/abc123", {
  method: "PATCH",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    editToken: "tok_aBcDeFgH",
    markdown: "# Updated Content",
  }),
});

Request - Python

python
import requests

res = requests.patch("https://mdfy.cc/api/docs/abc123", json={
    "editToken": "tok_aBcDeFgH",
    "markdown": "# Updated Content",
})

Response 200

json
{
  "success": true,
  "id": "abc123",
  "updated_at": "2026-04-15T02:00:00Z"
}
HEAD/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

bash
curl -I https://mdfy.cc/api/docs/abc123

# Response headers:
# x-updated-at: 2026-04-15T01:00:00Z
# x-content-length: 1234

Request - JavaScript

javascript
const res = await fetch("https://mdfy.cc/api/docs/abc123", {
  method: "HEAD",
});
const updatedAt = res.headers.get("x-updated-at");

Request - Python

python
import requests

res = requests.head("https://mdfy.cc/api/docs/abc123")
updated_at = res.headers["x-updated-at"]
GET/api/user/documents

List 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

bash
curl https://mdfy.cc/api/user/documents \
  -H "x-user-id: user-uuid-here"

Request - JavaScript

javascript
const res = await fetch("https://mdfy.cc/api/user/documents", {
  headers: { "x-user-id": "user-uuid-here" },
});
const { documents } = await res.json();

Request - Python

python
import requests

res = requests.get("https://mdfy.cc/api/user/documents",
    headers={"x-user-id": "user-uuid-here"})
documents = res.json()["documents"]

Response 200

json
{
  "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
    }
  ]
}
POST/api/upload

Upload an image file. Returns a public URL. Accepts multipart form-data with a file field.

Request - curl

bash
curl -X POST https://mdfy.cc/api/upload \
  -F "file=@screenshot.png"

Request - JavaScript

javascript
const form = new FormData();
form.append("file", fileBlob, "screenshot.png");

const res = await fetch("https://mdfy.cc/api/upload", {
  method: "POST",
  body: form,
});
const { url } = await res.json();

Request - Python

python
import requests

with open("screenshot.png", "rb") as f:
    res = requests.post("https://mdfy.cc/api/upload",
        files={"file": f})
url = res.json()["url"]

Response 200

json
{
  "url": "https://storage.mdfy.cc/uploads/screenshot.png"
}

Authentication

mdfy.cc 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

json
{
  "error": "Document not found",
  "status": 404
}