Files
Suwayomi-Server/API_DOCUMENTATION.md
achmad 06e93fd7bd
CI build / Validate Gradle Wrapper (push) Successful in 2m30s
CI build / jlink (linux-x64, ubuntu-latest) (push) Failing after 1m12s
CI build / Build Jar (push) Failing after 2m18s
CI build / jlink (macOS-arm64, macos-15) (push) Has been cancelled
CI build / jlink (macOS-x64, macos-15-intel) (push) Has been cancelled
CI build / jlink (windows-x64, windows-latest) (push) Has been cancelled
CI build / Make linux-assets release (push) Has been cancelled
CI build / Make appimage release (push) Has been cancelled
CI build / Make debian-all release (push) Has been cancelled
CI build / Make linux-x64 release (push) Has been cancelled
CI build / Make macOS-arm64 release (push) Has been cancelled
CI build / Make macOS-x64 release (push) Has been cancelled
CI build / Make windows-x64 release (push) Has been cancelled
CI build / release (push) Has been cancelled
chore: add Docker build config, scripts, and private registry setup
2026-05-10 11:45:24 +07:00

42 KiB

Suwayomi-Server REST API Documentation

This document describes all REST API endpoints available in Suwayomi-Server.

Base URL: http://localhost:4567/api/v1/


Authentication

All API endpoints (except where noted) require HTTP Basic Authentication.

Authorization Header

Include the following header in your requests:

Authorization: Basic <base64-encoded-credentials>

How to Generate the Header

  1. Combine username and password with a colon: username:password
  2. Encode the string in Base64
  3. Prepend with Basic

Example:

  • Username: admin
  • Password: password123
  • Credentials string: admin:password123
  • Base64 encoded: YWRtaW46cGFzc3dvcmQxMjM=
  • Header: Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=

Default Credentials

The default username and password are configured in the server settings:

  • Default username: admin
  • Default password: admin

Note: These should be changed in production via server configuration.

Authentication Modes

The server supports different authentication modes (configured in server settings):

  1. BASIC_AUTH - Requires Basic Auth header for all API requests
  2. SIMPLE_LOGIN - Uses cookie-based session authentication for web interface, but requires Basic Auth for API
  3. NONE - No authentication required (not recommended for production)

Unauthorized Response

If authentication fails, the server returns:

HTTP 401 Unauthorized

WWW-Authenticate: Basic

Response Body:

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

WebSocket Authentication

WebSocket endpoints use the same Basic Authentication mechanism. Include the Authorization header when establishing the WebSocket connection.


Table of Contents

  1. Extension Endpoints
  2. Source Endpoints
  3. Manga Endpoints
  4. Chapter Endpoints
  5. Category Endpoints
  6. Backup Endpoints
  7. Download Endpoints
  8. Update Endpoints
  9. Track Endpoints
  10. Global Meta Endpoints
  11. Settings Endpoints
  12. WebView Endpoints
  13. WebSocket Endpoints
  14. OPDS Endpoints

Extension Endpoints

GET /api/v1/extension/list

  • What it does: List all installed extensions
  • Expected request: No parameters required
  • Expected response: JSON array of ExtensionDataClass objects (HTTP 200)

Response JSON Example:

[
  {
    "repo": "https://raw.githubusercontent.com/k对身体1/extensions/repo",
    "apkName": "extensions/kofthub/Dramacafe",
    "iconUrl": "/extension/icon/Dramacafe.apk",
    "name": "Dramacafe",
    "pkgName": "eu.kanade.tachiyomi.extension.en.dramacafe",
    "versionName": "1.2.3",
    "versionCode": 12,
    "lang": "en",
    "isNsfw": false,
    "installed": true,
    "hasUpdate": false,
    "obsolete": false
  }
]

GET /api/v1/extension/install/{pkgName}

  • What it does: Install an extension by package name
  • Expected request: Path parameter: pkgName (string) - e.g., eu.kanade.tachiyomi.extension.en.mangadex
  • Expected response: HTTP 201 (Created), HTTP 302 (Found), or HTTP 500 (Internal Server Error)

POST /api/v1/extension/install

  • What it does: Install an extension from uploaded APK file
  • Expected request: Multipart form data with file field named "file" containing the extension APK
  • Expected response: HTTP 201 (Created), HTTP 302 (Found), or HTTP 500 (Internal Server Error)

GET /api/v1/extension/update/{pkgName}

  • What it does: Update an extension by package name
  • Expected request: Path parameter: pkgName (string)
  • Expected response: HTTP 201 (Created), HTTP 302 (Found), HTTP 404 (Not Found), or HTTP 500 (Internal Server Error)

GET /api/v1/extension/uninstall/{pkgName}

  • What it does: Uninstall an extension by package name
  • Expected request: Path parameter: pkgName (string)
  • Expected response: HTTP 200 (OK), HTTP 404 (Not Found), or HTTP 500 (Internal Server Error)

GET /api/v1/extension/icon/{apkName}

  • What it does: Get the icon for an extension
  • Expected request: Path parameter: apkName (string) - e.g., Dramacafe.apk
  • Expected response: Image file (PNG/JPEG) with HTTP 200, or HTTP 404 (Not Found)

Source Endpoints

