API documentation for jschan. Gitgud pages: http://fatchan.gitgud.site/jschan-docs/#introduction
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

2516 lines
86 KiB

---
title: API Reference
language_tabs: # must be one of https://git.io/vQNgJ
- shell
- go
toc_footers:
- <a href='https://gitgud.io/fatchan/jschan'>jschan source code</a>
- <a href='https://gitgud.io/fatchan/jschan-docs'>API docs source code</a>
- <a href='https://gitgud.io/fatchan/jschan-api-go'>Golang SDK</a>
- <a href='https://github.com/ussaohelcim/jschan-api-sdk'>TypeScript SDK</a>
includes:
- errors
search: true
code_clipboard: true
meta:
- name: description
content: Documentation for the jschan API
---
# Introduction
This is the API documentation for open source imageboard [jschan](https://gitgud.io/fatchan).
- [Golang SDK](https://gitgud.io/fatchan/jschan-api-go) (Official, work in progress)
- [TypeScript SDK](https://github.com/ussaohelcim/jschan-api-sdk), [Typings](https://github.com/ussaohelcim/jschan-api-types) (Unofficial)
---
In the data examples, arrays can contain more than one item however only one is included to reduce the size of this document.
In data parameters, note that data is always submitted as a strings, that is how urlencoded/multipart forms work. There is no concept of "types". "number" simply means a string only including numbers. For "boolean", any value with length > 0 = true, 0 length or missing = false.
# Public Endpoints
## Board list
```shell
curl "https://fatchan.org/boards.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getBoardsPublicOptions := &jschan.GetBoardsPublicOptions{
Search: "tech",
}
boards, err := client.GetBoardsPublic(ctx, getBoardsPublicOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", boards)
```
> The above command returns JSON structured like this:
```json
{
"boards": [
{
"_id": "61a45ea2c5f3b57f31789cfc",
"uri": "a",
"sequence_value": 709261,
"ips": 109,
"pph": 25,
"webring": true
"path": "https://smuglo.li/a",
"siteName": "Smug",
"lastPostTimestamp": {
"text": "12 minutes ago",
"color": "#14d900"
},
"settings": {
"sfw": false,
"name": "Anime & Manga",
"description": "Stay away from 3DPD"
},
"tags": [
"anime",
"manga"
]
},
{
"_id": "b",
"sequence_value": 320,
"ips": 4,
"pph": 0,
"ppd": 5,
"webring": false
"lastPostTimestamp": {
"text": "1 hour ago",
"color": "#72d900"
},
"settings": {
"name": "Random",
"description": "Anything and everything",
"sfw": false,
"unlistedLocal": false
},
"tags": [
"random",
"b",
"rand",
"anything",
"everything"
],
},
],
"page": 1,
"maxPage": 1
}
```
Returns a list of boards, max 30 per page. Unlisted boards are not included in search results. Also return the current page and maximum page with the current search and sites parameters.
### HTTP Request
`GET https://fatchan.org/boards.json`
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
search | | A string to search by board name and tags, including prefix matches.
sort | `popularity` | `popularity` sorts by a compound of (ips, pph, sequence_value), `activity` sorts by lastPostTimestamp.
direction | `desc` | `desc` or `asc` for descending or ascending sort order respectively.
local_first | `false` | If `true`, put local sites grouped before webring sites. Sort and direction for local and webring sites will be independent.
sites | | Sites to include by siteName, can be repeated to include multiple sites. Blank includes all sites.
page | | Page number. 30 per page. Blank is first page. Page numbering starts at 1. Included in all responses is `maxPage`.
## Overboard index
```shell
curl "https://fatchan.org/overboard.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
overboardOptions := &jschan.GetOverboardOptions{
IncludeDefault: true,
}
overboard, err := client.GetOverboardIndex(ctx, overboardOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", overboard.Threads)
```
> The above command returns JSON structured like this:
```json
{
"threads": [
{
"_id": "619b5c90de842499502c366c",
"date": "2021-11-22T09:02:08.852Z",
"u": 1637571728852,
"name": "Anon",
"country": null,
"board": "b",
"tripcode": null,
"capcode": null,
"subject": "My music",
"message": null,
"messagehash": null,
"nomarkup": null,
"thread": null,
"email": null,
"spoiler": false,
"banmessage": null,
"userId": null,
"files": [
{
"filename": "a631c506f8884d263a3cf79023399504d600b0ab3219b515ac1e658d746f5d38.mp4",
"spoiler": null,
"hash": "a631c506f8884d263a3cf79023399504d600b0ab3219b515ac1e658d746f5d38",
"originalFilename": "the matrixx - black moon.mp4",
"mimetype": "video/mp4",
"size": 17745211,
"extension": ".mp4",
"sizeString": "16.9MB",
"duration": 191.379,
"durationString": "03:11",
"thumbextension": ".jpg",
"geometry": {
"width": 640,
"height": 368,
"thumbwidth": 250,
"thumbheight": 143
},
"geometryString": "640x368",
"hasThumb": true
}
],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 3,
"replyfiles": 7,
"sticky": 0,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-29T03:54:32.232Z",
"postId": 309,
"replies": [
{
"_id": "619b832b009b4a926fb37f36",
"date": "2021-11-22T11:46:51.776Z",
"u": 1637581611776,
"name": "Anon",
"country": null,
"board": "b",
"tripcode": null,
"capcode": null,
"subject": null,
"message": "fuck dude those russians left as fast as they came",
"messagehash": "NNRY6z0VURq58lfsJ80CXqSHR/fvtokjVmFT2lE5IkM=",
"nomarkup": "fuck dude those russians left as fast as they came",
"thread": 309,
"email": null,
"spoiler": false,
"banmessage": null,
"userId": null,
"files": [
{
"filename": "421049b5beedb751c05be7f53f3a4bb781b8f03cd8fd6888293918deea9a9f64.jpg",
"spoiler": null,
"hash": "421049b5beedb751c05be7f53f3a4bb781b8f03cd8fd6888293918deea9a9f64",
"originalFilename": "cover.jpg",
"mimetype": "image/jpeg",
"size": 1214658,
"extension": ".jpg",
"sizeString": "1.2MB",
"thumbextension": ".jpg",
"geometry": {
"width": 1403,
"height": 1400,
"thumbwidth": 250,
"thumbheight": 249
},
"geometryString": "1403x1400",
"hasThumb": true
}
],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"postId": 310
}
]
}
]
}
```
Returns a list of threads with preview replies from multiple boards.
Similar to board index pages.
### HTTP Request
`GET https://fatchan.org/overboard.json`
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
include_default | `true` | Whether to include boards that are publicly listed and by default appear on the overboard. If not `true` and the add_boards parameter is empty, this will be ignored and default to true (otherwise you are asking for an overboard view of no boards).
add | | Additional boards to fetch threads from. Can be repeated for multiple boards.
rem | | Boards to remove from the default board list if include_detault is true. Can be repeated for multiple boards.
## Overboard catalog
```shell
curl "https://fatchan.org/catalog.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
overboardOptions := &jschan.GetOverboardOptions{
IncludeDefault: true,
}
overboard, err := client.GetOverboardCatalog(ctx, overboardOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", overboard.Threads)
```
> The above command returns JSON structured like this:
```json
{
"threads": [
{
"_id": "619b5c90de842499502c366c",
"date": "2021-11-22T09:02:08.852Z",
"u": 1637571728852,
"name": "Anon",
"country": null,
"board": "b",
"tripcode": null,
"capcode": null,
"subject": "My music",
"message": null,
"messagehash": null,
"nomarkup": null,
"thread": null,
"email": null,
"spoiler": false,
"banmessage": null,
"userId": null,
"files": [
{
"filename": "a631c506f8884d263a3cf79023399504d600b0ab3219b515ac1e658d746f5d38.mp4",
"spoiler": null,
"hash": "a631c506f8884d263a3cf79023399504d600b0ab3219b515ac1e658d746f5d38",
"originalFilename": "the matrixx - black moon.mp4",
"mimetype": "video/mp4",
"size": 17745211,
"extension": ".mp4",
"sizeString": "16.9MB",
"duration": 191.379,
"durationString": "03:11",
"thumbextension": ".jpg",
"geometry": {
"width": 640,
"height": 368,
"thumbwidth": 250,
"thumbheight": 143
},
"geometryString": "640x368",
"hasThumb": true
}
],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 3,
"replyfiles": 7,
"sticky": 0,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-29T03:54:32.232Z",
"postId": 309
},
{
"_id": "60aabfd6fc57a0112f5dbdc4",
"date": "2021-05-23T20:49:26.918Z",
"u": 1621802966918,
"name": "名無し",
"country": null,
"board": "lain",
"tripcode": null,
"capcode": null,
"subject": "lain Fanart thread",
"message": null,
"messagehash": null,
"nomarkup": null,
"thread": null,
"email": null,
"spoiler": false,
"banmessage": null,
"userId": null,
"files": [
{
"spoiler": null,
"hash": "10e24a1eef06d36d29a30f60e4616ef8cea9050c8f1e13b80af75b01687ef1fa",
"filename": "10e24a1eef06d36d29a30f60e4616ef8cea9050c8f1e13b80af75b01687ef1fa.jpg",
"originalFilename": "10e24a1eef06d36d29a30f60e4616ef8cea9050c8f1e13b80af75b01687ef1fa.jpg",
"mimetype": "image/jpeg",
"size": 259561,
"extension": ".jpg",
"sizeString": "253.5KB",
"thumbextension": ".jpg",
"geometry": {
"width": 1024,
"height": 768,
"thumbwidth": 250,
"thumbheight": 187
},
"geometryString": "1024x768",
"hasThumb": true
}
],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 42,
"replyfiles": 119,
"sticky": 0,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-28T18:57:37.215Z",
"postId": 362
}
]
}
```
Returns a list of threads without replies from multiple boards.
Similar to board catalog pages.
### HTTP Request
`GET https://fatchan.org/catalog.json`
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
include_default | `true` | Whether to include boards that are publicly listed and by default appear on the overboard. If not `true` and the add_boards parameter is empty, this will be ignored and default to true (otherwise you are asking for an overboard view of no boards).
add | | Additional boards to fetch threads from. Can be repeated for multiple boards.
rem | | Boards to remove from the default board list if include_detault is true. Can be repeated for multiple boards.
## Thread
```shell
curl "https://fatchan.org/t/thread/1329.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getThreadOptions := &jschan.GetThreadOptions{
Board: "t",
ThreadId: 1329,
}
thread, err := client.GetThread(ctx, getThreadOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", thread)
```
> The above command returns JSON structured like this:
```json
{
"_id": "614de00fdd671464b69b6fe0",
"date": "2021-09-24T14:26:23.861Z",
"u": 1632493583861,
"name": "Anon",
"country": {
"code": "TOR",
"name": "Tor Hidden Service"
},
"board": "t",
"tripcode": null,
"capcode": null,
"subject": "Login and Board Abandonment",
"message": "Tom,\r\nWhat are the criteria for a board becoming available for claim? My board hardly gets any traffic, so I do not often log in, but I still monitor it closely. Does this put it at risk of being given away or deleted? How often should one log in to maintain ownership of his board?\r\nThank you.",
"messagehash": "s5Jm+bRGPlsMb78ROCTwEg0H7fAAtAhBlhd+yvdwbhE=",
"nomarkup": "Tom,\r\nWhat are the criteria for a board becoming available for claim? My board hardly gets any traffic, so I do not often log in, but I still monitor it closely. Does this put it at risk of being given away or deleted? How often should one log in to maintain ownership of his board?\r\nThank you.",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "65fedc",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [
{
"_id": "614dfa85dd671464b69b6fe2",
"postId": 1330
}
],
"replyposts": 5,
"replyfiles": 0,
"sticky": 0,
"locked": 0,
"bumplocked": 1,
"cyclic": 0,
"bumped": "2021-10-03T22:52:13.202Z",
"postId": 1329,
"replies": [
{
"_id": "614dfa85dd671464b69b6fe2",
"date": "2021-09-24T16:19:17.465Z",
"u": 1632500357465,
"name": "Anon",
"country": {
"code": "AU",
"name": "Australia"
},
"board": "t",
"tripcode": null,
"capcode": "## Admin",
"subject": "",
"message": "<a class=\"quote\" href=\"/t/thread/1329.html#1329\">&gt;&gt;1329</a> <small>(OP)</small> \r\nThere is no regular claims process, but I was considering a cleanup soon. There will be a newspost and global announcement with reasonable notice before any account deletion or board forfeiture takes place. Logging into your account in that instance would be warranted, because I can see the last activity date and will delete inactive accounts.",
"messagehash": "jviA+n4rb3tYhSq2eonkuCZYzr/frpmwsDVv2N0XQUE=",
"nomarkup": ">>1329\r\nThere is no regular claims process, but I was considering a cleanup soon. There will be a newspost and global announcement with reasonable notice before any account deletion or board forfeiture takes place. Logging into your account in that instance would be warranted, because I can see the last activity date and will delete inactive accounts.",
"thread": 1329,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "b5d092",
"files": [],
"quotes": [
{
"_id": "614de00fdd671464b69b6fe0",
"thread": 1329,
"postId": 1329
}
],
"crossquotes": [],
"backlinks": [
{
"_id": "614fb22e448d10f67a8d4dff",
"postId": 1331
},
{
"_id": "61538bd4dd671464b69b7034",
"postId": 1339
},
{
"_id": "615a341db33d7abaa5f90bb5",
"postId": 1363
}
],
"postId": 1330
}
]
]
```
Returns a thread with all replies.
### HTTP Request
`GET https://fatchan.org/{board}/thread/{threadId}.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | The board URI for whatever board you want
threadId | The thread number, which is the post number of the OP.
## Board index pages
```shell
curl "https://fatchan.org/t/index.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getIndexOptions := &jschan.GetIndexOptions{
Board: "t",
Page: 1,
}
index, err := client.GetIndex(ctx, getIndexOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", index)
```
> The above command returns JSON structured like this:
```json
[
{
"_id": "6158e81eb33d7abaa5f90ba0",
"date": "2021-10-02T23:15:42.675Z",
"u": 1633216542675,
"name": "Anon",
"country": {
"code": "AU",
"name": "Australia"
},
"board": "t",
"tripcode": null,
"capcode": "## Admin",
"subject": "Important Links",
"message": "<span class=\"title\">Git repository &amp; issue tracker:</span> <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://gitgud.io/fatchan/jschan\">https://gitgud.io/fatchan/jschan</a>\nGo here to see the source code, report issues or ask relevant questions.\n\n<span class=\"title\">IRC:</span> <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://irc-web.fatpeople.lol\">https://irc-web.fatpeople.lol</a> (irc-web.fatpeople.lol port 6697 TLS on)\nJoin IRC to chat directly with staff and other users in a realtime format.\n\n<span class=\"title\">Test board:</span> <a class=\"quote\" href=\"/test/index.html\">&gt;&gt;&gt;/test/</a>\nTest things on the /test/ board rather than here or anywhere else.",
"messagehash": "tkak9s72dCSv9XkocVNwceUfmtwqaTH8gL9bzcQxwP4=",
"nomarkup": "==Git repository & issue tracker:== https://gitgud.io/fatchan/jschan\nGo here to see the source code, report issues or ask relevant questions.\n\n==IRC:== https://irc-web.fatpeople.lol (irc-web.fatpeople.lol port 6697 TLS on)\nJoin IRC to chat directly with staff and other users in a realtime format.\n\n==Test board:== >>>/test/\nTest things on the /test/ board rather than here or anywhere else.",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "307203",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 0,
"replyfiles": 0,
"sticky": 3,
"locked": 1,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-10-02T23:15:42.675Z",
"postId": 1360,
"edited": {
"username": "admin",
"date": "2021-11-03T00:36:36.620Z"
},
"replies": []
},
{
"_id": "614ba0e132f471fcdd2c7139",
"date": "2021-09-22T21:32:17.737Z",
"u": 1632346337737,
"name": "Anon",
"country": {
"code": "AU",
"name": "Australia"
},
"board": "t",
"tripcode": null,
"capcode": "## Admin",
"subject": "Board Requests",
"message": "1. <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"/rules.html\">Global rules</a>\r\n2. <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"/register.html\">Register an account</a> \r\n3. Post in this thread, format:\r\n<span class=\"code\">''Board URI:'' /example/\r\n''Board name:'' &lt;name of the board&gt;\r\n''Board description:'' &lt;25 words or less&gt;\r\n''I want it because:'' &lt;your pathetic excuse for wanting a board&gt;\r\n''My registered account username is:'' &lt;username&gt;\r\n''I have read and understand the global rules, and acknowledge the existence of the Israeli nuclear weapons program.''\r\n</span>\r\nEnjoy.",
"messagehash": "J3Sg5W1b7iXYZQAofK+HFHvrpr8IpjOKEOMZvnMWB5I=",
"nomarkup": "1. [Global rules](/rules.html)\r\n2. [Register an account](/register.html) \r\n3. Post in this thread, format:\r\n[code]plain\r\n''Board URI:'' /example/\r\n''Board name:'' <name of the board>\r\n''Board description:'' <25 words or less>\r\n''I want it because:'' <your pathetic excuse for wanting a board>\r\n''My registered account username is:'' <username>\r\n''I have read and understand the global rules, and acknowledge the existence of the Israeli nuclear weapons program.''\r\n[/code]\r\n\r\nEnjoy.",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "f63865",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 1,
"replyfiles": 0,
"sticky": 2,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-14T14:09:39.353Z",
"postId": 1325,
"edited": {
"username": "admin",
"date": "2021-10-05T13:18:26.680Z"
},
"replies": [
{
"_id": "619118a39ca8261cc8311609",
"date": "2021-11-14T14:09:39.353Z",
"u": 1636898979353,
"name": "Anon",
"country": {
"code": "LU",
"name": "Luxembourg"
},
"board": "t",
"tripcode": null,
"capcode": null,
"subject": "",
"message": "<span class=\"bold\">Board URI:</span> /shy/\r\n<span class=\"bold\">Board name:</span> Shy Anonymous\r\n<span class=\"bold\">Board description:</span> Доска для застенчивых одиноких людей без сети социальных связей (в том числе своего пола), друзей, тян, с отсутствующими навыками НЕФОРМАЛЬНОГО общения. Обсуждение связанных с этим проблем.\r\n<span class=\"bold\">I want it because:</span> Because I can and want\r\n<span class=\"bold\">My registered account username is:</span> anonymous1234\r\n<span class=\"bold\">I have read and understand the global rules, and acknowledge the existence of the Israeli nuclear weapons program.</span>",
"messagehash": "S3r9l9svoA/ebm4c7e9U1pOq6kW1WYsE1vc/9/BHZTg=",
"nomarkup": "''Board URI:'' /shy/\r\n''Board name:'' Shy Anonymous\r\n''Board description:'' Доска для застенчивых одиноких людей без сети социальных связей (в том числе своего пола), друзей, тян, с отсутствующими навыками НЕФОРМАЛЬНОГО общения. Обсуждение связанных с этим проблем.\r\n''I want it because:'' Because I can and want\r\n''My registered account username is:'' anonymous1234\r\n''I have read and understand the global rules, and acknowledge the existence of the Israeli nuclear weapons program.''",
"thread": 1325,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "c54e7d",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"postId": 1391
}
]
}
]
```
Returns a list of threads with preview replies from a page of a board.
### HTTP Request
`GET https://fatchan.org/{board}/{page}.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
page | `index` for page 1, or a number for subsequent pages.
## Board catalog
```shell
curl "https://fatchan.org/t/catalog.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getCatalogOptions := &jschan.GetCatalogOptions{
Board: "t",
}
catalog, err := client.GetCatalog(ctx, getCatalogOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", catalog)
```
> The above command returns JSON structured like this:
```json
[
{
"_id": "6158e81eb33d7abaa5f90ba0",
"date": "2021-10-02T23:15:42.675Z",
"u": 1633216542675,
"name": "Anon",
"country": {
"code": "AU",
"name": "Australia"
},
"board": "t",
"tripcode": null,
"capcode": "## Admin",
"subject": "Important Links",
"message": "<span class=\"title\">Git repository &amp; issue tracker:</span> <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://gitgud.io/fatchan/jschan\">https://gitgud.io/fatchan/jschan</a>\nGo here to see the source code, report issues or ask relevant questions.\n\n<span class=\"title\">IRC:</span> <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://irc-web.fatpeople.lol\">https://irc-web.fatpeople.lol</a> (irc-web.fatpeople.lol port 6697 TLS on)\nJoin IRC to chat directly with staff and other users in a realtime format.\n\n<span class=\"title\">Test board:</span> <a class=\"quote\" href=\"/test/index.html\">&gt;&gt;&gt;/test/</a>\nTest things on the /test/ board rather than here or anywhere else.",
"messagehash": "tkak9s72dCSv9XkocVNwceUfmtwqaTH8gL9bzcQxwP4=",
"nomarkup": "==Git repository & issue tracker:== https://gitgud.io/fatchan/jschan\nGo here to see the source code, report issues or ask relevant questions.\n\n==IRC:== https://irc-web.fatpeople.lol (irc-web.fatpeople.lol port 6697 TLS on)\nJoin IRC to chat directly with staff and other users in a realtime format.\n\n==Test board:== >>>/test/\nTest things on the /test/ board rather than here or anywhere else.",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "307203",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 0,
"replyfiles": 0,
"sticky": 3,
"locked": 1,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-10-02T23:15:42.675Z",
"postId": 1360,
"edited": {
"username": "admin",
"date": "2021-11-03T00:36:36.620Z"
}
},
{
"_id": "614ba0e132f471fcdd2c7139",
"date": "2021-09-22T21:32:17.737Z",
"u": 1632346337737,
"name": "Anon",
"country": {
"code": "AU",
"name": "Australia"
},
"board": "t",
"tripcode": null,
"capcode": "## Admin",
"subject": "Board Requests",
"message": "1. <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"/rules.html\">Global rules</a>\r\n2. <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"/register.html\">Register an account</a> \r\n3. Post in this thread, format:\r\n<span class=\"code\">''Board URI:'' /example/\r\n''Board name:'' &lt;name of the board&gt;\r\n''Board description:'' &lt;25 words or less&gt;\r\n''I want it because:'' &lt;your pathetic excuse for wanting a board&gt;\r\n''My registered account username is:'' &lt;username&gt;\r\n''I have read and understand the global rules, and acknowledge the existence of the Israeli nuclear weapons program.''\r\n</span>\r\nEnjoy.",
"messagehash": "J3Sg5W1b7iXYZQAofK+HFHvrpr8IpjOKEOMZvnMWB5I=",
"nomarkup": "1. [Global rules](/rules.html)\r\n2. [Register an account](/register.html) \r\n3. Post in this thread, format:\r\n[code]plain\r\n''Board URI:'' /example/\r\n''Board name:'' <name of the board>\r\n''Board description:'' <25 words or less>\r\n''I want it because:'' <your pathetic excuse for wanting a board>\r\n''My registered account username is:'' <username>\r\n''I have read and understand the global rules, and acknowledge the existence of the Israeli nuclear weapons program.''\r\n[/code]\r\n\r\nEnjoy.",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "f63865",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 1,
"replyfiles": 0,
"sticky": 2,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-14T14:09:39.353Z",
"postId": 1325,
"edited": {
"username": "admin",
"date": "2021-10-05T13:18:26.680Z"
}
}
]
```
Returns a list of all threads on a board.
### HTTP Request
`GET https://fatchan.org/{board}/catalog.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
## Board log list
```shell
curl "https://fatchan.org/t/logs.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getLogsListOptions := &jschan.GetLogsListOptions{
Board: "t",
}
logs, err := client.GetLogsList(ctx, getLogsListOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", logs)
```
> The above command returns JSON structured like this:
```json
[
{
"date": {
"year": 2022,
"month": 8,
"day": 13
},
"count": 3
},
{
"date": {
"year": 2022,
"month": 8,
"day": 12
},
"count": 1
}
]
```
Returns a list of objects each containing a date (day, month, year) and number of log entries on that date.
### HTTP Request
`GET https://fatchan.org/{board}/logs.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
## Board log (day)
```shell
curl "https://fatchan.org/t/logs/8-12-2022.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getLogsOptions := &jschan.GetLogsOptions{
Board: "t",
Date: models.LogDate{
Year: 2022,
Month: 12,
Day: 8,
}
}
logs, err := client.GetLogs(ctx, getLogsOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", logs)
```
> The above command returns JSON structured like this:
```json
[
{
"_id": "62f5f3d1b0ffeb3e12205fa2",
"showLinks": false,
"postLinks": [
{
"postId": 143,
"thread": 138,
"board": "t"
}
],
"actions": [
"Delete"
],
"date": "2022-08-12T06:31:45.492Z",
"showUser": false,
"message": null,
"user": null,
"board": "t"
},
{
"_id": "62f5f3c0b0ffeb3e12205fa1",
"showLinks": true,
"postLinks": [
{
"postId": 144,
"thread": 138,
"board": "t"
}
],
"actions": [
"Unlink files"
],
"date": "2022-08-12T06:31:28.084Z",
"showUser": true,
"message": null,
"user": "admin",
"board": "t"
},
{
"_id": "62f5e88038f79a03efaee40c",
"showLinks": true,
"postLinks": [
{
"postId": 138,
"thread": null,
"board": "t"
}
],
"actions": [
"Sticky"
],
"date": "2022-08-12T05:43:28.800Z",
"showUser": true,
"message": null,
"user": "admin",
"board": "t"
}
]
```
Returns a list of log entries for a board ona a particular date.
### HTTP Request
`GET https://fatchan.org/{board}/logs/{mm}-{dd}-{yyyy}.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
mm | Month of date to fetch log entries from, 01-12.
dd | Day of date to fetch log entries from, 01-31.
yyyy | Year of date to fetch log entries from, 0000-9999.
## Board custom page
```shell
curl "https://fatchan.org/t/custompage/example.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getCustomPageOptions := &jschan.GetCustomPageOptions{
Board: "t",
CustomPage: "example",
}
custompage, err := client.GetCustomPage(ctx, getCustomPageOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", custompage)
```
> The above command returns JSON structured like this:
```json
{
"board": "t",
"page": "example",
"title": "Example custompage",
"message": {
"raw": "Hello, world!\n>12345\n''wow!''",
"markdown": "Hello, world!\n<span class=\"greentext\">&gt;12345</span>\n<span class=\"bold\">wow!</span>"
},
"date": "2022-08-25T11:47:32.073Z",
"edited": null,
"_id": "63076154f5e68d47ddd787c4"
}
```
Returns the data for a board custom page.
### HTTP Request
`GET https://fatchan.org/{board}/custompage/{page}.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
name | Name of the page (same as the `name` property).
## Board banners
```shell
curl "https://fatchan.org/t/banners.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getBannersOptions := &jschan.GetBannersOptions{
Board: "t",
}
banners, err := client.GetBanners(ctx, getBannersOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", banners)
```
> The above command returns JSON structured like this:
```json
[
"efdff01e8310bd76f6561ea8f34ded9bca1a6ddff067fd9f024d39aad3ebf1ae.png",
"41bcdcb558954073a45a5faac7ac38f0824108062b5d0236c5b4e891b5278553.jpg"
]
```
Returns a list of board banner file names. Full path of a banner is `/banner/{board}/{filename}`.
### HTTP Request
`GET https://fatchan.org/{board}/banners.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
## Board settings
```shell
curl "https://fatchan.org/t/settings.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
getSettingsOptions := &jschan.GetSettingsOptions{
Board: "t",
}
settings, err := client.GetBanners(ctx, getSettingsOptions)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", settings)
```
> The above command returns JSON structured like this:
```json
{
"customPages": [
"example"
],
"announcement": {
"raw": ">lol!",
"markdown": "<span class=\"greentext\">&gt;lol!</span>"
},
"allowedFileTypes": {
"animatedImage": true,
"image": true,
"video": true,
"audio": true,
"other": true
},
"maxFiles": 5,
"captchaMode": 0,
"forceAnon": false,
"sageOnlyEmail": false,
"customFlags": false,
"forceThreadMessage": false,
"forceThreadFile": false,
"forceThreadSubject": false,
"disableReplySubject": false,
"minThreadMessageLength": 0,
"minReplyMessageLength": 0,
"maxThreadMessageLength": 20000,
"maxReplyMessageLength": 20000,
"defaultName": "Anon"
}
```
Returns some publicly available board settings.
### HTTP Request
`GET https://fatchan.org/{board}/settings.json`
### URL Parameters
Parameter | Description
--------- | -----------
board | Board URI.
## Global settings
```shell
curl "https://fatchan.org/settings.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
settings, err := client.GetGlobalSettings(ctx)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", settings)
```
> The above command returns JSON structured like this:
```json
{
"captchaOptions": {
"type": "text",
"grid": {
"size": 4,
"question": "Select all the odd numbers."
}
}
}
```
Returns some publicly available global settings.
### HTTP Request
`GET https://fatchan.org/settings.json`
## Webring
```shell
curl "https://fatchan.org/webring.json"
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
webring, err := client.GetWebring(ctx)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", webring)
```
> The above command returns JSON structured like this:
```json
{
"name": "fatchan",
"url": "https://fatchan.org",
"endpoint": "https://fatchan.org/webring.json",
"logo": [
"https://fatchan.org/favicon.ico"
],
"following": [
"https://anon.cafe/webring.json",
...
],
"blacklist": [],
"known": [
"https://anon.cafe/webring.json",
...
],
"boards": [
{
"uri": "t",
"title": "Meta",
"subtitle": "Fatchan Official",
"path": "https://fatchan.org/t/",
"postsPerHour": 0,
"postsPerDay": 0,
"totalPosts": 1410,
"uniqueUsers": 0,
"nsfw": false,
"tags": [
"meta",
"t",
"site",
"discussion",
"fatchan",
"/t/",
"/meta/",
"jschan"
],
"lastPostTimestamp": "2021-11-23T01:11:13.122Z"
}
]
}
```
Returns webring information.
The webring is a system "enabling the collaborating with other imageboards to form a decentralized webring via a standardized schema."
See here for compatible implementations:
- <a href='https://gitlab.com/Tenicu/infinityaddon-webring'>https://gitlab.com/Tenicu/infinityaddon-webring</a> (For infinity-based imageboards)
- <a href='https://gitlab.com/alogware/LynxChanAddon-Webring'>https://gitlab.com/alogware/LynxChanAddon-Webring</a> (For Lynxchan-based imageboards)
### HTTP Request
`GET https://fatchan.org/webring.json`
## Create thread/reply
```shell
# UNDER CONSTRUCTION...
```
```go
ctx := context.Background()
client := jschan.NewClient("https://fatchan.org")
makePostOptions := &jschan.MakePostOptions{
Board: "test",
Thread: 277,
Name: "Test",
Message: ">test",
Email: "sage",
PostPassword: "123",
Files: []string{"./image.png"},
}
err := client.MakePost(ctx, makePostOptions)
if err != nil {
fmt.Println(err)
return
}
```
Make a new thread, or reply to an existing thread.
### HTTP Request
`POST https://fatchan.org/forms/board/{board}/post`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
thread | number or null | postId of the thread this post is replying to. If null, creates a new thread.
name | string | Name
message | string | Message
subject | string | Subject
email | string | Email, or special values such as 'sage'.
postpassword | string | Post password lets users action posts e.g. delete, spoiler, remove files after posting. It's useful to let anonymous users manage their own posts without requiring an account. Users can set it manually, or if they have JavaScript enabled one is randomly generated and stored in localstorage. If the post password is left empty, the post can only be actioned by staff. Staff can also action any post without needing the post password. The ability for anonymous users to action their posts can be disabled on a per-board level.
file | file(s) | One or more files, multipart form data.
spoiler | array(string) | Array of sha256 hash of files to be spoilered.
spoiler_all | boolean | Whether to spoiler all files.
strip_filename | array(string) | Array of sha256 hash of files to have filenames stripped.. The sha256 hash will be used instead. Note: the server will still receive the original filenames before stripping.
customflag | string or null | Name of custom flag to be used. If null, will use no flag unless the board also has geoip flags enabled, then it will use the geo flag.
captcha | array(number) or string | See <a href='#captcha-block-bypass'>Captcha/block bypass</a>
signature | string | Signature output of a web3 eth personal_sign request with the content of the `message` parameter. Will add a signature and the recovered address to the bottom of the post.
## Post actions (delete, report, etc)
```shell
# UNDER CONSTRUCTION...
```
Submit actions against posts e.g. report, spoiler, delete. Supports multiple posts in a single submission. Actions against OP such as delete or move will take replies with it.
This endpoint does not require a session cookie or CSRF token like the staff variants, but having valid credentials will allow staff to bypass certain restrictions such as being able to delete posts when the board settings have "user post deletion" disabled.
Anonymous users can submit parameters checkedposts, delete, unlink_file, spoiler, postpassword, report, global_report, report_reason and captcha.
Multiple actions can be combined e.g. delete+ban. While there are no errors for submitting incompatible actions e.g. delete+report (you cannot report and delete a post simultaneously), the server will handle them in a sensible order, with delete taking precedence.
### HTTP Request
`POST https://fatchan.org/forms/board/{board}/actions`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
checkedposts | array(number) | Array of `postId`'s to action against.
delete | boolean | Delete the selected posts.
spoiler | boolean | Spoiler all files in the selected posts.
unlink_file | boolean | Unlink files from the selected posts. If there are other copies of the file in other posts, or the global settings do not immediately prune unlinked files, the file may remain on disk.
postpassword | string | Post password lets users action posts e.g. delete, spoiler, remove files after posting. It's useful to let anonymous users manage their own posts without requiring an account. Users can set it manually, or if they have JavaScript enabled one is randomly generated and stored in localstorage. If the post password is left empty, the post can only be actioned by staff. Staff can also action any post without needing the post password. The ability for anonymous users to action their posts can be disabled on a per-board level.
report | boolean | Report the selected posts to board staff.
global_report | boolean | Report the selected posts to global staff.
report_reason | string | Reason for reporting, if report or global_report.
captcha | array(number) or string | See <a href='#captcha-block-bypass'>Captcha/block bypass</a>
### HTTP Request
`POST https://fatchan.org/forms/board/{board}/actions`
# Staff Endpoints
The following endpoints are only available when properly authenticated and if your account has permission to access the respective pages.
## Board staff - create thread/reply
```shell
# UNDER CONSTRUCTION...
```
Make a new thread, or reply to an existing thread. Staff endpoint does not require captcha completion, but requires a CSRF token and session cookie.
### HTTP Request
`POST https://fatchan.org/forms/board/{board}/modpost`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
_csrf | string | <a href='#csrf-token'>CSRF token</a>
thread | number or null | postId of the thread this post is replying to. If null, creates a new thread.
name | string | Name
message | string | Message
subject | string | Subject
email | string | Email, or special values such as 'sage'.
postpassword | string | Post password lets users action posts e.g. delete, spoiler, remove files after posting. It's useful to let anonymous users manage their own posts without requiring an account. Users can set it manually, or if they have JavaScript enabled one is randomly generated and stored in localstorage. If the post password is left empty, the post can only be actioned by staff. Staff can also action any post without needing the post password. The ability for anonymous users to action their posts can be disabled on a per-board level.
file | file(s) | One or more files, multipart form data.
spoiler | array(string) | Array of sha256 hash of files to be spoilered.
spoiler_all | boolean | Whether to spoiler all files.
strip_filename | array(string) | Array of sha256 hash of files to have filenames stripped.. The sha256 hash will be used instead. Note: the server will still receive the original filenames before stripping.
customflag | string or null | Name of custom flag to be used. If null, will use no flag unless the board also has geoip flags enabled, then it will use the geo flag.
## Board staff - post actions
```shell
# UNDER CONSTRUCTION...
```
Submit actions against posts e.g. report, spoiler, delete. Supports multiple posts in a single submission. Actions against OP such as delete or move will take replies with it.
This endpoint requires a session cookie and CSRF token, allows staff to use additional actions, and bypass certain restrictions such as being able to delete posts when the board settings have "user post deletion" disabled.
Multiple actions can be combined e.g. delete+ban. While there are no errors for submitting incompatible actions e.g. delete+report (you cannot report and delete a post simultaneously), the server will handle them in a sensible order, with delete taking precedence.
### HTTP Request
`POST https://fatchan.org/forms/board/{board}/modactions`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
_csrf | string | <a href='#csrf-token'>CSRF token</a>
checkedposts | array(number) | Array of `postId`'s to action against.
delete | boolean | Delete the selected posts.
spoiler | boolean | Spoiler all files in the selected posts.
unlink_file | boolean | Unlink files from the selected posts. If there are other copies of the file in other posts, or the global settings do not immediately prune unlinked files, the file may remain on disk.
delete_file | boolean | Forcefully delete files from the selected posts, ignoring other references or server settings for delayed file pruning.
postpassword | string | Post password lets users action posts e.g. delete, spoiler, remove files after posting. It's useful to let anonymous users manage their own posts without requiring an account. Users can set it manually, or if they have JavaScript enabled one is randomly generated and stored in localstorage. If the post password is left empty, the post can only be actioned by staff. Staff can also action any post without needing the post password. The ability for anonymous users to action their posts can be disabled on a per-board level.
report | boolean | Report the selected posts to board staff.
global_report | boolean | Report the selected posts to global staff.
report_reason | string | Reason for reporting, if report or global_report.
ban | boolean | Ban the ips for all selected posts from the board.
global_ban | boolean | Ban the ips for all selected posts globally.
ban_q | boolean | Ban a small ip range, /24 for ipv4 and /64 for ipv6.
ban_h | boolean | Ban a larger ip range, /16 for ipv4 and /48 for ipv6.
no_appeal | boolean | Removes the ability to appeal a ban.
preserve_post | boolean | Whether to preserve the post and show it in the ban page. If the server prunes files, the files may no longer exist.
hide_name | boolean | Whether the username of the staff should be hidden from public modlogs.
sticky | number | Set the sticky priority for a thread. Threads are sorted in descending order, with 0 being the default or not sticky.
lock | boolean | Toggles if a thread is locked, so no more repies are allowed from unauthenticated users.
bumplock | boolean | Toggles if a thread is bumplocked, so replies will no longer bump the thread.
cyclic | boolean | Toggles if a thread is cyclic, i.e. when it reaches thread limit earlier replies are deleted and replaced by new posts instead of locking the thread.
checkedreports | array(string) | Array of report ids, for report actions such as dismiss or report_ban.
edit | boolean | Whether to edit the selected post. Staff only. Must have only a single `checkedposts`.
ban_reason | string | Reason for banning if ban or global_ban.
log_message | string | Message to show in modlog explaining the reason for post actions.
ban_duration | <a href='#time-format-string'>Time format string</a> | Time format string for how long until the ban expires.
report_ban | boolean | Whether to ban a reporter. Must submit the checkedpost and relevant checkedreports.
move | boolean | Whether to move selected posts to another thread.
move_to_thread | The postId of the destination thread for moving.
## Board staff - recent posts
```shell
curl -v 'https://fatchan.org/t/manage/recent.json' \
-H 'Cookie: connect.sid=s%REDACTED;'
```
> The above command returns JSON structured like this:
```json
[
{
"_id": "6182b5f2013eb3d1e8313300",
"date": "2021-11-03T16:16:50.257Z",
"u": 1635956210257,
"name": "Anon",
"country": {
"code": "TOR",
"name": "Tor Hidden Service"
},
"board": "t",
"tripcode": null,
"capcode": null,
"subject": "",
"message": "<a class=\"quote\" href=\"/t/thread/1376.html#1377\">&gt;&gt;1377</a>\r\nOh yeah. Did you change the default from iwakura to lain? Looks good.",
"messagehash": "uD7zsFXapRsocZPJzUeroVsND9KvX4FQ0AmAl54FXxg=",
"nomarkup": ">>1377\r\nOh yeah. Did you change the default from iwakura to lain? Looks good.",
"thread": 1376,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "546403",
"ip": {
"raw": "redacted",
"cloak": "redacted"
},
"files": [],
"reports": [],
"quotes": [
{
"_id": "61820031804c0bf6d2271026",
"thread": 1376,
"postId": 1377
}
],
"crossquotes": [],
"backlinks": [
{
"_id": "6182ba0da5af18e5ee5b3f2b",
"postId": 1382
}
],
"postId": 1381
}
]
```
Returns a list of the most recent posts made on a specific board.
### HTTP Request
`GET https://fatchan.org/{board}/manage/recent.json`
### URL Parameters
Parameter | Type | Description
--------- | ------- | -----------
board | string | The board to fetch recent posts from.
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
page | | Page number. 30 per page. Blank is first page. Page numbering starts at 1.
## Board staff - reports
```shell
curl -v 'https://fatchan.org/t/manage/reports.json' \
-H 'Cookie: connect.sid=s%REDACTED;'
```
> The above command returns JSON structured like this:
```json
{
"reports": [
{
"_id": "61a06777c3ba8becf5be6303",
"date": "2021-11-26T04:49:59.832Z",
"u": 1637902199832,
"name": "Anon",
"country": {
"code": "TOR",
"name": "Tor Hidden Service"
},
"board": "test",
"tripcode": null,
"capcode": null,
"subject": "",
"message": "test",
"messagehash": "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=",
"nomarkup": "test",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "1e22fb",
"ip": {
"raw": "redacted",
"cloak": "redacted"
},
"files": [],
"reports": [
{
"id": "61a63249a2e147d7c0f382dd",
"reason": "test",
"date": "2021-11-30T14:16:41.780Z",
"ip": {
"cloak": "redacted"
}
}
],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 0,
"replyfiles": 0,
"sticky": 0,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-26T04:49:59.832Z",
"postId": 224
}
]
}
```
Returns a list of posts that were reported with the board reports attached.
### HTTP Request
`GET https://fatchan.org/{board}/manage/reports.json`
## Global staff - post actions
```shell
# UNDER CONSTRUCTION...
```
Submit actions against posts e.g. report, spoiler, delete. Supports multiple posts in a single submission. Actions against OP such as delete or move will take replies with it.
This endpoint requires a session cookie and CSRF token, allows global staff to use additional actions, and bypass restrictions.
Multiple actions can be combined e.g. delete+ban. While there are no errors for submitting incompatible actions e.g. delete+report (you cannot report and delete a post simultaneously), the server will handle them in a sensible order, with delete taking precedence.
Certain actions such as "move" are not present compared to the board-specific endpoints because global actions can apply to posts from multiple different boards.
Global actions use posts _id (mongo id) in the globalcheckedposts array instead of postIds because global actions can apply to posts from multiple different boards and cannot just reference postIds.
### HTTP Request
`POST https://fatchan.org/forms/global/actions`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
globalcheckedposts | array(string) | Array of post _ids to action against.
delete | boolean | Delete the selected posts.
spoiler | boolean | Spoiler all files in the selected posts.
unlink_file | boolean | Unlink files from the selected posts. If there are other copies of the file in other posts, or the global settings do not immediately prune unlinked files, the file may remain on disk.
delete_file | boolean | Forcefully delete files from the selected posts, ignoring other references or server settings for delayed file pruning.
global_report | boolean | Report the selected posts to global staff.
global_ban | boolean | Ban the ips for all selected posts globally.
ban_q | boolean | Ban a small ip range, /24 for ipv4 and /64 for ipv6.
ban_h | boolean | Ban a larger ip range, /16 for ipv4 and /48 for ipv6.
no_appeal | boolean | Removes the ability to appeal a ban.
preserve_post | boolean | Whether to preserve the post and show it in the ban page. If the server prunes files, the files may no longer exist.
hide_name | boolean | Whether the username of the staff should be hidden from public modlogs.
checkedreports | array(string) | Array of report ids, for report actions such as dismiss or report_ban.
edit | boolean | Whether to edit the selected post. Staff only. Must have only a single `checkedposts`.
ban_reason | string | Reason for banning if ban or global_ban.
log_message | string | Message to show in modlog explaining the reason for post actions.
ban_duration | <a href='#time-format-string'>Time format string</a> | Time format string for how long until the ban expires.
report_ban | boolean | Whether to ban a reporter. Must submit the checkedpost and relevant checkedreports.
_csrf | string | <a href='#csrf-token'>CSRF token</a>
## Global staff - reports
```shell
curl -v 'https://fatchan.org/globalmanage/reports.json' \
-H 'Cookie: connect.sid=s%REDACTED;'
```
> The above command returns JSON structured like this:
```json
{
"reports": [
{
"_id": "61a06777c3ba8becf5be6303",
"date": "2021-11-26T04:49:59.832Z",
"u": 1637902199832,
"name": "Anon",
"country": {
"code": "TOR",
"name": "Tor Hidden Service"
},
"board": "test",
"tripcode": null,
"capcode": null,
"subject": "",
"message": "test",
"messagehash": "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=",
"nomarkup": "test",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "1e22fb",
"ip": {
"raw": "redacted",
"cloak": "redacted"
},
"files": [],
"globalreports": [
{
"id": "61a63249a2e147d7c0f382dd",
"reason": "test",
"date": "2021-11-30T14:16:41.780Z",
"ip": {
"cloak": "redacted"
}
}
],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 0,
"replyfiles": 0,
"sticky": 0,
"locked": 0,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-11-26T04:49:59.832Z",
"postId": 224
}
],
"page": 1,
"ip": null,
"queryString": ""
}
```
Returns a list of posts that were globally reported with the global reports attached.
### HTTP Request
`GET https://fatchan.org/globalmanage/reports.json`
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
page | | Page number. 30 per page. Blank is first page. Page numbering starts at 1.
ip | | Urlencoded IP address or cloak. Filters results to only posts made or reported by the IP.
## Global staff - recent posts
```shell
curl -v 'https://fatchan.org/globalmanage/recent.json' \
-H 'Cookie: connect.sid=s%REDACTED;'
```
> The above command returns JSON structured like this:
```json
[
{
"_id": "619c4cd4c3ba8becf5be62eb",
"date": "2021-11-23T02:07:16.339Z",
"u": 1637633236339,
"name": "Anon",
"country": null,
"board": "b",
"tripcode": null,
"capcode": null,
"subject": null,
"message": "<a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://m.youtube.com/watch?v=Fiv7nteHZPY&amp;feature=emb_title\">https://m.youtube.com/watch?v=Fiv7nteHZPY&amp;feature=emb_title</a>\r\n\r\nPresenting, life of childe",
"messagehash": "yzBCT0RFSk7PWwHipZdetIkymJc7HDbth2d5uVQFokk=",
"nomarkup": "https://m.youtube.com/watch?v=Fiv7nteHZPY&feature=emb_title\r\n\r\nPresenting, life of childe",
"thread": 109,
"email": null,
"spoiler": false,
"banmessage": null,
"userId": null,
"ip": {
"raw": "redacted",
"cloak": "redacted"
},
"files": [],
"globalreports": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"postId": 311
}
]
```
Returns a list of the most recent posts made across all boards.
### HTTP Request
`GET https://fatchan.org/globalmanage/recent.json`
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
page | | Page number. 30 per page. Blank is first page. Page numbering starts at 1.
## Global staff - board list
```shell
curl -v 'https://fatchan.org/globalmanage/boards.json' \
-H 'Cookie: connect.sid=s%REDACTED;'
```
> The above command returns JSON structured like this:
```json
{
"localBoards": [
{
"_id": "lain",
"owner": "redacted",
"tags": [
"lain",
"internet",
"technology",
"transhumanism",
"anime",
"manga",
"japan"
],
"sequence_value": 572,
"pph": 0,
"ppd": 2,
"ips": 2,
"lastPostTimestamp": {
"text": "5 hours ago",
"color": "#83d900"
},
"webring": false,
"settings": {
"moderators": [],
"name": "serial experiments lain",
"description": "ANIME / GAME / PRINT / SOFTWARE",
"sfw": true,
"unlistedLocal": false
}
},
{
"_id": "b",
"owner": "redacted",
"sequence_value": 323,
"pph": 0,
"ips": 2,
"lastPostTimestamp": {
"text": "27 minutes ago",
"color": "#31d900"
},
"settings": {
"moderators": [],
"name": "Random",
"description": "Where morons argue with baiting spammers",
"sfw": false,
"unlistedLocal": false
},
"ppd": 2,
"tags": [
"random",
"b",
"rand",
"anything",
"everything"
],
"webring": false
},
],
"page": 1,
"maxPage": 1
}
```
Returns a list of boards, 30 per page. Unlike the public endpoint it does not include webring boards, includes unlisted boards and shows whether a board is abandoned (has no owner). Can be filtered and sorted like the public board list.
### HTTP Request
`GET https://fatchan.org/globalmanage/boards.json`
### Query Parameters
Parameter | Default | Description
--------- | ------- | -----------
page | | Page number. 30 per page. Blank is first page. Page numbering starts at 1.
search | | A string to search by board name and tags, including prefix matches.
sort | `popularity` | `popularity` sorts by a compound of (ips, pph, sequence_value), `activity` sorts by lastPostTimestamp.
direction | `desc` | `desc` or `asc` for descending or ascending sort order respectively.
filter_unlisted | `false` | Filter to only unlisted boards.
filter_sfw | `false` | Filter to only sfw boards.
filter_abandoned | `false` | Filter to only abandoned boards.
Filters used in conjunction will AND together. That is, filter_unlited=true&filter_sfw=true will show only boards that are both unlisted and sfw.
# Authentication
## Register
```shell
curl -v 'https://fatchan.org/forms/register' -X POST \
-H 'Referer: https://fatchan.org/registration.html' -H 'x-using-xhr: true' \
--data "username=admin" --data "password=hunter2" --data "passwordconfirm=hunter2" --data "captcha=abc123"
# if the account is created successfully, 302 redirect to login.
...
< HTTP/2 302
< location: /login.html
...
```
Registers a new account.
### HTTP Request
`POST https://fatchan.org/forms/register`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
username | string | Account username
password | string | Account password
passwordconfirm | string | Account password repeated
captcha | array(number) or string | See <a href='#captcha-block-bypass'>Captcha/block bypass</a>
nonce | string | Optional, for web3 registration: the nonce fetched from the nonce endpoint
address | string | Optional, for web3 registration: eth address
signature | string | Optional, for web3 registration: web3 signature output of signing the nonce
## Login
```shell
curl -v 'https://fatchan.org/forms/login' -X POST \
-H 'Referer: https://fatchan.org/login.html' -H 'x-using-xhr: true' \
--data "username=admin" --data "password=hunter2"
# if the password is correct, 302 response code and sets the 'connect.sid' cookie
...
< HTTP/2 302
< location: /account.html
< set-cookie: connect.sid=s%REDACTED; Path=/; Expires=Wed, 01 Dec 2021 10:35:03 GMT; HttpOnly; Secure; SameSite=Strict
...
# or, for an incorrect password, a 403 and an error
...
< HTTP/2 403
...
{"title":"Forbidden","message":"Incorrect username or password","redirect":"/login.html?goto=%2Faccount.html"}
```
Login to an account to get a session cookie. The `connect.sid` cookie must be sent in requests to endpoints that require authentication.
Expiry is rolling, so each time the session is used, the expiry is reset to 24 hours and this will be reflected in the expiry value in set-cookie headers.
### HTTP Request
`POST https://fatchan.org/forms/login`
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
username | string | Account username
password | string | Account password
nonce | string | Optional, for web3 login: the nonce fetched from the nonce endpoint
address | string | Optional, for web3 login: eth address
signature | string | Optional, for web3 login: web3 signature output of signing the nonce
## Logout
```shell
curl 'https://fatchan.org/forms/logout' -X POST \
-H 'Referer: https://fatchan.org/account.html' -H 'x-using-xhr: true' \
-H 'Cookie: connect.sid=s%REDACTED;'
```
Logs out and invalidate the connect.sid session cookie.
### HTTP Request
`POST https://fatchan.org/forms/logout`
## CSRF token
```shell
curl -v 'https://fatchan.org/csrf.json' \
-H 'Referer: https://fatchan.org/csrf.json' \
-H 'Cookie: connect.sid=s%REDACTED;'
# Returns a csrf token if the session cookie is valid.
...
< HTTP/2 200
...
{"token":"REDACTED"}
```
Returns a token used as an additional security field by some endpoints. For more information about CSRF (cross site request forgery), see <a href='https://owasp.org/www-community/attacks/csrf'>https://owasp.org/www-community/attacks/csrf'</a>
### HTTP Request
`GET https://fatchan.org/csrf.json`
## Captcha/block bypass
To solve a captcha when posting, or to separately solve a block bypass, submit the `captchaid` cookie and data `captcha`. Depending on captcha type, there are different options.
The example requests below are for blockbypass endpoint, however the same `captchaid` cookie and `captcha` data should be submitted to the reporting and posting endpoint when captcha is enabled.
If a form submission requires a block bypass and the form also requires a captcha, solving the captcha correctly will count as a block bypass, so it is not necessary to solve an additional block bypass captcha beforehand.
---
```shell
# Get a captchaid cookie
curl -v 'https://fatchan.org/captcha'
# returns 302 to the captcha image, and sets the cookie.
< HTTP/2 302
< set-cookie: captchaid=61b55e3e49e367be7c5a818c; Max-Age=300; Path=/; Expires=Sun, 12 Dec 2021 02:33:14 GMT; Secure; SameSite=Strict
< location: /captcha/61b55e3e49e367be7c5a818c.jpg
...
```
## Web3 Nonce
```shell
curl -v 'https://fatchan.org/nonce/{address}.json' -X POST \
-H 'Referer: https://fatchan.org/login.html' \
# Returns json with the nonce
...
< HTTP/2 200 OK
...
< {"nonce":"diPRlfjSVQs78DGE3YKcENb4pgRqB1Bdlv3RH/yiE6Y="}
...
Fetches a nonce used as part of the web3 login process.
### HTTP Request
`GET https://fatchan.org/nonce/{address}.json`
### URL Parameters
Parameter | Type | Description
--------- | ---- | -----------
address | string | Ethereum address e.g. 0x68b637f227953eeb081a3b591c218adbeaa4c489
### Captcha cookie
To solve a captcha, you need a `captchaid` cookie.
Visiting `/captcha` will set the captchaid cookie (if you do not already have one), and redirect you to the captcha image `/captcha/<captchaid>.jpg`.
The cookie is required to be submitted when solving the captcha as described in the next sections. Captcha id cookies are valid for ~5 minutes in a default jschan configuration.
### HTTP Request
`GET https://fatchan.org/captcha`
```shell
# Grid v1 captcha example
curl 'https://fatchan.org/forms/blockbypass' -X POST \
-H 'Referer: https://fatchan.org/bypass.html' -H 'x-using-xhr: true' \
-H 'Cookie: captchaid=61a60064a2e147d7c0f382d8' \
--data 'captcha=1' --data 'captcha=3' --data 'captcha=11'
# returns 200 and a bypassid cookie if correct
< HTTP/2 200
< set-cookie: bypassid=s%REDACTED; Max-Age=86400; Path=/; Expires=Wed, 01 Dec 2021 11:12:21 GMT; Secure; SameSite=Strict
{"title":"Success","message":"Completed block bypass, you may go back and make your post."}
```
---
### Grid v1 captcha
Grid v1 captcha consists of a nxn (by default 4x4) square grid of characters, and a question text.
The characters are separated into "correct" and "incorrect" character groups, with a minimum of at least one correct character in the grid.
Follow the question text and select only the "correct" characters.
The character groups and question text can be completely customised, so it is not possible to document exact instructions for each.
The captcha may have image effects applied such as noise, edge detection and distortion.
The default grid v1 configuration of jschan is:
<ul>
<li>correct: `['●','■','♞','♦','▼','▲','♜','✦','♚','♞','♛','♝','♟','♣']`
<li>incorrect: `['○','□','♘','♢','▽','△','♖','✧','♔','♘','♕','♗','♙','♧']`
<li>question: 'Select the solid/filled icons'
</ul>
The grid positions start from 0 and go from left to right, top to bottom i.e:
<table>
<tr><td>0</td><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td><td>11</td></tr>
<tr><td>12</td><td>13</td><td>14</td><td>15</td></tr>
</table>
Example (the example request is for this image):
Question: "Select the solid/filled icons"
<table>
<tr>
<td style="padding: 0;">
<%= image_tag "images/grid-captcha.png" %>
</td>
<td style="padding: 0;">
<table style="padding: 0;margin: 0;">
<tr><td>0</td><td style="background: lightgreen;">1</td><td>2</td><td style="background: lightgreen;">3</td></tr>
<tr><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td><td style="background: lightgreen;">11</td></tr>
<tr><td>12</td><td>13</td><td>14</td><td>15</td></tr>
</table>
</td>
</tr>
</table>
The solution is 1, 3, 11.
Other examples:
Question: "Select the odd numbers"
<table>
<tr>
<td style="padding: 0;">
<%= image_tag "images/grid-captcha-2.jpg" %>
</td>
<td style="padding: 0;">
<table style="padding: 0;margin: 0;">
<tr><td>0</td><td style="background: lightgreen;">1</td><td>2</td><td style="background: lightgreen;">3</td></tr>
<tr><td style="background: lightgreen;">4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td><td>11</td></tr>
<tr><td style="background: lightgreen;">12</td><td style="background: lightgreen;">13</td><td style="background: lightgreen;">14</td><td>15</td></tr>
</table>
</td>
</tr>
</table>
The solution is 1, 3, 4, 12, 13, 14.
### HTTP Request
`POST https://fatchan.org/forms/blockbypass`
### Parameters
Parameter | Type | Description
--------- | ----------- | -----------
captcha | array(number) | One or more numbers for the correct grid square indexes.
```shell
# Grid v2 captcha example
curl 'https://fatchan.org/forms/blockbypass' -X POST \
-H 'Referer: https://fatchan.org/bypass.html' -H 'x-using-xhr: true' \
-H 'Cookie: captchaid=61a60064a2e147d7c0f382d8' \
--data 'captcha=2' --data 'captcha=6' --data 'captcha=11' --data 'captcha=14'
# returns 200 and a bypassid cookie if correct
< HTTP/2 200
< set-cookie: bypassid=s%REDACTED; Max-Age=86400; Path=/; Expires=Wed, 01 Dec 2021 11:12:21 GMT; Secure; SameSite=Strict
{"title":"Success","message":"Completed block bypass, you may go back and make your post."}
```
---
### Grid v2 captcha
Grid v2 captcha consists of a nxn (by default 4x4) square grid of characters and arrows, and a question text.
The characters are separated into "correct" and "incorrect" character groups, with one correct character in the grid. The rest of the grid will be incorrect characters and arrows.
The objective is to select all arrows pointing at the "correct" character.
The character groups (excluding arrows) and question text can be completely customised, so it is not possible to document exact instructions for each.
The captcha may have image effects applied such as noise, edge detection and distortion.
Grid v2 configuration is shared with v1.
The grid positions start from 0 and go from left to right, top to bottom i.e:
<table>
<tr><td>0</td><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td><td>11</td></tr>
<tr><td>12</td><td>13</td><td>14</td><td>15</td></tr>
</table>
Example (the example request is for this image):
<table>
<tr>
<td style="padding: 0;">
<%= image_tag "images/grid2-captcha.png" %>
</td>
<td style="padding: 0;">
<table style="padding: 0;margin: 0;">
<tr><td>0</td><td>1</td><td style="background: lightgreen;">2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td style="background: lightgreen;">6</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td><td style="background: lightgreen;">11</td></tr>
<tr><td>12</td><td>13</td><td style="background: lightgreen;">14</td><td>15</td></tr>
</table>
</td>
</tr>
</table>
The solution is 2, 6, 11, 14.
### HTTP Request
`POST https://fatchan.org/forms/blockbypass`
### Parameters
Parameter | Type | Description
--------- | ----------- | -----------
captcha | array(number) | One or more numbers for the correct grid square indexes.
---
```shell
# Text captcha example
curl 'https://fatchan.org/forms/blockbypass' -X POST \
-H 'Referer: https://fatchan.org/bypass.html' -H 'x-using-xhr: true' \
-H 'Cookie: captchaid=61a60064a2e147d7c0f382d8' \
--data 'captcha=bxw9yt'
# returns 200 and a bypassid cookie if correct
< HTTP/2 200
< set-cookie: bypassid=s%REDACTED; Max-Age=86400; Path=/; Expires=Wed, 01 Dec 2021 11:12:21 GMT; Secure; SameSite=Strict
{"title":"Success","message":"Completed block bypass, you may go back and make your post."}
```
### Text captcha
Text captcha is a simple 6 character captcha containing numbers and letters only.
The captcha may have a different font, and image effects applied such as wave, noise, paint, strikethrough, and distortion.
Example (the example request is for this image):
<%= image_tag "images/text-captcha.png" %> Solution: `bxw9yt`.
Other examples:
<%= image_tag "images/text-captcha-2.jpg" %> Solution: `3dhm6f`.
<%= image_tag "images/text-captcha-3.jpg" %> Solution: `lcvpya`.
<%= image_tag "images/text-captcha-4.jpg" %> Solution: `xnkosc`.
### HTTP Request
`POST https://fatchan.org/forms/blockbypass`
### Parameters
Parameter | Type | Description
--------- | ----------- | -----------
captcha | string | The text shown in the image.
# Objects & Properties
## Board
> Two example boards. The first a webring board, the second a local board.
```json
{
"_id": "61a45ea2c5f3b57f31789cfc",
"uri": "a",
"sequence_value": 709261,
"ips": 109,
"pph": 25,
"webring": true
"path": "https://smuglo.li/a",
"siteName": "Smug",
"lastPostTimestamp": {
"text": "12 minutes ago",
"color": "#14d900"
},
"settings": {
"sfw": false,
"name": "Anime & Manga",
"description": "Stay away from 3DPD"
},
"tags": [
"anime",
"manga"
]
}
```
```json
{
"_id": "b",
"sequence_value": 320,
"ips": 4,
"pph": 0,
"ppd": 5,
"webring": false
"lastPostTimestamp": {
"text": "1 hour ago",
"color": "#72d900"
},
"settings": {
"name": "Random",
"description": "Anything and everything",
"sfw": false,
"unlistedLocal": false
},
"tags": [
"random",
"b",
"rand",
"anything",
"everything"
],
},
```
Returned from boards endpoint and global staff boards endpoint. Can be a local board, or one fetched from a federated site through the "webring" system. Local and webring boards have slightly different data.
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
_id | string | The board URI if `webring` is false, otherwise a unique identifier for a webring board.
uri | string | The board URI if `webring` is true, otherwise not present.
sequence_value | number | The current highest post number.
ips | number | Number of IPs from active users. In `webring` false boards, represents the number of unique IPs that have posted in the last 24 hours. In `webring` true, implementations vary and the timeframe may be different.
pph | number | Number of posts made in the last hour.
ppd | number | Number of posts made in the last day. Not present in all webring implementations.
webring | boolean | Whether a board is a webring board, or a local board.
path | string | The URL of the board if `webring` true, otherwise not present.
siteName | string | The site name if `webring` true, otherwise not preesnt.
lastPostTimestamp | object |
lastPostTimestamp.text | string | Text representation of when the last post was made e.g. "13 minutes ago".
lastPostTimestamp.color | string | Text of a hexadecimal color code prefixed with # e.g. "#14d900".
settings | object
settings.sfw | boolean | Whether the board is "safe for work".
settings.name | string | The board name.
settings.description | string | The board description.
settings.unlistedLocal | boolean | Whether the board is unlisted locally if `webring` false, otherwise not present. Always false on public boards endpoint.
settings.moderators | array(string) | List of usernames of moderators, only present in global staff board list.
owner | string | Board owner username, only present in global staff board list.
tags | array(string) | List of tags for the board.
## Post
> An example post
```json
{
"_id": "6158e81eb33d7abaa5f90ba0",
"date": "2021-10-02T23:15:42.675Z",
"u": 1633216542675,
"name": "Anon",
"country": {
"code": "AU",
"name": "Australia"
},
"ip": {
"raw": "redacted",
"cloak": "redacted"
},
"board": "t",
"tripcode": null,
"capcode": "## Admin",
"subject": "Important Links",
"message": "<span class=\"title\">Git repository &amp; issue tracker:</span> <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://gitgud.io/fatchan/jschan\">https://gitgud.io/fatchan/jschan</a>\nGo here to see the source code, report issues or ask relevant questions.\n\n<span class=\"title\">IRC:</span> <a rel=\"nofollow\" referrerpolicy=\"same-origin\" target=\"_blank\" href=\"https://irc-web.fatpeople.lol\">https://irc-web.fatpeople.lol</a> (irc-web.fatpeople.lol port 6697 TLS on)\nJoin IRC to chat directly with staff and other users in a realtime format.\n\n<span class=\"title\">Test board:</span> <a class=\"quote\" href=\"/test/index.html\">&gt;&gt;&gt;/test/</a>\nTest things on the /test/ board rather than here or anywhere else.",
"messagehash": "tkak9s72dCSv9XkocVNwceUfmtwqaTH8gL9bzcQxwP4=",
"nomarkup": "==Git repository & issue tracker:== https://gitgud.io/fatchan/jschan\nGo here to see the source code, report issues or ask relevant questions.\n\n==IRC:== https://irc-web.fatpeople.lol (irc-web.fatpeople.lol port 6697 TLS on)\nJoin IRC to chat directly with staff and other users in a realtime format.\n\n==Test board:== >>>/test/\nTest things on the /test/ board rather than here or anywhere else.",
"thread": null,
"email": "",
"spoiler": false,
"banmessage": null,
"userId": "307203",
"files": [],
"quotes": [],
"crossquotes": [],
"backlinks": [],
"replyposts": 0,
"replyfiles": 0,
"sticky": 3,
"locked": 1,
"bumplocked": 0,
"cyclic": 0,
"bumped": "2021-10-02T23:15:42.675Z",
"postId": 1360,
"edited": {
"username": "admin",
"date": "2021-11-03T00:36:36.620Z"
},
"replies": []
}
```
Returned from overboard endpoints, board endpoints, staff recent posts and staff reports endpoints.
A post can be a thread of a reply. The thread being the first post under which replies are made. Threads include a few extra properties for things such as being "sticky". Where included (such as index pages and threads), replies are nested within the "replies" property of a thread.
### Parameters
Parameter | Type | Description
--------- | ---- | -----------
_id | string | Unique identifier for the post.
date | string | The ISO format date string of when the post was made.
u | string | Unix timestamp format of when the post was made.
name | string | The poster name.
board | string | The board URI.
country | object | Geoip or custom flag information, if enabled on a board.
country.code | string | Custom flag name if `country.custom` is true. Otherwise ISO 2 character country code, or "T1" for Tor exit nodes, "TOR" for Tor .onion, "LOKI" for lokinet, or "XX" for unknown (no geoip information).
country.name | string | Custom flag name if `country.custom` is true. Otherwise the country name. "Europe" for unknown european country. "Unknown" when no geoip information is available. "Tor Exit Node" for Tor exit node. "Tor Hidden Service" for Tor .onion.
country.custom | boolean | Whether the flag is a board custom flag.
country.src | string | The filename of a board custom flag. The absolute path of the flag file is `/flag/{board}/{country.src}`.
ip | object |
ip.raw | string | IP (or `ip.cloak` if raw ips are not stored).
ip.cloak | string | Cloaked IP.
tripcode | string or null | The tripcode if one was used, otherwise null. Traditional ("insecure") tripcodes start with `!`, "secure" tripcodes use `!!`.
capcode | string or null | The staff capcode if one is used e.g. '## Admin'.
subject | string | The post subject.
message | string | HTML formatted message
nomarkup | string | Original message before HTML formatting.
messagehash | string | sha256 hash of nomarkup.
postId | number | The post number, increasing by 1 for each post.
thread | number of null | For threads, null. For replies, a number equal to the `postId` of the thread.
email | string or null | The poster email. Not necessarily an email, can be any string or special values like "sage" meaning the post will not bump a thread.
spoiler | boolean | Whether all files in a post are spoilered.
signature | string or null | Web3 eth personal_sign signature of signed message content.
address | string or null | Recovered ethereum address from web3 signature.
banmessage | string or null | The public ban message attached to a post, optionally set when a staff member bans the poster without deleting the post.
userId | string or null | The user ID which is a substring of a hash of poster IP + server side per-thread secret e.g. substring(hash(poster IP + thread secret)).
files | array(<a href='#file'>File</a>) | Array of files, explained in the File subsection
quotes | array(object) | Array of quotes, posts within the same thread that this post mentions.
quotes[]._id | string | Corresponds to the `_id` property of a post.
quotes[].thread | number | Corresponds to the `thread` property of a post.
quotes[].postId | number | Corresponds to the `postId` property of a post.
crossquotes | array(object) | Array of crossquotes, posts in other threads on the same board that this post mentions.
crossquotes[]._id | string | Corresponds to the `_id` property of a post.
crossquotes[].thread | number | Corresponds to the `thread` property of a post.
crossquotes[].postId | number | Corresponds to the `postId` property of a post.
backlinks | array(object) | Array of backlinks, posts in the same thread that mention this post.
backlinks[]._id | string | Corresponds to the `_id` property of a post.
backlinks[].postId | number | Corresponds to the `postId` property of a post.
replyposts | number | Threads only, the number of replies to this post.
replyfiles | number | Threads only, the total number of files in all replie sto this post.
sticky | number | Threads only, The "sticky" priority of a thread. Higher number = higher priority and sorted earlier. 0 = Not sticky.
locked | number | Threads only, 0 = not locked, 1 = locked. Locked prevents non-staff from replying to the thread.
cyclic | number | Threads only, 0 = not cyclic, 1 = locked. Cyclic means earlier replies will be deleted to make room for new replies, instead of the thread reaching a bump limit and locking.
bumplocked | number | Threads only, 0 = not locked, 1 = locked. Bumplocked prevents the thread from being bumped when a reply is posted.
bumped | string | Threads only, the ISO format date string of when the thread was last bumped. Note, this is not equal to the `date` of the most recent reply because it could have used "sage" email, the thread may be bumplocked, or have reached the bump limit.
edited | object | Object with information about when the post was last edited.
edited.username | string | Username of the staff who edited the post.
edited.date | string | ISO format date string of when the post was edited.
replies | array(<a href='#post'>Post</a>) | Array of replies (other non-thread posts). Only present in threads, or index pages with > 0 preview replies.
reports | array(<a href='#report'>Report</a>) | Array of board reports. Only present when fetched from board staff endpoints.
globalreports | array(<a href='#report'>Report</a>) | Array of global reports. Only present when fetched from global staff endpoints.
## File
> An example file
```json
{
"spoiler": null,
"hash": "10e24a1eef06d36d29a30f60e4616ef8cea9050c8f1e13b80af75b01687ef1fa",
"filename": "10e24a1eef06d36d29a30f60e4616ef8cea9050c8f1e13b80af75b01687ef1fa.jpg",
"originalFilename": "10e24a1eef06d36d29a30f60e4616ef8cea9050c8f1e13b80af75b01687ef1fa.jpg",
"mimetype": "image/jpeg",
"size": 259561,
"extension": ".jpg",
"sizeString": "253.5KB",
"thumbextension": ".jpg",
"geometry": {
"width": 1024,
"height": 768,
"thumbwidth": 250,
"thumbheight": 187
},
"geometryString": "1024x768",
"hasThumb": true
}
```
Files uploaded by users, in the `files` array of a Post object.
Parameter | Type | Description
--------- | ---- | -----------
spoiler | boolean | If the individual file is spoilered
hash | string | Sha256 hash of the file
filename | string | Filename (sha256sum + extension). Absolute path of files are /file/{filename}
originalFilename | string | The original filename (non hash) of the file when uploaded.
mimetype | string | Mimetype of the file e.g. "image/png" or "video/webm"
extension | string | The file extension with . e.g. ".jpg"
size | number | Size in bytes of the file
sizeString | string | Friendly string format of filesize, a number with up to 1 decimal place followed by the unit B, KB, MB, GB, TB.
duration | number | Floating point number, how many seconds a video or audio file is.
durationString | string | Friendly string format of duration, in hours:minutes:seconds format. Hours are the largest unit and can be a number larger than 99. Number in each segment are left padded with 0. Duration less than 60 seconds will have 00: prefixed. Will not show 00: for hours. e.g. 35 seconds = 00:35, 1 minute 25 seconds = 01:35, 1 hour 35 minutes = 01:35:00
thumbextension | string | The file extension of the thumbnail with . e.g. ".jpg". Can be different from `extension` due to thumbnails using different format.
geometry | object | Object containing information about file and thumbnail dimensions.
geometry.width | string | Width in pixels of the file.
geometry.height | string | Height in pixels of the file.
geometry.thumbwidth | string | Width in pixels of the thumbnail.
geometry.thumbheight | string | Height in pixels of the thumbnail.
geometryString | string | Friendly string format of the file geometry as `{width}x{height}`.
hasThumb | boolean | Whether the file has a thumbnail.
attachment | boolean | Whether the file is an "attachment" type, a file that is not an image, video or audio.
## Report
> An example report
```json
{
"id": "61a5d504ed285eccf2909dee",
"reason": "spam",
"date": "2021-11-30T07:38:44.971Z",
"ip": {
"raw": "redacted",
"cloak": "redacted"
}
}
```
Parameter | Type | Description
--------- | ---- | -----------
id | string | Unique identifier of the report.
reason | string | Report reason entered by the reporter.
date | string | ISO format date string when the report was made.
ip | object |
ip.raw | string | IP (or `ip.cloak` if raw ips are not stored).
ip.cloak | string | Cloaked IP.
## Webring.json
> Example webring.json data
```json
{
"name": "fatchan",
"url": "https://fatchan.org",
"endpoint": "https://fatchan.org/webring.json",
"logo": [
"https://fatchan.org/favicon.ico"
],
"following": [
"https://anon.cafe/webring.json",
...
],
"blacklist": [],
"known": [
"https://anon.cafe/webring.json",
...
],
"boards": [
]
}
```
Webring.json data.
Parameter | Type | Description
--------- | ---- | -----------
name | string | The name of this site.
url | string | The primary url of this site.
endpoint | string | The url of the webring.json file. Typically `{url}/webring.json`
logo | array(string) | Array of URLs to logo images to use.
following | array(string) | Array of URLs of other sites `endpoint` to follow.
known | array(string) | Array of known endpoints found through crawling, starting from endpoints in `following`.
blacklist | array(string) | Array of hostnames to blacklist and not crawl.
boards | array(<a href='#webring-json-board'>Webring Board</a>) | Array of webring-listed board on this site in webring format.
## Webring.json board
> Example webring.json board
```json
{
"uri": "t",
"title": "Meta",
"subtitle": "Fatchan Official",
"path": "https://fatchan.org/t/",
"postsPerHour": 0,
"postsPerDay": 0,
"totalPosts": 1410,
"uniqueUsers": 0,
"nsfw": false,
"tags": [
"meta",
"t",
"site",
"discussion",
"fatchan",
"/t/",
"/meta/",
"jschan"
],
"lastPostTimestamp": "2021-11-23T01:11:13.122Z"
}
```
A board from webring.json.
Parameter | Type | Description
--------- | ---- | -----------
uri | string | The uri of the board on this site.
title | string | The board title/name.
subtitle | string | The board subtitle.
path | string | Full URL of the board.
postsPerHour | number | Number of posts made per hour on this board.
postsPerDay | number | Number of posts made per day on this board.
totalPosts | number | The total number of posts ever made on this board.
uniqueUsers | number | The number of unique user IP/IDs that have posted on this board in the past 24 hours.
nsfw | boolean | Whether the board is nsfw (not safe for work).
tags | array(string) | List of tags for the board.
lastPostTimeStamp | string | ISO format date string of when the last post was made on the board.
# Miscellaneous
## Time format string
Some moderation interfaces, for example the ban duration when moderating posts, or the ban duration for post filtering use a shorthand for times/length. This format supports years, months, weeks, days, hours, minutes and seconds.
An input of "3mo" would mean 3 months and "1y2mo3w4d5h6m7s" would mean 1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes and 7 seconds. Units of time should be in descending order, so "2w1mo" is invalid.
However you may use "6w" for example to input 6 weeks, and are not required to use "1mo2w".