# Uploading a chapter

# In A Nutshell

To upload a chapter, you need to:

  1. Start an upload session
  2. Upload files to the session (the chapter's pages)
  3. Commit the session

Once your session is committed, it is sent to a processing queue:

  1. An automated process picks up the images you sent us, checks/processes them if necessary, and saves them in our image archive
  2. The chapter is then published on the site

Note: Uploaded chapters will be held in a manual review queue for staff validation if it is your first upload.

# Requirements and limitations

You must have an account, and it must be in good standing (ie not restricted due to past offences). All the upload-related endpoints require authentication.

The following limitations then apply:

  • 1 active upload session per account
    • You need to either commit or abandon your current upload session before starting a new one
  • Max 10 files per one PUT request
  • Max 20MB per file
  • Max 500 files per upload session
  • Max 150MB per upload session
  • File format must be JPEG, PNG, or GIF
  • File resolution must be below 10'000 pixels in both width and height
    • If uploading long-strip content, that means you will probably need to split your images before uploading; our reader will transparently display them as if it was a single image
    • This is to avoid massive performance issues for users on lower-end devices when they try to load one 800x130'000 monster 90MB image...

# Detailed example

Remember that you need to be logged in for any upload operation to succeed.

An upload session is based on:

  • A manga entity you are uploading to
  • Zero or more scanlation group entities which are to be credited for the chapter

In this example, we will be using:

Note: This serves as an example. You can not (and should not) upload with the group "Unknown". In general

  • DO NOT upload content on MangaDex if you don't know its provenance
  • If you still try, your upload will be rejected and your account restricted or banned. See our rules.

# Verify that you don't have an active upload session already

Because only one upload session is allowed per user, we check if we have any open upload sessions.

GET /upload

You should get an HTTP 404 response (error detail will be "No upload session found") to note that no active upload sessions were found for the current user.

{
  "errors": [
    {
      ...
      "detail": "No upload session found"
    }
  ]
}

# Create an upload session

The next step is to begin a new upload session.

POST /upload/begin
{
  "manga": "f9c33607-9180-4ba6-b85c-e4b5faee7192",
  "groups": [
    "145f9110-0a6c-4b71-8737-6acb1a3c5da4"
  ]
}

On success, you will receive an HTTP 200 OK response back, with content similar to this:

{
  "result": "ok",
  "data": {
    "id": "113b7724-dcc2-4fbc-968f-9d775fcb1cd6",
    "type": "upload_session",
    "attributes": {
      "isCommitted": false,
      "isProcessed": false,
      "isDeleted": false
    },
    "relationships": [
      {
        "id": "41ce3e1a-8325-45b5-af8e-06aaf648a0df",
        "type": "user"
      },
      {
        "id": "f9c33607-9180-4ba6-b85c-e4b5faee7192",
        "type": "manga"
      },
      {
        "id": "145f9110-0a6c-4b71-8737-6acb1a3c5da4",
        "type": "scanlation_group"
      }
    ]
  }
}

The id in data.id is the id of your upload session, referred to as uploadSessionId from here on out.

Note: The is no fixed time limit between beginning and committing your session. However we expire old uncommitted sessions regularly, so if you wait a long time (say, more than 24 hours) to commit your upload session, you might have to start it from the beginning.

# Upload files to your upload session

Now that you have an uploadSessionId, you can upload images to your session.

Only the JPEG, PNG, and GIF formats are allowed. Archives like ZIP, CBZ, RAR, etc will be rejected. You must extract those on your side beforehand and submit individual image files to us.

Note 1: .JPEG and .JPG file extensions refer to the same exact image format (JPEG). Usage of .JPG is an historical artifact due to MS-DOS using only 3 letters for file extensions decades ago.

Note 2: Newer file formats that are backwards compatible with those (JPEG-XT, APNG, etc) may or may not be accepted. They aren't officially supported however, and we may start rejecting them without prior notice. This is generally based on whether or not they cause issues with our tooling or break for end-users on older devices/browsers.

Note 3: There's no point asking us about AV1, WEBM, JPEG-XL, etc. We are aware of them, but are limited by tooling quality and end-user device/browser compatibility. And at the moment that means none of these is usable.

For each file, send a POST request to the session endpoint with the image's data. Note that this is a multipart file endpoint. You cannot directly upload your image's bytes there.

POST /upload/{uploadSessionId}

In our experience the form-data layout seems to be the most compatible. That is Content-Type: multipart/form-data; boundary=boundary for example. However, your mileage might vary depending on your programming language and libraries. Join our discord and ask for advice in #dev-talk-api if you need help.

You can upload multiple files in a single request (currently limited to 10). The response body may be successful overall (response.result == "ok") and also contain errors if only some of the files failed validation. It's up to you to handle partial failures if you choose to upload multiple images per requests. Successful file uploads for the request are listed in the response's data array with type upload_session_file.

{
  "result": "ok",
  "errors": [],
  "data": [
    {
      "id": "12cc211a-c3c3-4f64-8493-f26f9b98c6f6",
      "type": "upload_session_file",
      "attributes": {
        "originalFileName": "testimage1.png",
        "fileHash": "bbf9b9548ee4605c388acb09e8ca83f625e5ff8e241f315eab5291ebd8049c6f",
        "fileSize": 18920,
        "mimeType": "image/png",
        "version": 1
      }
    },
    ...
  ]
}

The original file name is returned here only to allow you to handle retries. MangaDex automatically discards user-side filenames on success for security reason.

The original mime type (file format) is resolved by us from the raw bytes in your file. There's no point renaming your WEBM (or whatever else that's not allowed) file with a .JPG extension to try and sneak it through as we entirely ignore the user-side extension, once again for security reasons.