GET /api/v1/source/list

  • What it does: List all available sources
  • Expected request: No parameters required
  • Expected response: JSON array of SourceDataClass objects (HTTP 200)

Response JSON Example:

[
  {
    "id": "1234567890",
    "name": "MangaDex",
    "lang": "en",
    "iconUrl": "/source/icon/1234567890",
    "supportsLatest": true,
    "isConfigurable": true,
    "isNsfw": false,
    "displayName": "MangaDex",
    "baseUrl": "https://mangadex.org"
  }
]

GET /api/v1/source/{sourceId}

  • What it does: Get information about a specific source
  • Expected request: Path parameter: sourceId (long) - e.g., 1234567890
  • Expected response: JSON SourceDataClass object (HTTP 200) or HTTP 404 (Not Found)

GET /api/v1/source/{sourceId}/popular/{pageNum}

  • What it does: Get popular manga from a source
  • Expected request: Path parameters: sourceId (long), pageNum (int)
  • Expected response: JSON PagedMangaListDataClass object (HTTP 200)

Response JSON Example:

{
  "mangaList": [
    {
      "id": 1,
      "sourceId": "1234567890",
      "url": "/manga/12345",
      "title": "One Piece",
      "thumbnailUrl": "https://example.com/cover.jpg",
      "thumbnailUrlLastFetched": 1699999999,
      "initialized": true,
      "artist": "Eiichiro Oda",
      "author": "Eiichiro Oda",
      "description": "Monkey D. Luffy sets off on an adventure...",
      "genre": ["Action", "Adventure", "Comedy"],
      "status": "ONGOING",
      "inLibrary": true,
      "inLibraryAt": 1699999999,
      "source": null,
      "meta": {},
      "realUrl": "https://mangadex.org/manga/12345",
      "lastFetchedAt": 1699999999,
      "chaptersLastFetchedAt": 1699999999,
      "updateStrategy": "ALWAYS_UPDATE",
      "freshData": false,
      "unreadCount": 100,
      "downloadCount": 0,
      "chapterCount": 1000,
      "lastReadAt": null,
      "lastChapterRead": null,
      "age": 0,
      "chaptersAge": 0,
      "trackers": null
    }
  ],
  "hasNextPage": true
}

GET /api/v1/source/{sourceId}/latest/{pageNum}

  • What it does: Get latest manga from a source
  • Expected request: Path parameters: sourceId (long), pageNum (int)
  • Expected response: JSON PagedMangaListDataClass object (HTTP 200)

GET /api/v1/source/{sourceId}/preferences

  • What it does: Get source preferences/settings
  • Expected request: Path parameter: sourceId (long)
  • Expected response: JSON array of preference objects (HTTP 200)

Response JSON Example:

[
  {
    "type": "EditTextPreference",
    "props": {
      "key": "username",
      "title": "Username",
      "summary": "",
      "text": "",
      "default": ""
    }
  },
  {
    "type": "SwitchPreferenceCompat",
    "props": {
      "key": "hentai",
      "title": "Show Hentai",
      "summary": "Show mature content",
      "checked": false
    }
  }
]

POST /api/v1/source/{sourceId}/preferences

  • What it does: Set a source preference
  • Expected request: Path parameter: sourceId (long), body: SourcePreferenceChange JSON object

Request JSON Example:

{
  "position": 0,
  "value": "myusername"
}
  • Expected response: HTTP 200 (OK)

GET /api/v1/source/{sourceId}/filters

  • What it does: Get source filters
  • Expected request: Path parameter: sourceId (long), optional query param: reset (boolean)
  • Expected response: JSON array of FilterObject objects (HTTP 200)

Response JSON Example:

[
  {
    "type": "Header",
    "filter": {
      "name": "Content"
    }
  },
  {
    "type": "Select",
    "filter": {
      "name": "Genre",
      "state": 0,
      "values": ["All", "Action", "Adventure", "Comedy"]
    }
  },
  {
    "type": "Text",
    "filter": {
      "name": "Year",
      "state": ""
    }
  },
  {
    "type": "CheckBox",
    "filter": {
      "name": "Completed",
      "state": false
    }
  }
]

POST /api/v1/source/{sourceId}/filters

  • What it does: Set source filters
  • Expected request: Path parameter: sourceId (long), body: FilterChange object or array of FilterChange objects

Request JSON Example (Single filter):

{
  "position": 1,
  "state": "2"
}

Request JSON Example (Multiple filters):

[
  { "position": 1, "state": "2" },
  { "position": 2, "state": "2023" },
  { "position": 3, "state": "true" }
]
  • Expected response: HTTP 200 (OK)

GET /api/v1/source/{sourceId}/search

  • What it does: Search for manga in a single source
  • Expected request: Path parameter: sourceId (long), query params: searchTerm (string), pageNum (int, default: 1)
  • Expected response: JSON PagedMangaListDataClass object (HTTP 200)

POST /api/v1/source/{sourceId}/quick-search

  • What it does: Quick search manga in a source using filters
  • Expected request: Path parameter: sourceId (long), query param: pageNum (int, default: 1), body: FilterData object

Request JSON Example:

