.do

MDX.md

REST API for MDXLD documents

MDX.md

MDX.md is the REST API for MDXLD documents - GET, POST, PUT, DELETE operations for MDX content over HTTP.

What is MDX.md?

MDX.md provides a text-only HTTP API for MDXLD documents:

  • GET: Retrieve MDX documents as plain text
  • POST: Create new MDX documents
  • PUT: Update existing MDX documents
  • DELETE: Delete MDX documents
  • Content-Type: text/markdown or text/mdx
  • No UI: Pure API, no visual interface
  • Authentication: OAuth via OAuth.do

URL Patterns

Database Structure: mdx.md/:domain/:type/:id

Access documents using the platform database structure:

Where:

  • :domain - The domain/namespace (e.g., blog.do, docs.do, landing.do)
  • :type - Document $type (e.g., BlogPost, Article, LandingPage)
  • :id - Document $id from platform database

Custom URL: mdx.md/:url

Access documents with custom URLs stored in the database:

The platform resolves the URL to the correct document in the database.

HTTP Methods

GET - Retrieve Document

Retrieve MDX document as plain text:

Response:

---
$id: my-first-post
$type: BlogPost
$context: https://schema.org
title: My First Post
author: Jane Doe
datePublished: 2024-01-15
---

# My First Post

This is my first blog post...

Response Headers:

  • Content-Type: text/markdown; charset=utf-8
  • X-MDX-Type: BlogPost
  • X-MDX-ID: my-first-post
  • X-MDX-Domain: blog.do

POST - Create Document

Create a new MDX document:

curl -X POST https://mdx.md/blog.do/BlogPost/new-post \
  -H "Content-Type: text/markdown" \
  -H "Authorization: Bearer $TOKEN" \
  --data-binary @new-post.mdx

Request Body:

---
$type: BlogPost
$context: https://schema.org
title: New Blog Post
---

# New Blog Post

Content here...

Response:

  • 201 Created
  • Location: https://mdx.md/blog.do/BlogPost/new-post

PUT - Update Document

Update an existing MDX document:

curl -X PUT https://mdx.md/blog.do/BlogPost/my-first-post \
  -H "Content-Type: text/markdown" \
  -H "Authorization: Bearer $TOKEN" \
  --data-binary @updated-post.mdx

Response:

  • 200 OK

DELETE - Delete Document

Delete an MDX document:

curl -X DELETE https://mdx.md/blog.do/BlogPost/my-first-post \
  -H "Authorization: Bearer $TOKEN"

Response:

  • 204 No Content

Query Parameters

Format

Specify output format:

Revision

Get specific revision:

Fields

Select specific fields:

List Documents

List documents by type:

Authentication

Use OAuth tokens for authenticated requests:

# Get OAuth token
TOKEN=$(curl -X POST https://oauth.do/token \
  -d "grant_type=client_credentials" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET" \
  | jq -r .access_token)

# Use token
curl https://mdx.md/blog.do/BlogPost/my-post \
  -H "Authorization: Bearer $TOKEN"

Content Negotiation

MDX.md supports content negotiation via Accept header:

# Get as Markdown
curl https://mdx.md/blog.do/BlogPost/my-post \
  -H "Accept: text/markdown"

# Get as JSON
curl https://mdx.md/blog.do/BlogPost/my-post \
  -H "Accept: application/json"

# Get as HTML (rendered)
curl https://mdx.md/blog.do/BlogPost/my-post \
  -H "Accept: text/html"

# Get as XML (Atom/RSS)
curl https://mdx.md/blog.do/BlogPost \
  -H "Accept: application/atom+xml"

Response Formats

Markdown (default)

Raw MDX document:

---
$type: BlogPost
title: My Post
---

# My Post

Content...

JSON

Structured format:

{
  "$id": "my-post",
  "$type": "BlogPost",
  "$context": "https://schema.org",
  "data": {
    "title": "My Post",
    "author": "Jane Doe",
    "datePublished": "2024-01-15"
  },
  "content": "# My Post\n\nContent...",
  "metadata": {
    "created": "2024-01-15T10:00:00Z",
    "modified": "2024-01-15T12:00:00Z",
    "revision": 3
  }
}

HTML

Rendered output:

<!DOCTYPE html>
<html>
<head>
  <title>My Post</title>
  <meta property="og:type" content="article">
</head>
<body>
  <article>
    <h1>My Post</h1>
    <p>Content...</p>
  </article>
</body>
</html>

Batch Operations

Batch GET

Retrieve multiple documents:

curl -X POST https://mdx.md/_batch \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      {"method": "GET", "path": "/blog.do/BlogPost/post-1"},
      {"method": "GET", "path": "/blog.do/BlogPost/post-2"},
      {"method": "GET", "path": "/blog.do/BlogPost/post-3"}
    ]
  }'

