#
JSON API
This is the main API for nekoBT, and is used for most requests.
The base URL for the JSON API is https://nekobt.to/api/v1
#
Authorization
Most endpoints require authorization using an API key.
To authorize your requests, use the ssid cookie with your API key as the value.
If authorization isn't present or is invalid, you will receive a 401 Unauthorized JSON response.
{
"error": true,
"message": "Unauthorized."
}
#
Schema Validation
When sending data to the API, nekoBT validates the data against a schema.
If the data is invalid, you will receive a 400 Bad Request JSON response with details about the validation errors.
{
"error": true,
"message": "Data provided was invalid: must have required property 'query'.",
"validate_errors": [
{
"instancePath": "",
"schemaPath": "#/required",
"keyword": "required",
"params": {
"missingProperty": "query"
},
"message": "must have required property 'query'"
}
]
}
{
"error": true,
"message": "Data provided was invalid: 'limit' must be <= 100.",
"validate_errors": [
{
"instancePath": "/limit",
"schemaPath": "#/properties/limit/maximum",
"keyword": "maximum",
"params": {
"comparison": "<=",
"limit": 100
},
"message": "must be <= 100"
}
]
}
{
"error": true,
"message": "Data provided was invalid: 'offset' must be >= 0.",
"validate_errors": [
{
"instancePath": "/offset",
"schemaPath": "#/properties/offset/minimum",
"keyword": "minimum",
"params": {
"comparison": ">=",
"limit": 0
},
"message": "must be >= 0"
}
]
}
{
"error": true,
"message": "Data provided was invalid: 'offset' must be integer.",
"validate_errors": [
{
"instancePath": "/offset",
"schemaPath": "#/properties/offset/type",
"keyword": "type",
"params": {
"type": "integer"
},
"message": "must be integer"
}
]
}
#
Rate Limiting
nekoBT enforces rate limits to prevent abuse of the API. These limits are not publicly shared.
#
API Rate Limits
API Rate Limits are enforced by nekoBT to prevent abuse of the API.
If you exceed these limits, you will receive a 429 Too Many Requests JSON response.
Use the retry_after JSON field to determine how long to wait before making another request.
{
"error": true,
"message": "Rate limit exceeded, try again in 12 seconds.",
"retry_after": 11.82
}
#
Cloudflare Rate Limits
Cloudflare Rate Limits are enforced at the edge by Cloudflare to prevent abuse of the site.
If you exceed these limits, you will receive a 429 Too Many Requests HTML response.
Use the Retry-After header to determine how long to wait before making another request.
HTTP/2 429
retry-after: 4
date: ***
content-type: text/html; charset=UTF-8
x-frame-options: SAMEORIGIN
referrer-policy: same-origin
#
Endpoints
#
Get Announcements
GET
/announcements
Auth Optional
Returns the latest announcements displayed on the home page from nekoBT.
{
"error": false,
"data": [
{
"start_time": "1763856000000",
"end_time": "1767225600000",
"message": "Welcome! This site is in open-beta, so expect issues and changes.",
"link": "",
"new_tab": false,
"color": "grey", // info, success, warning, error, primary, grey
"dismissible": true
}
]
}
{
"error": true,
"message": "Internal Error"
}
#
Get Group
GET
/groups/<group_id>
Auth Optional
Returns information about a specific group, including its name, description, members, and other metadata.
{
"error": false,
"data": {
"id": "1234567890",
"name": "example",
"display_name": "Example",
"tag": "example",
"display_tag": "Example",
"pfp_hash": null,
"tagline": "Example fansub group",
"description": "This is an example fansub group.",
"anonymous": 0,
"members": [
{
"id": "1234567890",
"username": "exampleuser",
"invite": false,
"invite_key": null, // Only present if user is group leader/admin
"display_name": "ExampleUser",
"pfp_hash": "abcdef1234567890abcdef1234567890abcdef12",
"leader": true,
"admin": false,
"regular": true,
"torrent_count": 0
}
],
"relations": {
"parents": [],
"children": [
{
"id": "1234567890",
"name": "example2",
"display_name": "Example2",
"tag": "example2",
"display_tag": "Example2",
"pfp_hash": null,
"tagline": "",
"anonymous": 0,
"active": true, // Whether the link has been approved by both groups
"initiator": false // Whether the child group was the one to initiate the link
}
]
},
"media": [
{
"episodes": [ // List of episode IDs the group/child groups have worked on for this media
"1234"
],
"torrents": [ // List of torrent IDs the group/child groups have uploaded for this media
"1234567890"
],
"groups": [ // List of group IDs (including child groups) that have worked on this media
"1234567890"
],
"media": {
"id": "m1",
"title": "Example Movie",
"banner_url": "https://image.tmdb.org/t/p/original/....jpg",
"episodes": [ // Use this list to get episode details for the episodes worked on by this group
{
"id": 1234,
"season": 1,
"episode": 1,
"absolute": 1,
"tvdbId": 1234567,
"title": "Example Episode Title"
},
]
}
}
],
"can_edit": false,
"can_leave": false,
"can_delete": null, // Only present if user is group leader
"stats": {
"uploads": 50,
"hidden_uploads": 5, // Only present if user is group leader
"tags": 28,
"seeders": "261",
"leechers": "2",
"downloads": "4518"
}
}
}
{
"error": true,
"message": "Group not found."
}
#
Search Groups
GET
/groups/search
Auth Optional
Searches for groups based on their name.
#
italics = default, ? = optional
{
"error": false,
"data": {
"results": [
{
"id": "1234567890",
"anonymous": 0,
"description": "",
"display_name": "Example Group",
"name": "example-group",
"tag": "example-group",
"display_tag": "Example Group",
"pfp_hash": "abcdefghijklmnopqrstuvwxyz123456",
"tagline": "An example group tagline.",
"member_count": "5",
"torrent_count": "2",
"download_count": "53"
}
],
"more": true // Whether there are more results to fetch with pagination
}
}
{
"error": true,
"message": "Internal Error"
}
#
Create Group Link
POST
/groups/<group_id_1>/links/<group_id_2>
Auth Required
Creates a link between two groups. If the authorized user is the leader of both groups, the link is automatically approved. Otherwise, the link will be pending approval from the other group's leader.
group_id_1 should be the group ID that the user is leader of, and group_id_2 should be the other group ID.
#
italics = default, ? = optional
{
"error": false
}
{
"error": true,
"message": "Link is waiting for other group to approve."
}
#
Delete Group Link
DELETE
/groups/<group_id>/links/<group_id_2>
Auth Required
Deletes a link between two groups.
group_id_1 should be the group ID that the user is leader of, and group_id_2 should be the other group ID.
{
"error": false
}
{
"error": true,
"message": "Unauthorized."
}
#
Add Group Member(s)
POST
/groups/<group_id>/members
Auth Required
Creates invites for one or more users to join a group.
Data should be formatted as a JSON Array of Objects with the following fields:
#
italics = default, ? = optional
{
"error": false,
"data": [
{
"id": "1234567890",
"invite_key": "abcdef1234567890abcdef1234567890",
}
]
}
{
"error": true,
"message": "Display name (\"Example\") already taken."
}
#
Update Group Member
PATCH
/groups/<group_id>/members/<user_or_invite_id>
Auth Required
Updates a member in a group.
#
At least one is required, italics = default, ? = optional
{
"error": false
}
{
"error": true,
"message": "Forbidden."
}
#
Remove Group Member
DELETE
/groups/<group_id>/members/<user_or_invite_id>
Auth Required
Removes a member from a group.
This endpoint has a destructive query parameter.
To delete an invited member, destructive=true must be used.
The differences are as follows:
#
italics = default, ? = optional
{
"error": false
}
{
"error": true,
"message": "Cannot soft delete an invite. Use ?destructive=true to delete an invite."
}
#
Get Invite
GET
/invites/<invite_id>
Auth Optional
Returns information about an invited user, including the group it belongs to.
Use ?key= to reveal who the recipient is.
{
"error": false,
"data": {
"id": "1234567890",
"display_name": "Example Invite",
"author": {
"id": "1234567890",
"username": "example",
"pfp_hash": "abcdef1234567890abcdef1234567890abcdef12",
"display_name": "Example"
},
"used": false,
"recipient": { // Only present if ?key= is used, and the key is valid, otherwise null
"id": "1234567890",
"display_name": "ExampleUser",
"pfp_hash": null,
"username": "exampleuser"
},
"group": {
"id": "1234567890",
"display_name": "Example",
"name": "example",
"tag": "example-subs",
"display_tag": "Example-subs",
"pfp_hash": "abcdef1234567890abcdef1234567890abcdef12",
"anonymous": 0,
"description": "blah blah blah",
"tagline": "An example group tagline."
},
"torrent_count": "18"
}
}
{
"error": true,
"message": "Invite not found."
}
#
Accept Invite
POST
/invites/<invite_id>/accept/<invite_key>
Auth Required
Accepts an invite to a group using the provided invite ID and key.
{
"error": false
}
{
"error": true,
"message": "You are already in this group."
}
#
Get Languages
GET
/langs
Auth Optional
Returns the list of supported languages for audio, subtitles, and fansubs.
{
"error": false,
"data": {
"langs": {
"ja": {
"code": "ja",
"name": "Japanese",
"flag": "https://flagcdn.com/40x30/jp.png"
},
"en": {
"code": "en",
"name": "English",
"flag": "https://flagcdn.com/40x30/gb.png"
},
"enm": {
"code": "enm",
"name": "English (Weeb)",
"flag": "/assets/img/flags/enm.png"
}
// ...
},
"convert": {
"jp": "ja",
"eng": "en",
"en-jp": "enm",
"spa-419": "es-419",
"es": "es-es",
"pt": "pt-pt",
"fr": "fr-fr",
"tg": "fil",
"nb": "no",
"nn": "no"
}
}
}
{
"error": true,
"message": "Internal Error"
}
#
Get Media
GET
/media/<media_id>
Auth Optional
Returns information about a specific media item, including its title, description, and other metadata.
Use ?force=true to get the media, even if there are no torrents for it.
{
"error": false,
"data": {
"title": "Dusk Beyond the End of the World",
"year": 2025,
"genres": [
"Animation",
"Anime",
"Romance",
"Science Fiction"
],
"overview": "When tensions around...",
"status": "continuing",
"banner_url": "https://artworks.thetvdb.com/banners/v4/series/465214/posters/685e663785276.jpg",
"runtime": 24,
"tvdbId": 465214,
"tmdbId": 294867,
"imdbId": "tt37532634",
"alternate_titles": [
"Towa no Yuugure",
"Towa no Yugure"
],
"notes": null,
"episodes": [
{
"id": 48690,
"title": "Think Morning, Count Two",
"season": 0,
"episode": 1,
"overview": "Akira and Towasa's friendship...",
"runtime": 24,
"airDateUtc": "2025-09-25T15:30:00Z",
"tvdbId": 11307751
}
],
"groups": [
{
"id": "1234567890",
"name": "example",
"display_name": "Example",
"tag": "example",
"display_tag": "Example",
"tagline": "Example fansub group",
"pfp_hash": null,
"episodes": { // Episodes worked on by this group
"48690": {
"level": 1, // Highest sub level for this episode by this group
"video_type": 9,
"mtl": false
}
},
"max_level": 1, // Highest sub level for this media by this group
"langs": {
"fsub": [
"en"
],
"sub": []
}
}
]
}
}
{
"error": true,
"message": "No torrents found for this media."
}
#
Search Media
GET
/media/search
Auth Optional
Searches for media items based on search query.
#
italics = default, ? = optional
{
"error": false,
"data": {
"more": true,
"results": [
{
"id": "s1234",
"title": "Aria",
"year": 2005,
"genres": [
"Animation",
"Anime",
"Comedy",
"Drama",
"Fantasy",
"Science Fiction"
],
"overview": "On the planet Aqua lies the watery...",
"status": "ended",
"banner_url": "https://artworks.thetvdb.com/banners/posters/79839-3.jpg",
"runtime": 25,
"tvdbId": 79839,
"tmdbId": 53787,
"imdbId": "tt0977907",
"alternate_titles": [
"Aria the Natural",
"Aria the Origination"
],
"similarity": 0.25
}
]
}
}
{
"error": true,
"message": "Internal Error"
}
#
Get Site Statistics
GET
/stats
Auth Optional
Returns various statistics about the site, such as the number of users, torrents, and groups.
{
"error": false,
"data": {
"created_at": "1764203045818",
"top_media_1w": [ // Top media by seeders in the past week, max 10
{
"id": "s1539",
"title": "Dusk Beyond the End of the World",
"banner_url": "https://artworks.thetvdb.com/banners/v4/series/465214/posters/685e663785276.jpg",
"seeders": 155
}
],
"users": {
"total": 405,
"new_1w": 254,
"active_1m": 331
},
"groups": {
"total": 177,
"new_1w": 77,
"active_1m": 47
},
"torrents": {
"total": 578,
"new_1d": 48,
"total_downloads": 36500
},
"peers": {
"seeders": 2683,
"leechers": 31
}
},
"message": "Cache hit, returning stats."
}
{
"error": true,
"message": "Timed out whilst fetching stats."
}
#
Get Torrent
GET
/torrents/<torrent_id>
Auth Optional
Returns information about a specific torrent, including its title, description, and other metadata.
{
"error": false,
"data": {
"id": "1234567890",
"title": "Torrent Title",
"auto_title": "Torrent Title {Tags:L1;V9;C1;A-ja;F-en;}",
"description": "...", // Markdown formatted description, can be null
"mediainfo": "...", // Can be null
"category": 1,
"deleted": null,
"hidden": false,
"otl": false,
"hardsub": false,
"level": 1,
"mtl": false,
"filesize": "242587117",
"media_id": "s1234",
"media_episode_ids": [
"48665"
],
"audio_lang": "ja", // All languages are comma separated lists
"sub_lang": "",
"fsub_lang": "en",
"video_codec": 1,
"video_type": 9,
"files": [
{
"path": "[SubsPlus+] Hero Without a Class - Who Even Needs Skills - S01E10 (ADN WEB-DL 1080p AVC AAC) [FAC10B8C].mkv",
"name": "[SubsPlus+] Hero Without a Class - Who Even Needs Skills - S01E10 (ADN WEB-DL 1080p AVC AAC) [FAC10B8C].mkv",
"length": 592387117,
"offset": 0
}
],
"magnet": "magnet:?xt=urn:btih:bd2fb09...",
"private_magnet": "magnet:?xt=urn:btih:bd2fb09...",
"infohash": "bd2fb09...",
"anonymous": false,
"uploader": { // Can be null on anonymous uploads
"id": "1234567890",
"username": "example",
"display_name": "Example",
"pfp_hash": null
},
"groups": [
{
"id": "1234567890",
"name": "example group",
"display_name": "Example Group",
"pfp_hash": null,
"tagline": "An example group tagline.",
"members": [
{
"id": "1234567890",
"invite": false,
"username": "exampleuser",
"display_name": "ExampleUser",
"pfp_hash": null,
"role": "Typesetting",
"weight": 1 // Order of members, smallest first
}
],
"uploading_group": true,
"role": null
}
],
"imported": null, // If imported from Nyaa, the original Nyaa ID, otherwise null
"seeders": "52",
"leechers": "1",
"completed": "185",
"activity": "5557", // Estimated peer speeds in bytes/second
"upgraded": null, // Torrent ID of the new torrent, or null
"animetosho": [ // Can be null, array, or 'skipped', 'processing', 'not_found', 'error', 'no_media'
{
"file_id": 1234,
"filename": "....mkv",
"filesize": 937007977,
"subs": [
{
"id": 5678,
"codec": "SRT",
"lang": "jpn",
"name": "SDH",
"default": false,
"enabled": true,
"forced": false,
"trackid": 4,
"tracknum": 5
}
],
"mediainfo": "General\nUniqu...",
"screenshot_id": "00000000", // You can use this ID and timings to reconstruct the screenshot URLs
"screenshot_timings": [
13980,
366330,
718680,
1069030,
1421380
]
}
],
"animetosho_fetch_time": "1767984097784", // Unix timestamp in milliseconds of when the AnimeTosho data was fetched, or null
"screenshots": [ // Array of screenshot URLs, can be empty. If AnimeTosho data is present, it is highly likely screenshots has data. Max 5 screenshots.
"https://storage.animetosho.org/sframes/00000000_13980.png",
"https://storage.animetosho.org/sframes/00000000_366330.png",
"https://storage.animetosho.org/sframes/00000000_718680.png",
"https://storage.animetosho.org/sframes/00000000_1069030.png",
"https://storage.animetosho.org/sframes/00000000_1421380.png"
],
"can_edit": false,
"waiting_approve": false,
"disable_comments": false,
"lock_comments": false,
"disable_edits": false,
"nyaa_upload_time": null // If imported from Nyaa, the original upload time as a Unix timestamp in milliseconds, otherwise null
}
}
{
"error": true,
"message": "Torrent is waiting for approval."
}
#
Edit Torrent
PATCH
/torrents/<torrent_id>
Auth Required
Edit a specific torrent.
#
At least one is required, italics = default, ? = optional
{
"title": "Torrent Title",
"upgraded": null,
"description": "...",
"mediainfo": "...",
"video_type": 9,
"video_codec": 1,
"audio_lang": "ja",
"sub_lang": "",
"fsub_lang": "en",
"anonymous": false,
"hidden": false,
"primary_group": {
"id": "1234567890",
"members": [
{
"id": "1234567890", // Can be null for new members
"display_name": "ExampleUser", // Only used for new members
"role": "Typesetting",
"pfp_hash": null
}
]
},
"secondary_groups": [],
"media_episodes": [
48665
],
"mtl": false,
"otl": false,
"hardsub": false
}
{
"error": false
}
{
"error": true,
"message": "Can't edit torrent due to parsing failures.",
"fails": [
"You have set sub level to \"no subs\", but you have added fansub languages."
],
"warns": []
}
#
Get Torrent's AnimeTosho Data
GET
/torrents/<torrent_id>/animetosho
Auth Optional
Returns the AnimeTosho data for a specific torrent. You should handle for long request times on this endpoint. If data is not yet available, the request may take up to 60 seconds to complete while the site fetches all data from AnimeTosho.
AnimeTosho data is not fetched automatically for torrents. A client must request it using this endpoint before the site will fetch it from AnimeTosho. The site's frontend will automatically call this endpoint when viewing a torrent that does not have final AnimeTosho data yet.
If another user is already fetching the data for this torrent, your request will be halted until the other user's fetch is complete, to prevent multiple simultaneous fetches for the same torrent.
Even if the request is cancelled by the client, the site will continue fetching the data in the background.
200 if data was already present, 201 if the data was just fetched.
{
"error": false,
"data": [
{
"file_id": 1234,
"filename": "....mkv",
"filesize": 937007977,
"subs": [
{
"id": 5678,
"codec": "SRT",
"lang": "jpn",
"name": "SDH",
"default": false,
"enabled": true,
"forced": false,
"trackid": 4,
"tracknum": 5
}
],
"mediainfo": "General\nUniqu...",
"screenshot_id": "00000000", // You can use this ID and timings to reconstruct the screenshot URLs
"screenshot_timings": [
13980,
366330,
718680,
1069030,
1421380
]
}
],
"retry": false
}
The server sent a request to AnimeTosho, received a processing status, and is still waiting for the data to be ready.
{
"error": false,
"message": "Torrent is still being processed on AnimeTosho.",
"retry": true
}
{
"error": true,
"message": "Torrent was skipped on AnimeTosho.",
"retry": false
}
#
Get Torrent Comments
GET
/torrents/<torrent_id>/comments
Auth Optional
Returns comments for a specific torrent.
{
"error": false,
"data": [
{
"id": "1234567890",
"deleted": false,
"user_id": "1234567890",
"text": "this is a comment",
"replying_to": null,
"display_name": "Example",
"pfp_hash": "abcdef1234567890abcdef1234567890abcdef12",
"positive": "0",
"negative": "0",
"pinned": false,
"user_rating": null, // The authenticated user's rating for this comment, true (liked), false (disliked), or null (no rating)
"last_edit": null,
"children": [
{
"id": "4567890123",
"deleted": false,
"user_id": "1234567890",
"text": "@Example and this is a reply",
"replying_to": "1234567890",
"display_name": "Example2",
"pfp_hash": null,
"positive": "0",
"negative": "0",
"pinned": false,
"user_rating": null,
"last_edit": 1764031668355 // Unix timestamp in milliseconds, or null
},
{
"id": "6789012345",
"deleted": true, // Deleted comments replace user_id, text, and display_name
"user_id": "0",
"text": "[deleted]",
"replying_to": "1234567890",
"display_name": "[deleted]",
"pfp_hash": null,
"positive": "0",
"negative": "0",
"pinned": false,
"user_rating": null,
"last_edit": null
}
]
}
]
}
{
"error": true,
"message": "Torrent not found."
}
#
Get Torrent File
GET
/torrents/<torrent_id>/download
Auth Optional
Returns the torrent file for a specific torrent.
When authenticated, the returned torrent file will be a private torrent with the user's passkey included in the announce URL.
You can specify ?public=true to get the torrent file without your torrent key.
This endpoint returns the raw torrent file data with a application/x-bittorrent content type.
#
Bulk Download Torrents
GET
/torrents/bulk/download
Auth Optional
PATCH
/torrents/bulk/download
Auth Optional
Download a group of .torrent files as a ZIP archive. Maximum 500 torrents per request.
You can either use a GET request with query parameters, or a PATCH request with a JSON body.
The PATCH method is recommended for larger requests, as the GET method may hit URL length limits.
When authenticated, the returned torrent files will be private torrents with the user's passkey included in the announce URL.
You can specify public=true to get the torrent files without your torrent key.
#
italics = default, ? = optional
#
italics = default, ? = optional
{
"ids": [
"1234567890",
"0987654321"
],
"public": false
}
Will return a ZIP file containing the requested .torrent files.
{
"error": true,
"message": "No accessible torrents found."
}
#
Bulk Edit Torrents
PATCH
/torrents/bulk/edit
Auth Required
Edit a group of torrents. You must have permission to edit all specified torrents. Maximum 250 torrents per request.
This endpoint will return a bad_torrents field in the response if any of the specified torrents could not be edited.
#
At least one is required, italics = default, ? = optional
{
"ids": [
"1234567890",
"0987654321"
],
"title": [
{
"find": "x264",
"replace": "x265"
}
],
"upgraded": null,
"description": "...",
"video_type": 9,
"video_codec": 1,
"audio_lang": "ja",
"sub_lang": "",
"fsub_lang": "en",
"anonymous": false,
"hidden": false,
"primary_group": {
"id": "1234567890",
"members": [
{
"id": "1234567890", // Can be null for new members
"display_name": "ExampleUser", // Only used for new members
"role": "Typesetting",
"pfp_hash": null
}
]
},
"secondary_groups": [],
"mtl": false,
"otl": false,
"hardsub": false
}
{
"error": false
}
{
"error": true,
"message": "Can't edit torrent due to parsing failures.",
"fails": [
"You have set sub level to \"no subs\", but you have added fansub languages."
],
"bad_torrents": [
"0987654321"
],
"warns": []
}
#
Check Torrent(s) Permissions
PATCH
/torrents/bulk/edit/perms
Auth Required
Checks whether you have permission to edit the torrents provided. Maximum 250 torrents per request.
This endpoint will return a bad_torrents field in the response if any of the specified torrents can not be edited.
This request is done before attempting a bulk edit on the website. You don't have to call this endpoint before calling the bulk edit endpoint.
You will receive the same bad_torrents field in the bulk edit response.
#
italics = default, ? = optional
{
"error": false
}
{
"error": true,
"message": "You do not have permission to edit one or more torrents.",
"bad_torrents": [
"0987654321"
]
}
#
Search Torrents
GET
/torrents/search
Auth Optional
Searches for torrents, using various criteria.
The search API attempts to extract meaning from the query parameter (called "hints"). Some examples are:
- Searching
HEVC, it will automatically add the video codec filter for HEVC. - Searching
your lie in april, it will recommend the media "Your Lie in April", either inrecommended_mediaif >=70% of results match, or insimilar_mediaby title searching. - Searching
s01when amedia_idis provided, it will add season 1 to the episode filter.
#
italics = default, ? = optional
{
"error": false,
"data": {
"results": [
{
"id": "1234567890",
"title": "Torrent Title",
"infohash": "abdef...",
"magnet": "magnet:?xt=urn:btih:9a4e649...",
"private_magnet": null, // Only present if authenticated
"media_id": "s123",
"description": "...", // Can be null
"filesize": "7738622751", // In bytes
"category": 1,
"level": 4,
"otl": true,
"hardsub": false,
"mtl": false,
"comment_count": "0",
"deleted": null,
"hidden": false,
"waiting_approve": false,
"auto_title": "Torrent Title {Tags:OTL;L4;V13;C1;A-ja;F-en;}",
"audio_lang": "ja", // Comma-separated list of languages
"sub_lang": "",
"fsub_lang": "en",
"video_codec": 1,
"video_type": 13,
"anonymous": false,
"upgraded": null,
"uploader": {
"id": "1234567890",
"display_name": "Example",
"username": "example",
"pfp_hash": "abdef..."
},
"seeders": "0",
"leechers": "0",
"completed": "0",
"groups": [
{
"id": "1234567890",
"display_name": "Example Group",
"name": "example group",
"anonymous": 0,
"tagline": "An example group tagline.",
"pfp_hash": "abdef...",
"uploading_group": true // Primary = true, Secondary = false
}
],
"imported": 123456, // If imported from Nyaa, the original Nyaa Torrent ID, otherwise null
"user_is_seeding": null, // If the authenticated user is seeding this torrent, true/false/null
"user_is_leeching": null, // If the authenticated user is leeching this torrent, true/false/null
"user_download_count": null, // Number of times the authenticated user has downloaded this torrent, or null
"has_mediainfo": false,
"nyaa_upload_time": "1573878523000" // If imported from Nyaa, the original upload time as a Unix timestamp in milliseconds, otherwise null
}
],
"infohash_match": null, // If the query matched an infohash exactly, this field contains that torrent ID, otherwise null
"recommended_media": null, // If the search used a query, and >=70% of the results contain the same media ID, this field contains that media object, otherwise null
"media": null, // If the search used a media_id filter, this field contains that media object, otherwise null
"similar_media": null, // If the query was similar to a media title, this field contains a list of media objects, otherwise null
"debug": {
"summary": [], // Summary of applied filters extracted from the query
"debug": [
"no hints found",
"hiding hidden torrents",
"sorting by best (level desc)",
"found 50 torrents",
"found 67 group relations",
"found 35 groups",
"found 22 users"
]
},
"more": true, // Whether there are more results to fetch with pagination
"search": { // Returns search parameters actually used after getting hints
"limit": 50,
"offset": 0,
"sort_by": "best",
"category": 0,
"episode_match_any": false,
"group_primary": true,
"group_secondary": false,
"group_childs": true,
"group_parents": false,
"uploader_uploads": true,
"uploader_contributions": false
}
}
}
{
"error": true,
"message": "Internal Error"
}
#
Upload Torrent
POST
/upload
Auth Required
Uploads a new torrent to the site.
It's recommended you first perform
Primary Group Object:
id(string): Group IDmembers(array, max 50): Array of member objects with:id(string or null): User ID, Invite ID, or null for new invitesrole(string): Role namedisplay_name(string, max 32): Display name (used for new invites)
Secondary Group Object:
id(string): Group IDrole(string or null, max 64): Role name or null
#
italics = default, ? = optional
{
"torrent": "ZDg6YW5ub3VuY2....",
"title": "[ExampleGroup] Media Title - 01 [WEB 1080p x265][FLAC 2.0]",
"movie": false,
"category": "1",
"video_codec": 2,
"hidden": false,
"video_type": "7",
"level": "3",
"mtl": false,
"otl": false,
"hardsub": false,
"anonymous": false,
"primary_group": {
"id": "1234567890",
"members": [
{
"id": "1234567890",
"display_name": "", // Can be empty for existing members
"role": "Typesetting"
}
]
},
"secondary_groups": [
{
"id": "0987654321",
"role": "Encode"
}
],
"audio_langs": "jp",
"sub_langs": "",
"fansub_langs": "en",
"description": "Example description...",
"mediainfo": ""
}
{
"error": false,
"data": {
"id": "1234567890"
}
}
{
"error": true,
"message": "Can't upload torrent due to parsing warnings.",
"fails": [],
"warns": [
"You have not included our public tracker URL in your torrent. If you plan to upload this torrent to other sites, you should make sure you include it.",
"You have not added any audio languages, please make sure to include them if you have any audio tracks."
]
}
{
"error": true,
"message": "Can't upload torrent due to parsing failures.",
"fails": [
"Torrents must have at least one backup tracker."
],
"warns": [
"You have not included our public tracker URL in your torrent. If you plan to upload this torrent to other sites, you should make sure you include it.",
"You have not added any audio languages, please make sure to include them if you have any audio tracks."
]
}
#
Perform Upload Checks
PUT
/upload/checks
Auth Required
Performs various checks for a new torrent upload, such as verifying its parsability.
Primary Group Object:
id(string): Group IDtag(string): Group tagmembers(array, max 50): Array of member objects with:id(string or null): User ID, Invite ID, or null for new invitesrole(string): Role namedisplay_name(string, max 32): Display name (used for new invites)
#
italics = default, ? = optional
{
"title": "[ExampleGroup] Media Title - 01 [WEB 1080p x265][FLAC 2.0]",
"movie": false,
"video_type": null,
"video_codec": null,
"files": [
{
"name": "[ExampleGroup] Media Title - 01 [WEB 1080p x265][FLAC 2.0].mkv",
}
],
"level": "",
"mtl": false,
"otl": false,
"hardsub": false,
"audio_langs": "",
"sub_langs": "",
"fansub_langs": "",
"announce_urls": [
"udp://tracker.opentrackr.org:1337/announce",
]
}
{
"error": false,
"data": {
"warns": [
"You have not included our public tracker URL in your torrent. If you plan to upload this torrent to other sites, you should make sure you include it.",
"You have not added any audio languages, please make sure to include them if you have any audio tracks."
],
"fails": [
"You need to set your Primary Group to the \"Release Group\" found in your title."
],
"parsedData": {
"media": {
"torrentTitle": "Media Title",
"releaseTokens": " [WEB 1080p x265][FLAC 2.0]",
"title": "Media Title",
"genres": [
"Action",
"Animation",
"Anime",
"Comedy",
"Fantasy",
"Romance"
],
"id": 1234
},
"episodes": [
{
"id": 1234567,
"title": "Episode Title",
"season": 1,
"episode": 1,
"absolute": 1
}
],
"quality": {
"id": 3,
"name": "WEBDL-1080p",
"source": "web",
"resolution": 1080,
"version": 1
},
"releaseGroup": "ExampleGroup"
},
"auto_title": "[ExampleGroup] Media Title - 01 [WEB 1080p x265][FLAC 2.0]",
"upgraded_torrents": []
}
}
{
"error": true,
"message": "Internal Error"
}
#
Perform Mediainfo Extraction
PUT
/upload/mediainfo
Auth Optional
Extracts metadata for a torrent using Mediainfo Text or JSON output.
When providing JSON output, you must provide the data as JSON, not a JSON string.
#
italics = default, ? = optional
{
"mediainfo": "General\nComplete name : example.mkv\nFormat : Matroska\nFile size : 1.46 GiB\nDuration : 24 min 0 s\nOverall bit rate : 8 738 kb/s\n..."
}
You can either provide the whole JSON object from Mediainfo, or just the media object.
{
"mediainfo": {
"track": [
{
"@type": "General",
"Complete_name": "example.mkv",
"Format": "Matroska",
"File_size": "1.46 GiB",
"Duration": "24 min 0 s",
"Overall_bit_rate": "8 738 kb/s"
}
// ...
]
}
}
{
"error": false,
"data": {
"video_codec": 2,
"fansub_langs": "",
"sub_langs": "en",
"audio_langs": "jp"
}
}
{
"error": true,
"message": "Failed to extract mediainfo text languages and codec."
}
#
Get User
GET
/users/<user_id|@me>
Auth Optional
For all endpoints starting with /users/, you can also use @me for <user_id> to refer to the currently authenticated user.
Returns information about a specific user, including their username, profile picture, and other metadata.
{
"error": false,
"data": {
"id": "1234567890",
"username": "example",
"display_name": "Example",
"pfp_hash": "abdef1234567890abcdef1234567890abcdef12",
"description": "Example user description.",
"permissions": 0, // Only present if authenticated as this user
"torrent_key": "...", // Only present if authenticated as this user
"torrent_count": 2,
"contribution_count": 1,
"groups": [
{
"id": "1234567890",
"name": "example group",
"display_name": "Example Group",
"tagline": "An example group tagline.",
"anonymous": 0,
"description": "Example group description.",
"pfp_hash": "abdef1234567890abcdef1234567890abcdef12",
"tag": "examplegroup",
"display_tag": "ExampleGroup",
"admin": false,
"leader": false,
"regular": false
}
],
"upload": "50043", // Total uploaded bytes
"download": "1945", // Total downloaded bytes
"seeding": "0", // Number of torrents currently seeding
"leeching": "0", // Number of torrents currently leeching
"disabled": false, // Whether the account is disabled
"nyaa": [
{
"username": "ExampleNyaa",
"public": true // Private links are only shown if authenticated as this user
}
],
"can_edit": false,
"has_mfa": null, // Whether the user has multi-factor authentication enabled, only shown if authenticated as this user
"can_download_recovery": null // Whether the user can still download their recovery key, only shown if authenticated as this user
}
}
{
"error": true,
"message": "Invalid user ID."
}
#
Edit User
PATCH
/users/<user_id|@me>
Auth Required
Perform edits on your account. This includes Nyaa links, profile picture, revoking API keys, and your description.
#
At least one is required, italics = default, ? = optional
{
"error": false,
"new_torrent_key": "abcdef..." // Only present if reset_torrent_key was true
}
{
"error": true,
"message": "Forbidden."
}
#
Get User Groups
GET
/users/<user_id|@me>/groups
Auth Optional
Returns the groups that a user is a member of.
{
"error": false,
"data": [
{
"id": "1234567890",
"name": "example",
"display_name": "Example",
"pfp_hash": "abdef...",
"tagline": "An example group tagline.",
"tag": "example",
"display_tag": "Example",
"description": "Example group description.",
"anonymous": 0,
"admin": false, // Whether the user is an admin of the group
"leader": false,
"regular": false,
"members": [
{
"id": "1234567890",
"invite": false,
"username": "example",
"display_name": "Example",
"pfp_hash": "abdef...",
"leader": false,
"admin": false,
"regular": false
}
],
"upload_count": 25
}
]
}
{
"error": true,
"message": "Invalid user ID."
}
#
Get User Notifications
GET
/users/<user_id|@me>/notifications
Auth Required
Returns notifications for a specific user.
There are several tags used in notifications:
{
"error": false,
"data": [
{
"id": "1234567890",
"data": "Welcome to the site.",
"seen": false
}
]
}
{
"error": true,
"message": "Forbidden."
}
#
Mark User Notifications as Read
PUT
/users/<user_id|@me>/notifications/read
Auth Required
Marks specified notifications as read. Returns the updated list of notifications.
#
italics = default, ? = optional
{
"error": false,
"data": [
{
"id": "1234567890",
"data": "Welcome to the site.",
"seen": false
}
]
}
{
"error": true,
"message": "Forbidden."
}
#
Get User Peers
GET
/users/<user_id|@me>/peers
Auth Required
Returns a list of torrents that the user is a peer of, including their upload and download statistics.
{
"error": false,
"data": [
{
"torrent_id": "1234567890",
"upload": "48492", // Total uploaded bytes
"download": "0", // Total downloaded bytes
"completed": "0", // Total downloads completed
"down_time": "0", // Seconds spent downloading
"up_time": "74859", // Seconds spent uploading
"created_at": "1764178764012", // First connection for this torrent, Unix timestamp in milliseconds
"updated_at": "1764253690054", // Last seen seeding/leeching, Unix timestamp in milliseconds
"last_completed": "0", // Last completed download time, Unix timestamp in milliseconds
"torrent_title": "[Example] Media Title - 01 [WEB 1080p x265][FLAC 2.0]",
"torrent_infohash": "abcdef...",
"torrent_filesize": "148129345", // In bytes
"peers": [
{
"torrent_id": "1234567890",
"peer_id": "-qb-69420-", // Peer ID from the torrent client
"upload": "63093967893", // Total uploaded bytes in this session
"download": "0", // Total downloaded bytes in this session
"left": "0", // Bytes left to download
"first_seen": "1764178764012", // Unix timestamp in milliseconds
"last_seen": "1764253690054", // Unix timestamp in milliseconds
"user_agent": "qBittorrent/69", // Peer user agent string
"est_upload_speed": 3911, // Estimated upload speed in bytes/second
"est_download_speed": 0,
"ip": "x.x.x.x", // IP address of the peer
"port": 58071 // Port of the peer
}
]
}
]
}
{
"error": true,
"message": "Forbidden."
}
#
Search Users
GET
/users/search
Auth Required
Searches for users based on their username.
To keep users who don't want to be known private, this endpoint only returns a user when the search query is an exact match of the username.
#
italics = default, ? = optional
{
"error": false,
"data": {
"more": false,
"results": [
{
"id": "1234567890",
"username": "example",
"display_name": "Example",
"pfp_hash": null
}
]
}
}
{
"error": true,
"message": "Unauthorized."
}