{
  "searchTerm": "One Piece",
  "filter": [
    { "position": 1, "state": "0" },
    { "position": 2, "state": "" }
  ]
}
  • Expected response: JSON PagedMangaListDataClass object (HTTP 200)

Manga Endpoints

GET /api/v1/manga/{mangaId}

  • What it does: Get manga information
  • Expected request: Path parameter: mangaId (int), optional query param: onlineFetch (boolean)
  • Expected response: JSON MangaDataClass object (HTTP 200) or HTTP 404 (Not Found)

Response JSON Example:

{
  "id": 1,
  "sourceId": "1234567890",
  "url": "/manga/12345",
  "title": "One Piece",
  "thumbnailUrl": "https://example.com/cover.jpg",
  "thumbnailUrlLastFetched": 1699999999,
  "initialized": true,
  "artist": "Eiichiro Oda",
  "author": "Eiichiro Oda",
  "description": "Monkey D. Luffy sets off on an adventure...",
  "genre": ["Action", "Adventure", "Comedy", "Fantasy"],
  "status": "ONGOING",
  "inLibrary": true,
  "inLibraryAt": 1699999999,
  "source": {
    "id": "1234567890",
    "name": "MangaDex",
    "lang": "en",
    "iconUrl": "/source/icon/1234567890",
    "supportsLatest": true,
    "isConfigurable": true,
    "isNsfw": false,
    "displayName": "MangaDex",
    "baseUrl": "https://mangadex.org"
  },
  "meta": {},
  "realUrl": "https://mangadex.org/manga/12345",
  "lastFetchedAt": 1699999999,
  "chaptersLastFetchedAt": 1699999999,
  "updateStrategy": "ALWAYS_UPDATE",
  "freshData": false,
  "unreadCount": 100,
  "downloadCount": 0,
  "chapterCount": 1000,
  "lastReadAt": 1699999999,
  "lastChapterRead": {
    "id": 100,
    "url": "/chapter/12345/1",
    "name": "Chapter 1: Dawn of Adventure",
    "uploadDate": 1699999999,
    "chapterNumber": 1.0,
    "scanlator": "MangaDex",
    "mangaId": 1,
    "read": true,
    "bookmarked": false,
    "lastPageRead": 20,
    "lastReadAt": 1699999999,
    "index": 1,
    "fetchedAt": 1699999999,
    "realUrl": "https://mangadex.org/chapter/12345/1",
    "downloaded": true,
    "pageCount": 20,
    "chapterCount": 1000,
    "meta": {}
  },
  "age": 0,
  "chaptersAge": 0,
  "trackers": [
    {
      "trackerId": 1,
      "trackerName": "MyAnimeList",
      "remoteId": "12345",
      "remoteUrl": "https://myanimelist.net/manga/12345",
      "title": "One Piece",
      "lastChapterRead": 100,
      "totalChapters": 1000,
      "score": 9.5,
      "status": "Reading",
      "startedReadingDate": null,
      "finishedReadingDate": null,
      "private": false
    }
  ]
}

GET /api/v1/manga/{mangaId}/full

  • What it does: Get full manga information with all data filled in
  • Expected request: Path parameter: mangaId (int), optional query param: onlineFetch (boolean)
  • Expected response: JSON MangaDataClass object (HTTP 200) or HTTP 404 (Not Found)

GET /api/v1/manga/{mangaId}/thumbnail

  • What it does: Get manga thumbnail image
  • Expected request: Path parameter: mangaId (int)
  • Expected response: Image file (JPEG/PNG) with HTTP 200 or HTTP 404 (Not Found)

GET /api/v1/manga/{mangaId}/category

  • What it does: Get categories assigned to a manga
  • Expected request: Path parameter: mangaId (int)
  • Expected response: JSON array of CategoryDataClass objects (HTTP 200)

Response JSON Example:

[
  {
    "id": 1,
    "order": 0,
    "name": "Favorites",
    "default": false,
    "size": 10,
    "includeInUpdate": "INCLUDE",
    "includeInDownload": "INCLUDE",
    "meta": {}
  }
]

GET /api/v1/manga/{mangaId}/category/{categoryId}

  • What it does: Add manga to a category
  • Expected request: Path parameters: mangaId (int), categoryId (int)
  • Expected response: HTTP 200 (OK)

DELETE /api/v1/manga/{mangaId}/category/{categoryId}

  • What it does: Remove manga from a category
  • Expected request: Path parameters: mangaId (int), categoryId (int)
  • Expected response: HTTP 200 (OK)

GET /api/v1/manga/{mangaId}/library

  • What it does: Add manga to library
  • Expected request: Path parameter: mangaId (int)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

DELETE /api/v1/manga/{mangaId}/library

  • What it does: Remove manga from library
  • Expected request: Path parameter: mangaId (int)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

PATCH /api/v1/manga/{mangaId}/meta

  • What it does: Add/update metadata to a manga
  • Expected request: Path parameter: mangaId (int), form params: key (string), value (string)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

GET /api/v1/manga/{mangaId}/chapters

  • What it does: Get manga chapter list
  • Expected request: Path parameter: mangaId (int), optional query param: onlineFetch (boolean)
  • Expected response: JSON array of ChapterDataClass objects (HTTP 200) or HTTP 404 (Not Found)

Response JSON Example:

[
  {
    "id": 100,
    "url": "/chapter/12345/1000",
    "name": "Chapter 1000: The Final Battle",
    "uploadDate": 1699999999,
    "chapterNumber": 1000.0,
    "scanlator": "MangaDex",
    "mangaId": 1,
    "read": false,
    "bookmarked": false,
    "lastPageRead": 0,
    "lastReadAt": 0,
    "index": 1000,
    "fetchedAt": 1699999999,
    "realUrl": "https://mangadex.org/chapter/12345/1000",
    "downloaded": false,
    "pageCount": 18,
    "chapterCount": 1000,
    "meta": {}
  },
  {
    "id": 99,
    "url": "/chapter/12345/999",
    "name": "Chapter 999: The Beginning",
    "uploadDate": 1699999998,
    "chapterNumber": 999.0,
    "scanlator": "MangaDex",
    "mangaId": 1,
    "read": true,
    "bookmarked": true,
    "lastPageRead": 15,
    "lastReadAt": 1699999999,
    "index": 999,
    "fetchedAt": 1699999998,
    "realUrl": "https://mangadex.org/chapter/12345/999",
    "downloaded": true,
    "pageCount": 15,
    "chapterCount": 1000,
    "meta": {}
  }
]

POST /api/v1/manga/{mangaId}/chapter/batch

  • What it does: Batch update chapters (mark as read, bookmark, etc.)
  • Expected request: Path parameter: mangaId (int), body: MangaChapterBatchEditInput object

Request JSON Example (Mark as read and bookmark):

{
  "chapterIds": [100, 101, 102],
  "chapterIndexes": null,
  "change": {
    "isRead": true,
    "isBookmarked": true,
    "lastPageRead": null,
    "delete": null
  }
}

Request JSON Example (Mark previous as read):

{
  "chapterIds": [100],
  "chapterIndexes": null,
  "change": {
    "isRead": null,
    "isBookmarked": null,
    "lastPageRead": null,
    "delete": null,
    "markPrevRead": true
  }
}

Request JSON Example (Delete downloaded chapters):

{
  "chapterIds": [100, 101],
  "change": {
    "isRead": null,
    "isBookmarked": null,
    "lastPageRead": null,
    "delete": true
  }
}
  • Expected response: HTTP 200 (OK)

GET /api/v1/manga/{mangaId}/chapter/{chapterIndex}

  • What it does: Get a specific chapter with pages
  • Expected request: Path parameters: mangaId (int), chapterIndex (int)
  • Expected response: JSON ChapterDataClass object (HTTP 200) or HTTP 404 (Not Found)

PATCH /api/v1/manga/{mangaId}/chapter/{chapterIndex}

  • What it does: Modify chapter (read status, bookmark, etc.)
  • Expected request: Path parameters: mangaId (int), chapterIndex (int), form params: read (boolean, optional), bookmarked (boolean, optional), markPrevRead (boolean, optional), lastPageRead (int, optional)

Form Data Example:

read=true
bookmarked=false
lastPageRead=5
markPrevRead=true
  • Expected response: HTTP 200 (OK)

PUT /api/v1/manga/{mangaId}/chapter/{chapterIndex}

  • What it does: Modify chapter (same as PATCH)
  • Expected request: Same as PATCH
  • Expected response: HTTP 200 (OK)

DELETE /api/v1/manga/{mangaId}/chapter/{chapterIndex}

  • What it does: Delete downloaded chapter files
  • Expected request: Path parameters: mangaId (int), chapterIndex (int)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

PATCH /api/v1/manga/{mangaId}/chapter/{chapterIndex}/meta

  • What it does: Add metadata to a chapter
  • Expected request: Path parameters: mangaId (int), chapterIndex (int), form params: key (string), value (string)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

GET /api/v1/manga/{mangaId}/chapter/{chapterIndex}/page/{index}

  • What it does: Get a chapter page image
  • Expected request: Path parameters: mangaId (int), chapterIndex (int), index (int), optional query params: updateProgress (boolean), format (string), opds (boolean)
  • Expected response: Image file with HTTP 200 or HTTP 404 (Not Found)

Chapter Endpoints

POST /api/v1/chapter/batch

  • What it does: Batch update chapters across any manga
  • Expected request: Body: ChapterBatchEditInput object

Request JSON Example:

{
  "chapterIds": [100, 101, 102, 200, 201],
  "change": {
    "isRead": true,
    "isBookmarked": false,
    "lastPageRead": null,
    "delete": null
  }
}
  • Expected response: HTTP 200 (OK)

GET /api/v1/chapter/{chapterId}/download

  • What it does: Download chapter as CBZ file
  • Expected request: Path parameter: chapterId (int), optional query param: markAsRead (boolean)
  • Expected response: CBZ file stream with HTTP 200 or HTTP 404 (Not Found)

Response Headers:

Content-Type: application/vnd.comicbook+zip
Content-Disposition: attachment; filename="One Piece - Chapter 1000.cbz"
Content-Length: 1234567

HEAD /api/v1/chapter/{chapterId}/download

  • What it does: Get CBZ file metadata (HEAD request)
  • Expected request: Path parameter: chapterId (int)
  • Expected response: HTTP headers with file info, or HTTP 404 (Not Found)

Category Endpoints