Batch POST/PUT

Create or update multiple documents:

curl -X POST https://mdx.md/_batch \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "operations": [
      {
        "method": "POST",
        "path": "/blog.do/BlogPost/new-post-1",
        "body": "---\n$type: BlogPost\n---\n\n# Post 1"
      },
      {
        "method": "PUT",
        "path": "/blog.do/BlogPost/existing-post",
        "body": "---\n$type: BlogPost\n---\n\n# Updated"
      }
    ]
  }'

Webhooks

Subscribe to document changes:

# Register webhook
curl -X POST https://mdx.md/_webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "url": "https://myapp.com/webhook",
    "events": ["created", "updated", "deleted"],
    "filter": {
      "type": "BlogPost",
      "domain": "blog.do"
    }
  }'

Webhook payload:

{
  "event": "updated",
  "document": {
    "$id": "my-post",
    "$type": "BlogPost",
    "domain": "blog.do"
  },
  "changes": {
    "title": {
      "old": "Old Title",
      "new": "New Title"
    }
  },
  "timestamp": "2024-01-15T12:00:00Z"
}

Integration Examples

Git Sync

Sync MDX documents to Git:

#!/bin/bash
# Fetch all documents
curl "https://mdx.md/blog.do/BlogPost?format=json" | \
  jq -r '.[] | "\(.data.path) \(.$id)"' | \
  while read path id; do
    curl "https://mdx.md/blog.do/BlogPost/$id" > "$path"
  done

git add .
git commit -m "Sync from MDX.md"
git push

CI/CD Integration

Deploy on document update:

# .github/workflows/deploy.yml
name: Deploy on MDX Update
on:
  repository_dispatch:
    types: [mdx-updated]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Fetch updated MDX
        run: |
          curl "https://mdx.md/${{ github.event.client_payload.path }}" \
            -o "${{ github.event.client_payload.local_path }}"
      - name: Deploy
        run: npm run deploy

CMS Integration

Use as headless CMS:

import { MDXClient } from '@dotdo/mdx-client'

const mdx = new MDXClient({
  baseURL: 'https://mdx.md',
  token: process.env.MDX_TOKEN
})

// Fetch all blog posts
const posts = await mdx.list('blog.do', 'BlogPost', {
  sort: '-datePublished',
  limit: 10
})

// Fetch single post
const post = await mdx.get('blog.do', 'BlogPost', 'my-post')

// Create new post
await mdx.create('blog.do', 'BlogPost', 'new-post', {
  frontmatter: {
    title: 'New Post',
    author: 'Jane Doe'
  },
  content: '# New Post\n\nContent...'
})

// Update post
await mdx.update('blog.do', 'BlogPost', 'my-post', {
  frontmatter: {
    title: 'Updated Title'
  }
})

// Delete post
await mdx.delete('blog.do', 'BlogPost', 'my-post')

Error Responses

404 Not Found

{
  "error": "not_found",
  "message": "Document not found",
  "path": "/blog.do/BlogPost/nonexistent"
}

401 Unauthorized

{
  "error": "unauthorized",
  "message": "Authentication required"
}

403 Forbidden

{
  "error": "forbidden",
  "message": "Insufficient permissions"
}

422 Unprocessable Entity

{
  "error": "validation_error",
  "message": "Invalid frontmatter",
  "details": [
    {
      "field": "datePublished",
      "message": "Must be a valid ISO 8601 date"
    }
  ]
}

Rate Limits

  • Free tier: 100 requests/hour
  • Pro tier: 1,000 requests/hour
  • Enterprise: Unlimited

Rate limit headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642262400

Best Practices

  1. Use authentication: Always use OAuth tokens for write operations
  2. Handle rate limits: Implement exponential backoff
  3. Cache responses: Use ETags for conditional requests
  4. Batch operations: Use batch API for multiple requests
  5. Subscribe to webhooks: Get real-time updates instead of polling
  6. Validate frontmatter: Ensure valid YAML before POST/PUT
  7. Version documents: Use revision parameter for history

Resources