There is no necessity to upload files in batch unless you're trying to bulk-backfill hundreds of chapters and have a very good internet connection. In the vast majority of cases, 1-by-1 uploads will work just fine and be easier to correctly program on your end.

Keep the data[*].id file attribute of your images, as you will need it later. We'll refer to these as uploadSessionFileId hereafter.

If you change your mind and want to remove a previously uploaded image, you can do so with a DELETE /upload/{uploadSessionId}/{uploadSessionFileId}, and will receive a response like so on success:

{
  "response": "ok"
}

Note: It is not necessary to delete files yourself, as you will be required to explicitly mention the ones you want to use when committing your session. It can however be useful if your session exceeds the total session size limit due to mistakes (too many retries, a bug in your code, ...).

# Commit your upload session

Finally, once all the pages you need at uploaded to the uploaded session, you can commit it.

At this point, you submit the metadata and selected ordered pages for the chapter, like so:

POST /upload/{uploadSessionId}/commit
{
  "chapterDraft": {
    "volume": "1",
    "chapter": "2.5",
    "title": "The name of the chapter, if applicable",
    "translatedLanguage": "en"
  },
  "pageOrder": [
    "12cc211a-c3c3-4f64-8493-f26f9b98c6f6"
  ]
}

The order of the pages in the published chapters will be the order specified in the pageOrder array.

The order in which you uploaded files to the session is not tracked/used by MangaDex. Only pageOrder is used.

Any files you uploaded but did not specify in the pageOrder array will be deleted. We do not keep discarded session files after commit, and cannot provide them to you if you lost them.

An example response is:

{
  "result": "ok",
  "data": {
    "id": "14d4639b-5a8f-4f42-a277-b222412930ca",
    "type": "chapter",
    "attributes": {
      "volume": "1",
      "chapter": "2.5",
      "title": "The name of the chapter, if applicable",
      "translatedLanguage": "en",
      "publishAt": null,
      "createdAt": "2021-06-16T00:40:22+00:00",
      "updatedAt": "2021-06-16T00:40:22+00:00",
      "version": 1
    },
    "relationships": [
      {
        "id": "145f9110-0a6c-4b71-8737-6acb1a3c5da4",
        "type": "scanlation_group"
      },
      {
        "id": "f9c33607-9180-4ba6-b85c-e4b5faee7192",
        "type": "manga"
      },
      {
        "id": "41ce3e1a-8325-45b5-af8e-06aaf648a0df",
        "type": "user"
      }
    ]
  }
}

You just uploaded a chapter. Congratz!

Its URL will be https://mangadex.org/chapter/${data.id} once it is published.

The first time you upload a chapter (per language), it is automatically put into a queue for manual review by staff. Until it is reviewed and approved, it will be held back and not appear on the website nor be found in the list and search endpoints. This review usually takes a few hours, but may occasionally take up to 48 hours. If it takes longer, contact a staff member to inquire about why it was rejected.

Subsequent uploads should be auto-approved hereafter. They are still however subject to image processing before publication on the site, and this usually takes anywhere between 1 and 5 minutes.

# Editing the pages of a published chapter

To edit the pages of a chapter use the endpoint begin-edit-session after finding the current chapter version's version attribute.

POST /upload/begin/{chapterId}

This will generate an "edit" session, which is the same as an upload session, but comes pre-filled with the page files of the chapter's current version.

You can then then upload to it and commit it like you would an upload session.

This allows you to select the pages to add, keep, remove, and the order they should have in the end.