GET /api/v1/category

  • What it does: Get list of all categories
  • Expected request: No parameters required
  • Expected response: JSON array of CategoryDataClass objects (HTTP 200)

Response JSON Example:

[
  {
    "id": 1,
    "order": 0,
    "name": "Favorites",
    "default": false,
    "size": 10,
    "includeInUpdate": "INCLUDE",
    "includeInDownload": "INCLUDE",
    "meta": {}
  },
  {
    "id": 2,
    "order": 1,
    "name": "Reading",
    "default": false,
    "size": 5,
    "includeInUpdate": "INCLUDE",
    "includeInDownload": "EXCLUDE",
    "meta": {}
  },
  {
    "id": 3,
    "order": 2,
    "name": "Default",
    "default": true,
    "size": 100,
    "includeInUpdate": "INCLUDE",
    "includeInDownload": "INCLUDE",
    "meta": {}
  }
]

POST /api/v1/category

  • What it does: Create a new category
  • Expected request: Form param: name (string)

Form Data Example:

name=My Category
  • Expected response: HTTP 200 (OK) or HTTP 400 (Bad Request)

PATCH /api/v1/category/reorder

  • What it does: Reorder categories
  • Expected request: Form params: from (int), to (int)

Form Data Example:

from=0
to=2
  • Expected response: HTTP 200 (OK)

GET /api/v1/category/{categoryId}

  • What it does: Get manga in a category
  • Expected request: Path parameter: categoryId (int)
  • Expected response: JSON array of MangaDataClass objects (HTTP 200)

PATCH /api/v1/category/{categoryId}

  • What it does: Modify a category
  • Expected request: Path parameter: categoryId (int), optional form params: name (string), default (boolean), includeInUpdate (int), includeInDownload (int)

Form Data Example:

name=Updated Name
default=false
includeInUpdate=1
includeInDownload=0
  • Expected response: HTTP 200 (OK)

DELETE /api/v1/category/{categoryId}

  • What it does: Delete a category
  • Expected request: Path parameter: categoryId (int)
  • Expected response: HTTP 200 (OK)

PATCH /api/v1/category/{categoryId}/meta

  • What it does: Add metadata to a category
  • Expected request: Path parameter: categoryId (int), form params: key (string), value (string)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

Backup Endpoints

POST /api/v1/backup/import

  • What it does: Restore a backup from request body
  • Expected request: Body: Tachiyomi protobuf backup data (binary)
  • Expected response: HTTP 200 (OK)

POST /api/v1/backup/import/file

  • What it does: Restore a backup from file upload
  • Expected request: Multipart form data with file named "backup.proto.gz"
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

POST /api/v1/backup/validate

  • What it does: Validate a backup from request body
  • Expected request: Body: Tachiyomi protobuf backup data (binary)
  • Expected response: JSON ValidationResult object (HTTP 200)

Response JSON Example:

{
  "missingSources": ["com.source.example"],
  "missingTrackers": ["myanimelist"],
  "isValid": false
}

POST /api/v1/backup/validate/file

  • What it does: Validate a backup from file upload
  • Expected request: Multipart form data with file named "backup.proto.gz"
  • Expected response: JSON ValidationResult object (HTTP 200)

GET /api/v1/backup/export

  • What it does: Create a backup (returns as body)
  • Expected request: No parameters required
  • Expected response: Binary stream (protobuf) with HTTP 200

Response Headers:

Content-Type: application/octet-stream

GET /api/v1/backup/export/file

  • What it does: Create a backup (returns as file download)
  • Expected request: No parameters required
  • Expected response: Binary stream (protobuf) as file download with HTTP 200

Response Headers:

Content-Type: application/octet-stream
Content-Disposition: attachment; filename="suwayomi_backup_20240101.proto.gz"

Download Endpoints

GET /api/v1/downloads/start

  • What it does: Start the downloader
  • Expected request: No parameters required
  • Expected response: HTTP 200 (OK)

GET /api/v1/downloads/stop

  • What it does: Stop the downloader
  • Expected request: No parameters required
  • Expected response: HTTP 200 (OK)

GET /api/v1/downloads/clear

  • What it does: Clear the download queue
  • Expected request: No parameters required
  • Expected response: HTTP 200 (OK)

GET /api/v1/download/{mangaId}/chapter/{chapterIndex}

  • What it does: Queue a chapter for download
  • Expected request: Path parameters: mangaId (int), chapterIndex (int)
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

DELETE /api/v1/download/{mangaId}/chapter/{chapterIndex}

  • What it does: Remove a chapter from download queue
  • Expected request: Path parameters: mangaId (int), chapterIndex (int)
  • Expected response: HTTP 200 (OK)

PATCH /api/v1/download/{mangaId}/chapter/{chapterIndex}/reorder/{to}

  • What it does: Reorder a chapter in download queue
  • Expected request: Path parameters: mangaId (int), chapterIndex (int), to (int)
  • Expected response: HTTP 200 (OK)

POST /api/v1/download/batch

  • What it does: Queue multiple chapters for download
  • Expected request: Body: EnqueueInput object

Request JSON Example:

{
  "chapterIds": [100, 101, 102, 103, 104]
}
  • Expected response: HTTP 200 (OK)

