Communities
Joinable groups / subreddits + join lifecycle.
This is not the live API. This page documents an earlier, in-browser mock API (routes like /accounts, /messaging and /brand), kept for reference. The real, read-only API that runs today is described in The API.
Communities — joinable groups and subreddits
Communities are the catalog of Facebook groups, X lists, and subreddits you can listen in. The catalog is static; what mutates is the join relation (none → pending → accepted) plus the attached Facebook accountId and entry-question answers. All 7 routes serve the Groups page and every keyword scope picker.
Facebook groups gate on a connected Facebook account + answers to every entryQuestions; other platforms auto-accept. Pasted URLs are registered as new rows. Mock admin accept flips pending to accepted. Code: apps/web/src/lib/communities/server.ts and mock.ts.
GET /communities — List communities
Lists the full catalog plus any client-resolved rows (from pasted Facebook links or typed subreddits) materialized with current joinState (none/pending/accepted), accountId for Facebook joins, and accountLabel. Optional ?platform=facebook|x|reddit filters server-side. This is the source for the Groups page and every keyword/listings scope picker. Code: apps/web/src/lib/communities/server.ts:180
POST /communities/{id}/join — Join community
Attempts to join :id. Facebook requires accountId of a connected Facebook account and answers matching every entryQuestions — missing/blank answers or wrong platform account returns 400. Facebook transitions to pending (awaits admin accept), other platforms (reddit/x) auto-set accepted. Already pending/accepted is a no-op 200. Persists to localStorage. Code: apps/web/src/lib/communities/server.ts:186
POST /communities/join-by-url — Join community by URL
Parses a facebook.com/groups/… URL via parseFacebookGroupUrl, registers it as a new catalog row if unseen (registerBase), then runs the same Facebook join transition (account + answers). Dedupes by URL — already tracked rows return 200. Registers unknown URLs before joining so pasted links become first-class communities. Code: apps/web/src/lib/communities/server.ts:201
POST /communities/resolve — Resolve community URL
Resolves a pasted Facebook group URL into its Community without changing joinState. Registers unknown URLs as new rows so the form can read entryQuestions before the user answers. Persists the catalog even though no join occurs — it's a read-ahead for the join form. Code: apps/web/src/lib/communities/server.ts:218
POST /communities/resolve-reddit — Resolve Reddit community
Resolves a typed r/name (via parseSubredditName) into its Community and immediately marks it accepted — subreddits have no entry gate, so a resolved row is instantly usable as a keyword scope. Creates a new row via communityFromSubreddit if unseen. Code: apps/web/src/lib/communities/server.ts:232
POST /communities/{id}/accept — Accept pending join
Mock admin accept — transitions :id from pending → accepted. Simulates the group admin approving the join request in the Groups page 'Approve' action and tests. Returns 400 No join request to accept if state is none, 404 if unknown id. Code: apps/web/src/lib/communities/server.ts:248
DELETE /communities/{id} — Leave community
Leaves :id — resets its joinState to none, clears accountId and answers. The catalog row stays (so pasted links remain) but is no longer a member and cannot scope keywords/listings. Persists. Code: apps/web/src/lib/communities/server.ts:261
List communities
Lists the full catalog plus any client-resolved rows (from pasted Facebook links or typed subreddits) materialized with current joinState (none/pending/accepted), accountId for Facebook joins, and accountLabel. Optional ?platform=facebook|x|reddit filters server-side. This is the source for the Groups page and every keyword/listings scope picker. Code: apps/web/src/lib/communities/server.ts:180
/communitiesQuery Parameters
platformstringPlatform filter.
"facebook" | "x" | "reddit"Response Body
Community list.
TypeScript Definitions
Use the response body type in TypeScript.
communitiesRequiredarray<object>curl -X GET "http://localhost:5174/communities?platform=facebook"fetch("http://localhost:5174/communities?platform=facebook")package mainimport ( "fmt" "net/http" "io/ioutil")func main() { url := "http://localhost:5174/communities?platform=facebook" req, _ := http.NewRequest("GET", url, nil) res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities?platform=facebook"response = requests.request("GET", url)print(response.text){
"communities": [
{
"property1": null,
"property2": null
}
]
}Join community
Attempts to join :id. Facebook requires accountId of a connected Facebook account and answers matching every entryQuestions — missing/blank answers or wrong platform account returns 400. Facebook transitions to pending (awaits admin accept), other platforms (reddit/x) auto-set accepted. Already pending/accepted is a no-op 200. Persists to localStorage. Code: apps/web/src/lib/communities/server.ts:186
/communities/{id}/joinRequest Body
application/jsonOptionalaccountIdstringFacebook account id (facebook only).
answersarray<string>Answers to entryQuestions, one per question.
Path Parameters
idRequiredstringCommunity id.
Response Body
Already joined.
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
communitiesRequiredarray<object>Joined (now pending/accepted).
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
communitiesRequiredarray<object>Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
curl -X POST "http://localhost:5174/communities/string/join" \ -H "Content-Type: application/json" \ -d '{ "accountId": "string", "answers": [ "string" ] }'const body = JSON.stringify({ "accountId": "string", "answers": [ "string" ]})fetch("http://localhost:5174/communities/string/join", { body})package mainimport ( "fmt" "net/http" "io/ioutil" "strings")func main() { url := "http://localhost:5174/communities/string/join" body := strings.NewReader(`{ "accountId": "string", "answers": [ "string" ] }`) req, _ := http.NewRequest("POST", url, body) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities/string/join"body = { "accountId": "string", "answers": [ "string" ]}response = requests.request("POST", url, json = body, headers = { "Content-Type": "application/json"})print(response.text){
"community": {
"property1": null,
"property2": null
},
"communities": [
{
"property1": null,
"property2": null
}
]
}{
"community": {
"property1": null,
"property2": null
},
"communities": [
{
"property1": null,
"property2": null
}
]
}{
"error": "string"
}{
"error": "string"
}Join community by URL
Parses a facebook.com/groups/… URL via parseFacebookGroupUrl, registers it as a new catalog row if unseen (registerBase), then runs the same Facebook join transition (account + answers). Dedupes by URL — already tracked rows return 200. Registers unknown URLs before joining so pasted links become first-class communities. Code: apps/web/src/lib/communities/server.ts:201
/communities/join-by-urlRequest Body
application/jsonRequiredurlRequiredstringFacebook group URL.
accountIdstringanswersarray<string>Response Body
Already tracked.
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
communitiesRequiredarray<object>Joined.
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
communitiesRequiredarray<object>Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
curl -X POST "http://localhost:5174/communities/join-by-url" \ -H "Content-Type: application/json" \ -d '{ "url": "string", "accountId": "string", "answers": [ "string" ] }'const body = JSON.stringify({ "url": "string", "accountId": "string", "answers": [ "string" ]})fetch("http://localhost:5174/communities/join-by-url", { body})package mainimport ( "fmt" "net/http" "io/ioutil" "strings")func main() { url := "http://localhost:5174/communities/join-by-url" body := strings.NewReader(`{ "url": "string", "accountId": "string", "answers": [ "string" ] }`) req, _ := http.NewRequest("POST", url, body) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities/join-by-url"body = { "url": "string", "accountId": "string", "answers": [ "string" ]}response = requests.request("POST", url, json = body, headers = { "Content-Type": "application/json"})print(response.text){
"community": {
"property1": null,
"property2": null
},
"communities": [
{
"property1": null,
"property2": null
}
]
}{
"community": {
"property1": null,
"property2": null
},
"communities": [
{
"property1": null,
"property2": null
}
]
}{
"error": "string"
}Resolve community URL
Resolves a pasted Facebook group URL into its Community without changing joinState. Registers unknown URLs as new rows so the form can read entryQuestions before the user answers. Persists the catalog even though no join occurs — it's a read-ahead for the join form. Code: apps/web/src/lib/communities/server.ts:218
/communities/resolveRequest Body
application/jsonRequiredurlRequiredstringFacebook group URL.
Response Body
Resolved.
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
curl -X POST "http://localhost:5174/communities/resolve" \ -H "Content-Type: application/json" \ -d '{ "url": "string" }'const body = JSON.stringify({ "url": "string"})fetch("http://localhost:5174/communities/resolve", { body})package mainimport ( "fmt" "net/http" "io/ioutil" "strings")func main() { url := "http://localhost:5174/communities/resolve" body := strings.NewReader(`{ "url": "string" }`) req, _ := http.NewRequest("POST", url, body) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities/resolve"body = { "url": "string"}response = requests.request("POST", url, json = body, headers = { "Content-Type": "application/json"})print(response.text){
"community": {
"property1": null,
"property2": null
}
}{
"error": "string"
}Resolve Reddit community
Resolves a typed r/name (via parseSubredditName) into its Community and immediately marks it accepted — subreddits have no entry gate, so a resolved row is instantly usable as a keyword scope. Creates a new row via communityFromSubreddit if unseen. Code: apps/web/src/lib/communities/server.ts:232
/communities/resolve-redditRequest Body
application/jsonRequirednameRequiredstringSubreddit name, e.g. r/test or test.
Response Body
Resolved + joined (accepted).
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
curl -X POST "http://localhost:5174/communities/resolve-reddit" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'const body = JSON.stringify({ "name": "string"})fetch("http://localhost:5174/communities/resolve-reddit", { body})package mainimport ( "fmt" "net/http" "io/ioutil" "strings")func main() { url := "http://localhost:5174/communities/resolve-reddit" body := strings.NewReader(`{ "name": "string" }`) req, _ := http.NewRequest("POST", url, body) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities/resolve-reddit"body = { "name": "string"}response = requests.request("POST", url, json = body, headers = { "Content-Type": "application/json"})print(response.text){
"community": {
"property1": null,
"property2": null
}
}{
"error": "string"
}Accept pending join
Mock admin accept — transitions :id from pending → accepted. Simulates the group admin approving the join request in the Groups page 'Approve' action and tests. Returns 400 No join request to accept if state is none, 404 if unknown id. Code: apps/web/src/lib/communities/server.ts:248
/communities/{id}/acceptPath Parameters
idRequiredstringCommunity id.
Response Body
Accepted.
TypeScript Definitions
Use the response body type in TypeScript.
communityRequiredobjectCommunity — joinable group / subreddit.
communitiesRequiredarray<object>Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
curl -X POST "http://localhost:5174/communities/string/accept"fetch("http://localhost:5174/communities/string/accept")package mainimport ( "fmt" "net/http" "io/ioutil")func main() { url := "http://localhost:5174/communities/string/accept" req, _ := http.NewRequest("POST", url, nil) res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities/string/accept"response = requests.request("POST", url)print(response.text){
"community": {
"property1": null,
"property2": null
},
"communities": [
{
"property1": null,
"property2": null
}
]
}{
"error": "string"
}{
"error": "string"
}Leave community
Leaves :id — resets its joinState to none, clears accountId and answers. The catalog row stays (so pasted links remain) but is no longer a member and cannot scope keywords/listings. Persists. Code: apps/web/src/lib/communities/server.ts:261
/communities/{id}Path Parameters
idRequiredstringCommunity id.
Response Body
Remaining communities.
TypeScript Definitions
Use the response body type in TypeScript.
communitiesRequiredarray<object>Failure envelope returned with 4xx statuses.
TypeScript Definitions
Use the response body type in TypeScript.
errorRequiredstringHuman-readable failure reason, e.g. "A key needs a name".
curl -X DELETE "http://localhost:5174/communities/string"fetch("http://localhost:5174/communities/string")package mainimport ( "fmt" "net/http" "io/ioutil")func main() { url := "http://localhost:5174/communities/string" req, _ := http.NewRequest("DELETE", url, nil) res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "http://localhost:5174/communities/string"response = requests.request("DELETE", url)print(response.text){
"communities": [
{
"property1": null,
"property2": null
}
]
}{
"error": "string"
}