A simple Typecho API plugin

Typecho API Plugin

This folder contains a deployable Typecho plugin named TypechoApi.

Install

  1. Copy the TypechoApi directory into your Typecho plugin directory: usr/plugins/TypechoApi
  2. Enable the plugin from the Typecho admin panel.
  3. Open the plugin settings and configure authentication.

Endpoints

  • GET /typecho-api/v1/posts
  • POST /typecho-api/v1/posts
  • GET /typecho-api/v1/post?id=123
  • PUT /typecho-api/v1/post?id=123
  • PATCH /typecho-api/v1/post?id=123
  • DELETE /typecho-api/v1/post?id=123

All endpoints return JSON.

Authentication

Recommended:

  • Enable Basic auth + Bearer token
  • Create a dedicated Typecho user for the API with the editor or administrator role
  • Use HTTP Basic auth with that account for server-to-server calls

Optional:

  • Add Bearer tokens in plugin settings, one per line: label:secret
  • Restrict access further with the IP allow-list

Example Requests

List posts:

curl -u api-user:api-password \
  'https://your-site.example/index.php/typecho-api/v1/posts?page=1&pageSize=10'

Create a post:

curl -u api-user:api-password \
  -H 'Content-Type: application/json' \
  -X POST \
  'https://your-site.example/index.php/typecho-api/v1/posts' \
  -d '{
    "title": "Hello from API",
    "text": "This post was created through the Typecho API plugin.",
    "status": "publish"
  }'

Create a Markdown post:

curl -H 'X-Typecho-Token: replace-this-token' \
  -H 'Content-Type: application/json' \
  -X POST \
  'https://your-site.example/index.php/typecho-api/v1/posts' \
  -d '{
    "title": "Markdown post",
    "markdown": "# Heading\n\nThis is **Markdown** content.",
    "status": "publish"
  }'

Create a published post with categories and tags:

curl -H 'X-Typecho-Token: replace-this-token' \
  -H 'Content-Type: application/json' \
  -X POST \
  'https://your-site.example/index.php/typecho-api/v1/posts' \
  -d '{
    "title": "Taxonomy example",
    "markdown": "# Post body",
    "status": "publish",
    "categories": ["News", {"name": "Announcements", "slug": "announcements"}],
    "tags": ["api", "typecho"]
  }'

Update a post:

curl -u api-user:api-password \
  -H 'Content-Type: application/json' \
  -X PUT \
  'https://your-site.example/index.php/typecho-api/v1/post?id=12' \
  -d '{
    "title": "Updated title",
    "text": "Updated content",
    "status": "draft"
  }'

Delete a post:

curl -u api-user:api-password \
  -X DELETE \
  'https://your-site.example/index.php/typecho-api/v1/post?id=12'

Bearer token request:

curl -H 'Authorization: Bearer replace-this-token' \
  'https://your-site.example/index.php/typecho-api/v1/posts'

Sample JSON Responses

List posts:

{
  "data": [
    {
      "id": 12,
      "title": "Markdown post",
      "slug": "markdown-post",
      "status": "publish",
      "text": "<!--markdown-->\n\n# Heading\n\nThis is **Markdown** content.",
      "markdown": "# Heading\n\nThis is **Markdown** content.",
      "contentFormat": "markdown",
      "authorId": 1,
      "authorName": "Admin",
      "allowComment": true,
      "allowPing": true,
      "allowFeed": true,
      "created": 1773102541,
      "createdAt": "2026-03-10T00:29:01+00:00",
      "modified": 1773102541,
      "modifiedAt": "2026-03-10T00:29:01+00:00",
      "categories": [
        {
          "id": 2,
          "name": "News",
          "slug": "news",
          "type": "category"
        }
      ],
      "tags": [
        {
          "id": 5,
          "name": "api",
          "slug": "api",
          "type": "tag"
        }
      ],
      "excerpt": "Heading This is Markdown content."
    }
  ],
  "meta": {
    "page": 1,
    "pageSize": 10,
    "total": 1
  }
}

Get a single post:

{
  "data": {
    "id": 12,
    "title": "Markdown post",
    "slug": "markdown-post",
    "status": "publish",
    "text": "<!--markdown-->\n\n# Heading\n\nThis is **Markdown** content.",
    "markdown": "# Heading\n\nThis is **Markdown** content.",
    "contentFormat": "markdown",
    "authorId": 1,
    "authorName": "Admin",
    "allowComment": true,
    "allowPing": true,
    "allowFeed": true,
    "created": 1773102541,
    "createdAt": "2026-03-10T00:29:01+00:00",
    "modified": 1773102541,
    "modifiedAt": "2026-03-10T00:29:01+00:00",
    "categories": [
      {
        "id": 2,
        "name": "News",
        "slug": "news",
        "type": "category"
      }
    ],
    "tags": [
      {
        "id": 5,
        "name": "api",
        "slug": "api",
        "type": "tag"
      }
    ]
  }
}

Create or update success:

{
  "message": "Post created.",
  "data": {
    "id": 12,
    "title": "Markdown post",
    "slug": "markdown-post",
    "status": "publish",
    "text": "<!--markdown-->\n\n# Heading\n\nThis is **Markdown** content.",
    "markdown": "# Heading\n\nThis is **Markdown** content.",
    "contentFormat": "markdown",
    "authorId": 1,
    "authorName": "Admin",
    "allowComment": true,
    "allowPing": true,
    "allowFeed": true,
    "created": 1773102541,
    "createdAt": "2026-03-10T00:29:01+00:00",
    "modified": 1773102541,
    "modifiedAt": "2026-03-10T00:29:01+00:00",
    "categories": [],
    "tags": []
  }
}

Error response:

{
  "error": {
    "code": 401,
    "message": "Authentication failed."
  }
}

Notes

  • The plugin manages standard Typecho posts in table.contents.
  • POST creates new posts.
  • PUT replaces a post payload.
  • PATCH partially updates a post.
  • DELETE performs a hard delete.
  • For write operations, markdown, text, and content are accepted. markdown takes priority when more than one is provided.
  • When markdown is used, the plugin stores the post in Typecho's native Markdown format with the <!--markdown--> prefix.
  • categories/category and tags/tag are accepted on create/update. Each can be a comma-separated string, an array of names, or an array of objects with id, name, and optional slug.