DELETE /api/v1/download/batch

  • What it does: Remove multiple chapters from download queue
  • Expected request: Body: EnqueueInput object

Request JSON Example:

{
  "chapterIds": [100, 101, 102]
}
  • Expected response: HTTP 200 (OK)

Update Endpoints

GET /api/v1/update/recentChapters/{pageNum}

  • What it does: Get recently updated chapters
  • Expected request: Path parameter: pageNum (int)
  • Expected response: JSON PagedMangaChapterListDataClass object (HTTP 200)

Response JSON Example:

{
  "mangaList": [
    {
      "id": 1,
      "mangaId": 1,
      "mangaTitle": "One Piece",
      "mangaThumbnail": "https://example.com/cover.jpg",
      "chapters": [
        {
          "id": 100,
          "url": "/chapter/1/100",
          "name": "Chapter 100",
          "uploadDate": 1699999999,
          "chapterNumber": 100.0,
          "scanlator": "MangaDex",
          "read": false,
          "bookmarked": false,
          "lastPageRead": 0,
          "lastReadAt": 0,
          "index": 100,
          "fetchedAt": 1699999999,
          "downloaded": false
        }
      ]
    }
  ],
  "hasNextPage": true
}

POST /api/v1/update/fetch

  • What it does: Start library update (optionally for specific category)
  • Expected request: Optional form param: categoryId (int)

Form Data Examples:

(Updates entire library)

or

categoryId=1
  • Expected response: HTTP 200 (OK) or HTTP 400 (Bad Request)

POST /api/v1/update/reset

  • What it does: Stop and reset the updater
  • Expected request: No parameters required
  • Expected response: HTTP 200 (OK)

GET /api/v1/update/summary

  • What it does: Get updater status summary
  • Expected request: No parameters required
  • Expected response: JSON UpdateStatus object (HTTP 200)

Response JSON Example:

{
  "status": "Running",
  "progress": {
    "current": 5,
    "total": 100
  },
  "pending": 0,
  "running": true,
  "mangaDone": 5,
  "mangaTotal": 100,
  "chapterDone": 50,
  "chapterAdded": 10
}

Track Endpoints

GET /api/v1/track/list

  • What it does: List all supported trackers
  • Expected request: No parameters required
  • Expected response: JSON array of TrackerDataClass objects (HTTP 200)

Response JSON Example:

[
  {
    "id": 1,
    "name": "MyAnimeList",
    "icon": "/track/thumbnail/1",
    "isLogin": false,
    "authUrl": "https://myanimelist.net/api/v2/oauth/authorize"
  },
  {
    "id": 2,
    "name": "AniList",
    "icon": "/track/thumbnail/2",
    "isLogin": true,
    "authUrl": "https://anilist.co/api/v2/oauth/authorize"
  }
]

POST /api/v1/track/login

  • What it does: Login to a tracker
  • Expected request: Body: LoginInput object

Request JSON Example:

{
  "trackerId": 1,
  "callbackUrl": "suwayomi://auth/myanimelist",
  "username": "myuser",
  "password": "mypassword"
}
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

POST /api/v1/track/logout

  • What it does: Logout from a tracker
  • Expected request: Body: LogoutInput object

Request JSON Example:

{
  "trackerId": 1
}
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

POST /api/v1/track/search

  • What it does: Search for manga on a tracker
  • Expected request: Body: SearchInput object

Request JSON Example:

{
  "trackerId": 1,
  "title": "One Piece"
}
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

Response JSON Example:

[
  {
    "trackerId": 1,
    "remoteId": "12345",
    "remoteUrl": "https://myanimelist.net/manga/12345",
    "title": "One Piece",
    "coverUrl": "https://example.com/cover.jpg",
    "summary": "A story about pirates...",
    "match": 95
  }
]

POST /api/v1/track/bind

  • What it does: Bind a manga to a track record
  • Expected request: Query params: mangaId (int), trackerId (int), remoteId (string), private (boolean)

Request URL Example:

/api/v1/track/bind?mangaId=1&trackerId=1&remoteId=12345&private=false
  • Expected response: HTTP 200 (OK)

POST /api/v1/track/update

  • What it does: Update track record with tracker
  • Expected request: Body: UpdateInput object

Request JSON Example (Update reading progress):

{
  "recordId": 1,
  "status": 1,
  "lastChapterRead": 100,
  "scoreString": "9.5",
  "startDate": null,
  "finishDate": null,
  "private": false
}

Request JSON Example (Unbind from tracker):

{
  "recordId": 1,
  "unbind": true
}

Status values:

  • 1 = Reading

  • 2 = Completed

  • 3 = On Hold

  • 4 = Dropped

  • 6 = Plan to Read

  • Expected response: HTTP 200 (OK)

GET /api/v1/track/{trackerId}/thumbnail

  • What it does: Get tracker thumbnail image
  • Expected request: Path parameter: trackerId (int)
  • Expected response: Image file with HTTP 200 or HTTP 404 (Not Found)

Global Meta Endpoints

GET /api/v1/meta

  • What it does: Get all global metadata
  • Expected request: No parameters required
  • Expected response: HTTP 200 (OK) with JSON key-value pairs

Response JSON Example:

{
  "customKey": "customValue",
  "lastSync": "1234567890"
}

PATCH /api/v1/meta

  • What it does: Add/update global metadata
  • Expected request: Form params: key (string), value (string)

Form Data Example:

key=lastSync
value=1234567890
  • Expected response: HTTP 200 (OK) or HTTP 404 (Not Found)

Settings Endpoints

GET /api/v1/settings/about

  • What it does: Get application information
  • Expected request: No parameters required
  • Expected response: JSON AboutDataClass object (HTTP 200)

Response JSON Example:

{
  "name": "Suwayomi-Server",
  "version": "0.7.0",
  "revision": "7a1b2c3",
  "buildType": "release",
  "buildTime": 1704067200,
  "github": "https://github.com/Suwayomi/Suwayomi-Server",
  "discord": "https://discord.gg/Suwayomi"
}

GET /api/v1/settings/check-update

  • What it does: Check for application updates
  • Expected request: No parameters required
  • Expected response: JSON array of UpdateDataClass objects (HTTP 200)

Response JSON Example:

[
  {
    "name": "0.8.0",
    "tagName": "v0.8.0",
    "body": "## Bug fixes\n- Fixed bug #123\n- Improved performance",
    "htmlUrl": "https://github.com/Suwayomi/Suwayomi-Server/releases/tag/v0.8.0",
    "prerelease": false
  }
]

WebView Endpoints

GET /api/v1/webview

  • What it does: Open webview interface
  • Expected request: Optional query param: lang (string)

Request URL Example:

/api/v1/webview?lang=en
  • Expected response: HTML page (HTTP 200)

WebSocket Endpoints

The server provides WebSocket connections for real-time communication and updates.

Note: Actions like starting/stopping downloads or updates are done via HTTP endpoints (GET /api/v1/downloads/start, GET /api/v1/downloads/stop, POST /api/v1/update/fetch, etc.), not through WebSocket messages. WebSocket connections are primarily for receiving real-time status updates.


WS /api/v1/downloads

  • What it does: Real-time download queue status updates
  • Expected request: WebSocket connection with authentication

Messages You Can Send to Server:

Request current download status:

STATUS
  • Expected Response from Server:
{
  "status": "Started",
  "queue": [
    {
      "mangaId": 1,
      "chapterId": 100,
      "chapterIndex": 100,
      "mangaTitle": "One Piece",
      "chapterTitle": "Chapter 100",
      "state": "DOWNLOADING",
      "progress": 50,
      "tries": 0,
      "downloadSpeed": 1024000,
      "errorMessage": null
    }
  ]
}

State values: Queued, Downloading, Completed, Error

Invalid command response:

Invalid command.
Supported commands are:
    - STATUS
       sends the current download status

Messages Received from Server (Automatic Updates):

The server automatically sends status updates when:

  • A download starts/completes/fails
  • Queue changes (add/remove/reorder)

Example update:

{
  "status": "Started",
  "queue": [
    {
      "mangaId": 1,
      "chapterId": 100,
      "chapterIndex": 100,
      "mangaTitle": "One Piece",
      "chapterTitle": "Chapter 100",
      "state": "Completed",
      "progress": 100,
      "tries": 0,
      "downloadSpeed": 0,
      "errorMessage": null
    }
  ],
  "downloads": [
    {
      "downloadQueueItem": {
        "mangaId": 1,
        "chapterId": 101,
        "chapterIndex": 101,
        "mangaTitle": "One Piece",
        "chapterTitle": "Chapter 101",
        "state": "Downloading",
        "progress": 25,
        "tries": 0
      },
      "downloadSpeed": 1024000
    }
  ]
}

WS /api/v1/update

  • What it does: Real-time library update progress
  • Expected request: WebSocket connection with authentication

Messages You Can Send to Server:

Request current update status:

STATUS
  • Expected Response from Server:
{
  "status": "Running",
  "pending": 0,
  "running": true,
  "mangaDone": 5,
  "mangaTotal": 100,
  "chapterDone": 50,
  "chapterAdded": 10,
  "progress": {
    "current": 5,
    "total": 100
  },
  "errors": []
}

Status values: Idle, Running, Completed, Stopped

Invalid command response:

Invalid command.
Supported commands are:
    - STATUS
       sends the current update status

Messages Received from Server (Automatic Updates):

The server automatically sends status updates during library updates.

Example update:

{
  "status": "Running",
  "pending": 95,
  "running": true,
  "mangaDone": 5,
  "mangaTotal": 100,
  "chapterDone": 50,
  "chapterAdded": 10,
  "progress": {
    "current": 5,
    "total": 100
  },
  "errors": []
}

WS /api/v1/webview

  • What it does: Real-time webview communication for embedded browser functionality
  • Expected request: WebSocket connection with authentication

Messages You Can Send to Server:

Load a URL in the webview:

{
  "type": "loadUrl",
  "url": "https://example.com",
  "width": 1920,
  "height": 1080
}
  • Expected Response: None (webview loads the URL)

Resize the webview:

{
  "type": "resize",
  "width": 800,
  "height": 600
}
  • Expected Response: None

Send a JavaScript event:

{
  "type": "event",
  "eventType": "click",
  "clickX": 100.5,
  "clickY": 200.75,
  "button": 0,
  "ctrlKey": false,
  "shiftKey": false,
  "altKey": false,
  "metaKey": false
}
  • Expected Response: None (event is sent to the webview)

Keyboard event:

{
  "type": "event",
  "eventType": "keydown",
  "key": "Enter",
  "code": "Enter",
  "ctrlKey": true
}
  • Expected Response: None

Scroll event:

{
  "type": "event",
  "eventType": "wheel",
  "deltaY": -100,
  "clientX": 500,
  "clientY": 500
}
  • Expected Response: None

Paste text to webview:

{
  "type": "paste",
  "data": "pasted text content"
}
  • Expected Response: None

Copy from webview:

{
  "type": "copy"
}
  • Expected Response: None

Ping to check connection:

{
  "type": "ping"
}
  • Expected Response from Server:
{
  "type": "pong"
}

Messages Received from Server:

The server sends various responses based on webview interactions:

Pong response:

{
  "type": "pong"
}

JavaScript console output (example):

{
  "type": "console",
  "level": "log",
  "message": "Page loaded successfully"
}

Page load events:

{
  "type": "loadStart",
  "url": "https://example.com"
}
{
  "type": "loadFinish",
  "url": "https://example.com",
  "httpStatusCode": 200
}

Error events:

{
  "type": "error",
  "description": "Failed to load resource",
  "url": "https://example.com/broken-link"
}

GraphQL Endpoint

Base URL: http://localhost:4567/api/graphql

The server also provides a GraphQL API for more flexible queries and subscriptions. See the GraphQL schema for available queries, mutations, and subscriptions.


OPDS Endpoints

The OPDS API provides catalog feeds for integration with OPDS-compatible readers.

Base URL: http://localhost:4567/api/opds/v1.2/

GET /api/opds/v1.2/opds/v1.2

  • What it does: OPDS Catalog Root Feed (Navigation)
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

Response XML Example:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:opds="http://opds-spec.org/2010/catalog">
  <title>Suwayomi</title>
  <link rel="start" href="/api/opds/v1.2/opds/v1.2" type="application/atom+xml"/>
  <link rel="self" href="/api/opds/v1.2/opds/v1.2" type="application/atom+xml"/>
  <entry>
    <title>Library</title>
    <link href="/api/opds/v1.2/library/series" type="application/atom+xml;profile=opds-catalog"/>
    <content type="text">Your manga library</content>
  </entry>
  <entry>
    <title>Explore</title>
    <link href="/api/opds/v1.2/sources" type="application/atom+xml;profile=opds-catalog"/>
    <content type="text">Browse sources</content>
  </entry>
</feed>

GET /api/opds/v1.2/search

  • What it does: OPDS Search Description Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/explore

  • What it does: Explore Sources Navigation Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/history

  • What it does: Reading History Acquisition Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library-updates

  • What it does: Library Updates Acquisition Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/series

  • What it does: All Series in Library / Search Results Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/sources

  • What it does: Library Sources Navigation Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/source/{sourceId}

  • What it does: Library Source-Specific Series Acquisition Feed
  • Expected request: Path parameter: sourceId (long)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/categories

  • What it does: Library Categories Navigation Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/genres

  • What it does: Library Genres Navigation Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/statuses

  • What it does: Library Status Navigation Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/library/languages

  • What it does: Library Content Languages Navigation Feed
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/sources

  • What it does: All Sources Navigation Feed (Explore)
  • Expected request: No parameters required
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/source/{sourceId}

  • What it does: Source-Specific Series Acquisition Feed (Explore)
  • Expected request: Path parameter: sourceId (long)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/series/{seriesId}/chapters

  • What it does: Series Chapters Acquisition Feed
  • Expected request: Path parameter: seriesId (int)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/series/{seriesId}/chapter/{chapterIndex}/metadata

  • What it does: Chapter Metadata Acquisition Feed
  • Expected request: Path parameters: seriesId (int), chapterIndex (int)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/category/{categoryId}

  • What it does: Category-Specific Series Acquisition Feed
  • Expected request: Path parameter: categoryId (int)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/genre/{genre}

  • What it does: Genre-Specific Series Acquisition Feed
  • Expected request: Path parameter: genre (string)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/status/{statusId}

  • What it does: Status-Specific Series Acquisition Feed
  • Expected request: Path parameter: statusId (int)
  • Expected response: XML OPDS feed (HTTP 200)

GET /api/opds/v1.2/language/{langCode}

  • What it does: Language-Specific Series Acquisition Feed
  • Expected request: Path parameter: langCode (string)
  • Expected response: XML OPDS feed (HTTP 200)

Notes

  • The server runs on port 4567 by default
  • All JSON responses use UTF-8 encoding
  • File uploads use multipart/form-data format
  • WebSocket endpoints provide real-time updates for downloads, updates, and webview
  • WebSocket messages are JSON formatted (except STATUS command which is plain text)
  • Image responses include caching headers with 1-day max-age for thumbnails and pages
  • OPDS feeds use Atom XML format for catalog navigation and acquisition
  • Actions like start/stop for downloads and updates are done via HTTP endpoints, not WebSocket
  • WebSocket endpoints only support "STATUS" command to query current status
  • See Authentication section for details on how to authenticate with the API