Run a community with a server list, forum and guides
Serve a server list, a forum, guides and your Discord chat on your storefront, and moderate what your customers post.
Your storefront can host a community for your customers and their players: a list of your customers' servers, a forum, a library of guides, and the public channels of your Discord server. Visitors read all of it without signing in. Customers post with their own token, and your team moderates what they post in the staff console.
Every route on this page is under https://api.coritan.com/api/v1/orgs/{org_slug}. With the API says which credential each group of routes takes.
Before you begin
Section titled Before you begin- To show your Discord chat, connect a Discord bot to your organization as Connect a Discord server describes. That needs the
owneroradminrole. - To let customers post, sign them in as Sign customers in to your storefront describes.
- To moderate, a member needs Tier 1 support or a higher role. Moderate the community lists the lowest role for each task.
Turn the community on
Section titled Turn the community onCoritan turns the server list, the forum and the guides on for your organization, and sets their options, such as the forum's boards, the tags a server can carry, the length limits and the limits on images. You turn the chat on yourself.
- Ask support to turn on the parts you want. Until a part is on, its routes answer
404. - To show your Discord chat, go to Organizations, open your organization, choose Growth, then Discord. On the Community chat card, tick Mirror public channels on the storefront, then choose Save changes. Connect the bot covers the Invite link and Hidden channels fields.
- Read
GET /storefront/branding, and check that each part you asked for hasenabled: truein its block.
Build the community pages
Section titled Build the community pagesGET /storefront/branding carries a block for each part, with what your pages need to show it. Read the switches and limits from it rather than writing them into your site, because Coritan can change them. Show your brand covers the rest of the answer.
| Block | What it holds |
|---|---|
public_server_list |
enabled, the path_prefix your site serves the community under, the categories and editions a server is listed under, the tags a customer can choose and max_tags. |
community_forum |
enabled and the forum's paths, such as forum_base and profile_base. Switches for what members can do: allow_customer_threads, allow_customer_replies, nested_replies, voting_enabled, downvotes_enabled, reactions_enabled, solutions_enabled, wall_enabled, member_directory_enabled and profile_images_enabled. Limits: max_body_chars, max_bio_chars, max_tags, max_reply_depth and bump_cooldown_hours. Lists: reactions, thread_kinds, report_categories, roles and role_labels. |
community_knowledgebase |
enabled and guides_base, the categories and difficulties a guide can take, the switches comments_enabled, allow_customer_contrib, helpful_votes_enabled and allow_cover_images, and the limits max_body_chars, max_summary_chars and max_tags. |
community_media |
Whether members can add images (uploads_enabled), the largest file in max_upload_mb, the file types in accept, and whether we copy images that posts link to on other sites (store_linked_images). Add images describes them. |
community_chat |
enabled, and the invite_url of your Discord server. |
GET /storefront/community/overview returns a community home page in one call: stats, servers, guides, forum, members and chat, with the counts and names a hub shows. It carries no images, so the page can paint at once. Add include=pages to get the first page of each tab as well, 24 items each, with their images.
GET /storefront/community/stats returns the counters on their own, for a live figure:
| Field | What it counts |
|---|---|
total_active_servers |
The servers running now. It is the number the staff console's Running tile shows with the audience switch on All, as Manage customer servers in the staff console describes. |
total_players |
The players connected to those running servers. |
total_servers |
The servers that have not been cancelled or terminated. |
total_servers_created |
Every server ever ordered. |
total_accounts |
The active customer accounts. |
Each counts your organization's own servers and customers. The same five fields are in stats on GET /storefront/community/overview.
total_active_servers and total_players are at most a few seconds old. We count total_servers, total_servers_created and total_accounts once a minute, so they can be up to about a minute and a half old. Asking more often than every three seconds returns the same figures.
List your customers' servers
Section titled List your customers' serversThe server list shows the servers your customers choose to list, each with a page of its own. The customer who owns the service creates its listing with their token.
Read the listing with
GET /portal/services/{service_id}/community-listing, whereservice_idis the service'sidfromGET /portal/services.feature_enabledsays whether the list is on. The answer holds theeditions,tagsandmax_tagsto offer, the server'sjoin_addressandplayers_online, the server's live status (live_motd,players_max,version_name,observed_atandonline, described under Show the server list), and thelisting, which isnulluntil the first save.Save the listing:
Shellcurl -X PUT "https://api.coritan.com/api/v1/orgs/acme/portal/services/41/community-listing" \ -H "Authorization: Bearer $CUSTOMER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"display_name": "Survival SMP", "slug": "survival-smp", "tagline": "Vanilla survival with land claims", "tags": ["survival"], "published": true}'The first save creates the listing from every field. Later saves change only the fields you send.
Show the customer their listing at
listing.public_path, such as/community/servers/survival-smpon your site.
These two routes replace GET and PATCH /portal/servers/{uuid}/listing, which are deprecated and may stop answering after 31 March 2027.
| Field | What it takes |
|---|---|
display_name |
Up to 120 characters. A new listing takes the service's hostname when you leave it out. |
slug |
The listing's address: 2–80 lowercase letters, digits and hyphens, unique in your organization. We make one from display_name when you leave it out. |
tagline, description |
Up to 200 and 8,000 characters. |
category |
One of the editions. Left out, it follows from the tags. |
tags |
Tags from your list, up to max_tags. |
website_url, discord_url |
http or https addresses, up to 500 characters. |
icon_data_uri, banner_data_uri, gallery |
PNG images as data URIs: an icon of up to 120,000 characters, a banner of up to 400,000, and up to 4 gallery images of up to 400,000 each. |
seo_title, seo_description |
The listing page's title and description for search engines. We keep the first 160 and 320 characters. |
show_player_count |
false hides how many players are online. It defaults to true. |
published |
true puts the listing on the public list. |
A listing can be published once it has at least one tag. When the answer's require_gameproxy is true, the server also needs a working join address. The listing shows the server's join address, or its custom domain when the owner linked one with include_in_list set, as Link a custom domain describes.
A server's own panel has a shorter switch for the same listing, which List the server in your directory covers. External servers can be listed too, and show the players they reported at their last status check.
When your staff hold or hide a listing, moderation in the answer is held or hidden, and the listing stays off the public list whatever published says.
Show the server list
Section titled Show the server listGET /storefront/community/servers lists the published listings for anyone:
curl "https://api.coritan.com/api/v1/orgs/acme/storefront/community/servers?tag=survival&sort=players"
Filter with q, category and tag, sort with sort (players, rating or newest), and page with page and page_size (1–100, 24 by default). GET /storefront/community/servers/{listing_slug} returns one listing. Each carries its join_address, players_online (null when the owner hides it), online, featured, average_rating and total_ratings. boosted is true when the server's boost level unlocks the Boosted badge (see Boost levels), so show a badge on its card. The first page of cards in GET /storefront/community/overview?include=pages carries boosted too.
Each hosted server's card also carries what the edge last saw when a player's game asked the server for its status:
| Field | What it holds |
|---|---|
online_motd |
The owner's online MOTD override from the join address's Server list tab. It is empty unless the owner set one. |
live_motd |
The server's own MOTD as the edge last saw it, with its § formatting codes. null until the edge has seen the server. |
players_max |
The player limit the server reported. |
version_name |
The version text the server reported. |
observed_at |
When the edge saw it, as a UTC time such as 2026-09-21T11:59:00Z. null until then. |
online |
true when the edge saw the server answer in the last three minutes, so a server with nobody on still counts as online. Before the edge has seen the server, online is true while players are connected. |
A card shows the owner's online_motd first when it has visible text, then live_motd. A MOTD made only of formatting codes has no visible text. The live line stays on a card after the server stops answering, with online set to false. The same fields appear on the owner's GET /portal/services/{service_id}/community-listing, and on each card of GET /storefront/community/overview?include=pages. Servers listed from another directory carry no live status: they have online_motd and online, but not live_motd, players_max, version_name or observed_at, so read those as null. Their online is true when that directory reports the server online or players are connected.
A signed-in customer rates a listing with POST /storefront/community/servers/{listing_slug}/rate and a rating from 1 to 5. A second rating replaces the first. Send the customer's token with GET /storefront/community/servers/{listing_slug}, and the answer includes their own rating as user_rating.
A server listed from another directory has source set to legacy and cannot be rated: the rate route answers 400 with This listing cannot be rated. Show its average without stars to pick, with a line saying that listing takes no ratings. When a signed-out visitor picks a star on a listing that takes ratings, send them to sign in and back to the listing.
Run the forum
Section titled Run the forumThe forum has boards of threads, and each thread is a discussion, question, announcement or showcase. Coritan sets up your boards when it turns the forum on. With none set, the forum has six: Announcements, where only forum administrators post, Help & Support, Guides & Tutorials, Server Showcase, Suggestions, and Off Topic, which search engines do not index. Votes, reactions, accepted answers, nested replies, the member directory and profile walls each have a switch in the community_forum block.
When a board is no longer used, Coritan can retire it for you. A retired board stays readable, but it takes no new threads, and only your forum staff can reply in it. Its board, and the category of each of its threads, carry retired: true and replaced_by, which says where readers go now: {"section": "guides"} for your guides, or another board's board, name and url. Show a notice on the board and its threads that says so and links there.
Read the forum
Section titled Read the forumThese routes need no token, and the lists take page and page_size:
| Route | What it returns |
|---|---|
GET /storefront/community/forum |
The boards, with the counts a forum's front page shows. |
GET /storefront/community/forum/boards/{category_slug} |
A board's threads. sort is hot (the default), new, top, active or unanswered, and q, tag and kind narrow the list. |
GET /storefront/community/forum/threads |
Threads from every public board. filter is latest or unanswered. |
GET /storefront/community/forum/threads/{category_slug}/{thread_slug} |
A thread and its replies. sort is best (the default), new, old or top. |
GET /storefront/community/forum/search |
Threads and replies whose title or text matches q, 2–120 characters. scope is all, threads or posts. |
GET /storefront/community/forum/tags |
The tags in use, busiest first. .../tags/{tag} lists the threads with one tag. |
GET /storefront/community/members |
The member directory, when it is on. sort is posts, threads, solutions, reactions, newest or active. |
GET /storefront/community/members/{handle} |
A member's profile. .../activity lists their threads, replies or accepted answers by kind, and .../wall their wall. |
Threads moved from your old site's forum keep their authors. An author who has not moved their own account yet is a placeholder: their profile, activity and threads stay readable, but the member directory and member counts leave them out, their wall is empty and takes no posts, and search engines never index their page. Link your old site to your storefront covers the move.
Post in the forum
Section titled Post in the forumPosting takes the customer's token, and the routes are under /portal/community/forum/. Bodies are Markdown, up to max_body_chars, and a member mentions another with @ and their handle. POST /storefront/community/forum/preview renders a draft as your site will show it, with the members it mentions in mentions.
| Route | What it does |
|---|---|
POST /threads |
Starts a thread from category_slug, title (3–200 characters), body_markdown, kind and tags. |
POST /threads/{thread_id}/posts |
Replies with body_markdown. With nested replies on, parent_post_id answers one reply. |
PUT /threads/{thread_id}, PUT /posts/{post_id} |
Edits the member's own thread or reply, with an optional edit_reason. |
DELETE /threads/{thread_id}, DELETE /posts/{post_id} |
Deletes the member's own thread or reply. Forum staff can delete anyone's, and only a forum administrator can delete a locked thread. |
POST /posts/{post_id}/vote |
Votes with value from -1 to 1. |
POST /posts/{post_id}/react |
Reacts with a reaction_type from reactions. |
POST /threads/{thread_id}/solution?post_id=... |
Accepts a reply as the answer. The thread's author and forum staff can, and DELETE clears it. |
POST /threads/{thread_id}/bump |
Moves the author's thread back to the top, once every bump_cooldown_hours. |
POST /threads/{thread_id}/subscription |
Follows a thread, or stops following it. GET /subscriptions lists followed threads with their unread posts. |
POST /reports |
Reports a thread, a post or a member, named by thread_id, post_id or handle in the query. The body takes a category from report_categories and a reason of up to 500 characters. |
GET /portal/community/forum/me returns the member's handle and forum role, their unread followed threads and, for forum staff, the number of open reports.
PUT /portal/community/profile changes the member's profile: display_name (2–64 characters), biography (up to max_bio_chars), location (up to 64), website_url and signature (up to 300 each), avatar_data_uri and banner_data_uri when profile images are on, wall_enabled and index_opt_out. The picture fields take the url of an image the member added with purpose set to forum_avatar or forum_banner (see Add images), a PNG, JPEG or WebP data URI, which we store the same way, or an empty string to remove it. A wall is where members post on each other's profiles. POST /portal/community/members/{handle}/wall takes up to 2,000 characters, and POST /portal/community/wall/{wall_post_id}/comments comments on a wall post. A member can write 20 wall posts and 60 wall comments an hour.
Publish guides
Section titled Publish guidesGuides are articles written in Markdown, each with a page under guides_base. Customers write them when allow_customer_contrib is on, and a moderator approves each one before it goes live.
Read guides
Section titled Read guidesGET /storefront/community/guideslists published guides. Filter withq,category,taganddifficulty, sort withsort(views, the default,newest,featuredorhelpful), and page withpageandpage_size. A tag matches only its exact spelling, capitals included. Guides withfeaturedset come first in every sort, andfeaturedorders the rest newest first, so a featured guide stays at the top of your guides page.GET /storefront/community/guides/{slug}returns one guide incontent, with itshelpfulvotes,relatedguides andview_count. Views by the author and by moderators do not count.GET /storefront/community/guides/{slug}/commentslists a guide's comments. A signed-in customer comments withPOSTandbody_markdown, up to 4,000 characters. When your guides hold comments for approval, a new comment'sstatusispendinguntil a moderator approves it.POST /storefront/community/guides/{slug}/helpfulwithhelpfulset totrueorfalserecords the customer's vote, one per customer.POST .../guides/{slug}/reportreports the guide, or one comment withcomment_id, with areasonof up to 500 characters.
Write a guide
Section titled Write a guide- Create the guide as the customer with
POST /portal/community/guides/articles. It needstitle, up to 200 characters, andbody_markdown, up tomax_body_chars.slug,summary,category,difficulty,tags,game_slug,cover_url,seo_titleandseo_descriptionare optional.cover_urlis theurlof an image the customer added withpurposeset toguide_cover(see Add images).cover_data_uristill takes a PNG of 128 KB or smaller as a data URI, which we store the same way. The guide is saved as adraft, andsubmitset totruesends it for review at once. - When the draft is ready, send it for review with
PUT /portal/community/guides/articles/{article_id}. An edit is submitted unless it carriessubmit: false. Itsproposal_statusbecomespending, and we notify your guide moderators. - A moderator publishes the guide, asks for changes, or rejects it (Review guides). Publishing puts the guide at its
public_path. Asking for changes and rejecting both leave the guide with the customer, with the moderator's note, and the customer can edit the guide and submit it again.
Changing a published guide works the same way: the live version stays up until a moderator publishes the proposed one. GET .../articles/{article_id}/diff returns the live and proposed versions with the diff between them, and POST .../articles/{article_id}/proposal/withdraw takes a proposal back.
GET /portal/community/guides/articles lists the customer's guides with their status (draft, published or archived) and proposal_status (none, pending, changes_requested or rejected). Each guide also carries review_decision and review_note, from its latest review, and rejection_reason while it was rejected. GET .../articles/{article_id} adds reviews, every review newest first, each with decision, note and created_at. A review never names the moderator, so show it as the moderation team. GET /portal/community/guides/notifications returns the customer's 50 latest notifications. A decision sends one of proposal_approved with a note, proposal_changes_requested with a note, or proposal_rejected with a reason.
On the storefronts we build with a community, a customer sees each decision in three places. A decision adds a line to the Updates block under the list on My articles (/community/guides/mine), with the moderator's note. A guide that was sent back shows the chip Changes requested or Not accepted beside its name, with the note under it, and is listed under the Sent back filter. And the guide's editor shows the note at the top until the customer submits the guide again. We also email the author each decision with the note.
POST /storefront/community/guides/preview renders Markdown as a guide will show it, with its table of contents in toc. A link keeps its address only when it is http or https or starts with / or #, and an image only when it is an http or https address, a path on your storefront that starts with a single /, or a PNG data URI.
Caution
DELETE /portal/community/guides/articles/{article_id} deletes the customer's guide in any state, with every revision, comment, vote and report. It cannot be undone.
Add images
Section titled Add imagesEvery image in your guides and your forum is stored on Coritan's storage: covers, images in guides, guide comments, forum posts, wall posts and bios, and avatars and banners. We serve each one from your own storefront at a path under /media/, so an image keeps working when your storefront's address changes.
A signed-in customer adds an image in one of two ways, and both answer the same image:
POST /portal/community/mediauploads a file, sent asmultipart/form-datawithfileandpurpose.POST /portal/community/media/linkcopies an image from another site. Sendurlandpurposeas JSON. We fetch it once and store our own copy, so the image keeps working when the other site deletes it.
purpose says where the image goes: guide_image or guide_cover for a guide, forum_image for a thread, reply or wall post, and forum_avatar or forum_banner for the customer's profile. The answer's url is a path such as /media/4ksx…-1600x900.webp. Put it in Markdown as , in a guide's cover_url, or in the profile's avatar_data_uri or banner_data_uri. The answer also carries width, height, bytes, preview (a small copy for a thumbnail) and token.
What we store:
- PNG, JPEG, WebP and GIF files of up to
max_upload_mb(10 MB unless Coritan changed it) and 48 megapixels. We refuse SVG files. - Every image is decoded and stored again as WebP, at most 1600 pixels on its longest side, without the camera's metadata. We crop avatars to 256 × 256 and banners to 1200 × 400. An animation stays animated, at most 800 pixels and 300 frames.
- Smaller copies are ready for any page: add
~and a width of 64, 128, 320, 480, 640, 800, 960 or 1280 before.webp, such as/media/4ksx…-1600x900~640.webp. The guide and forum HTML the API renders already gives each stored image itswidth,heightand asrcsetof these copies. - The same file added twice by your customers is one image. Avatars and banners are each customer's own.
Each customer can add 30 images an hour and 150 a day, links included, and keep 250 MB of images. GET /portal/community/media lists the customer's 24 newest images with the space they use in used_bytes and quota_bytes, and DELETE /portal/community/media/{token} deletes one that no saved guide, post or profile uses. We delete an image that nothing used 48 hours after it was added, so an image in a saved draft stays.
When a guide goes live, or a customer saves a post or a comment, we copy each image it links to on another site and point the link at our copy. A link we cannot copy stays as it was. Images in code blocks are never copied.
A refused request answers with a detail to show and a code:
code |
Status | Why |
|---|---|---|
uploads_off |
403 | Your organization takes no images, or not for that purpose. |
suspended |
403 | The customer is suspended or muted in the forum. |
too_large, too_many_pixels |
413 | The file is over the size or pixel limit. |
not_an_image |
415 | The file is not a PNG, JPEG, WebP or GIF image. |
link_failed |
422 | The link did not give us an image; detail says what happened. |
rate_limited |
429 | The customer added too many images this hour or today. |
quota, blocked, in_use |
409 | The customer's space is full, your staff removed that file, or the image to delete is in use. |
storage_unavailable |
503 | Storage cannot take images right now. Try again later. |
On the storefronts we build with a community, the guide editor, the forum composer and the wall have an Image button. It opens a dialog where a customer uploads a file, gives a link, or picks one of their own images again. A customer can also paste or drop an image onto the text. Images your community stored before they lived on Coritan's storage (inline covers and pictures, links to other sites) move with a job Coritan runs for you: ask support.
Show your Discord chat
Section titled Show your Discord chatThe chat mirrors your Discord server's public channels on your site. Anyone can read them, and a signed-in customer's messages appear in Discord under their username. Your team moderates it on the staff console's Chat page, as Moderate the community chat describes.
- A channel appears when Discord lets
@everyoneread it and send messages in it, unless it is in Hidden channels or your team hid it on the Chat page. Ticket channels never appear. We check the channels regularly and each time you save the Discord settings, and Sync community channels checks them now. A channel you delete in Discord disappears from the chat within a minute, along with the messages we kept from it. GET /storefront/community/chat/channelslists the channels bychannel_id,name,topicandslowmode_seconds, with theinvite_url, the longest message inmax_lengthand the default slow mode inrate_limit_secondsandrate_limit_hint. It also carriesposting(open, orpausedwhile your team has paused web chat), thepause_notice, your chat'srules, thelinkspolicy, thereport_reasonsa reader can pick, anddiscord, your server'sname,member_countandonline_countonce the bot has read them (each may benull).GET /storefront/community/chat/messagesreturns the latest messages of the channel inchannel_id:limitof them (1–100, 50 by default), or older ones withbefore_id. To poll, sendafter_idset to thelatest_idof the last answer, and you get only what is new. A message your team hid or someone deleted is never in it.GET /storefront/community/chat/statusreturns the customer'shandle, the seconds before they can send again inchannel_idincooldown_seconds, andmuted_seconds.can_postisfalsewhen the customer cannot post at all, andblockedthen holds thecode, themessageto show andretry_after_seconds.can_reportsays whether they can report messages.
Each message carries author_kind (discord, or customer for a message sent from your site), author_name, author_avatar_url, body and created_at, and:
| Field | What it holds |
|---|---|
author_badge |
staff for a message from your team, otherwise null. Only the Discord role in Staff role ID, a staff link, or managing your server when you set no staff role, earns it. |
mentions |
The names behind the <@id>, <@&id> and <#id> tokens in body, as users, roles and channels, or null. Only public channels are named. |
attachments |
Each attachment or sticker's kind (image, video, audio, file or sticker) and name. We never store the file or its address. |
reply |
The message this one answers: its id, author_name and a plain-text excerpt, or missing: true when it was removed. null for a message that answers nothing. |
jump_url |
The message in Discord, or null. |
edited_at |
When it was last edited, or null. |
body is Discord's own text, with its Markdown and tokens such as <:emoji:id> and <t:1759920000:R>. The storefronts we build render it as Discord does.
The bot leaves out of the mirror: messages from bots and webhooks, system messages such as joins and pins, a bot command typed as text (a message that starts with / or ! and a word, unless you turn that off), a Discord account your team blocked, and anything the moderation filter refuses. We keep up to 500 messages per channel, none older than 30 days.
Send from your site
Section titled Send from your sitePOST /storefront/community/chat/send sends body, up to 500 characters, to channel_id, as the signed-in customer. Send a client_nonce of your own, up to 64 characters, so that a retry returns the first message instead of sending a second, and reply_to_id to answer a message in the same channel. A message from your site reaches Discord through a webhook, under the customer's username; when the bot lacks Discord's Manage Webhooks permission, it posts the message itself, with the username in front. A reply opens with a line that links to the message it answers.
The send answers the message as the messages list shows it, or refuses with a detail to show and a code. The checks run in this order:
code |
Status | Why |
|---|---|---|
chat_paused |
403 | Your team paused web chat. detail is their notice. |
chat_banned |
403 | Your team banned the account from the chat, or the network it posts from. |
chat_muted |
429 | The account is muted. Retry-After gives the seconds left. |
verify_email |
403 | Your chat asks for a verified email address. |
account_too_new |
403 | Your chat asks new accounts to wait. Retry-After gives the seconds left. |
slow_mode |
429 | The customer sent a message less than the channel's slow mode ago (8 seconds unless your team changed it). |
address_busy |
429 | 20 messages in a minute came from the customer's network. |
channel_busy |
429 | 40 messages from your site reached the channel in 30 seconds. |
invalid_message |
422 | The message is empty, over 500 characters, or carries a Discord invite. |
duplicate |
422 | The customer sent the same words in the channel in the last 10 minutes. |
links_not_allowed |
422 | The message links to a site your chat's link policy does not allow. By default only your storefront's own sites and the sites your team trusts. |
reply_gone |
422 | The message in reply_to_id was removed, or is in another channel. |
filtered |
422 | The moderation filter refused the text. |
Report and delete messages
Section titled Report and delete messagesPOST /storefront/community/chat/messages/{message_id}/report reports a message to your team, as the signed-in customer, with a reason (spam, scam, harassment, hate, sexual or other) and an optional note of up to 300 characters. It answers {"ok": true, "already_reported": false, "hidden": false}. One account reports a message once, and sends 10 reports an hour at most. A customer who cannot post cannot report either, except while web chat is paused. When enough different customers report a message, hidden is true and the message leaves the chat until your team looks.
DELETE /storefront/community/chat/messages/{message_id} deletes the customer's own message from your site, from the website and from Discord, 20 a minute at most. discord_removed is false when Discord did not confirm, and the message may then stay in Discord until your team deletes it there.
Customer names in the community
Section titled Customer names in the communityPosts, messages and profiles show each customer's username, which the community calls their handle. Register a customer gives its rules, and PATCH /auth/me with chat_handle changes it. While a signed-in customer types a new one, GET /storefront/community/handle-available?handle=... answers available, with the reason when it is not. In the forum, a member can also set a display_name, which cannot be another member's handle.
Moderate the community
Section titled Moderate the communityYour team moderates on the staff console's community page at /staff/community, which works through the staff routes under /staff/community/. GET /staff/community/summary counts what is waiting. The lowest role for each task:
| Task | Lowest role |
|---|---|
| Read forum reports and server listings | Tier 1 support |
| Dismiss a report, quarantine what it points at, or mute its author for up to 7 days | Tier 1 support |
| Hold a listing for review | Tier 1 support |
| Restore or remove reported content | Tier 2 support |
| Hide, show, release or delete a listing | Tier 2 support |
| Pin, lock or hide a thread | Tier 3 support |
| Find members, change their forum role and suspend them | Tier 3 support |
| Review guides, guide comments and guide reports | Tier 3 support |
| Feature a listing, or mute for longer than 7 days | Tier 3 support |
| See the community's images | Tier 1 support |
| Remove an image | Tier 2 support |
| Add or remove guide moderators | Admin |
Billing, Admin and Owner can do everything Tier 3 support can. Every action goes on the audit log with a name that starts with community., such as community.content_removed or community.listing_held. The chat has a page of its own, with its own roles: Moderate the community chat.
Work through forum reports
Section titled Work through forum reportsGET /staff/community/forum/reports lists the open reports, and status set to quarantined, resolved or all shows the others. Each report names the member behind the content and whether they are muted. Every open report on the same content moves with the one you act on.
POST /staff/community/forum/reports/{report_id}/resolvedismisses the report, with an optionalresolution, and leaves the content as it is.POST .../quarantinehides the content, with an optionalnote, until Tier 2 support decides..../restoreputs it back, and.../removedeletes it.POST .../removealso works on content that is still up. The content leaves every list and search engines, and we keep it for the record.POST .../mutewithhoursand an optionalreasonstops the author posting in the forum and the chat. A longer mute already running stays as it is. To lift a mute, or set one in minutes, use/chat-muteas Change the account describes.
Forum members and roles
Section titled Forum members and rolesEvery member holds a forum role. Customers hold member, premium, supreme or ultimate, and the staff roles above them are support, supervisor, architect and administrator, from the lowest. role_labels in the branding block holds the name your site shows for each.
GET /staff/community/forum/membersfinds members:qmatches a handle or an email address, andonlyisall,stafforsuspended.assignablelists the roles you can give.POST /staff/community/forum/members/{handle}/rolewithrolechanges a member's role.POST /staff/community/forum/members/{handle}/suspendwithsuspendand areasonof up to 300 characters suspends a member.suspendset tofalselifts it and gives back their earlier role.
In the forum, your staff act as a supervisor: they can give the roles below it, and act on members who hold them. Owners and admins can give any role.
A customer with a staff role moderates from your site with their own token, under /portal/community/forum/moderation/. They read the reports and resolve one with action set to none, remove or suspend. With threads/{thread_id}/flags they pin, lock or move a thread, or mark it as a duplicate of another. They can change the roles of members below their own. Other members get 403 Forum staff only.
Remove an image
Section titled Remove an imageThe Images tab of the staff console's community page lists your community's images, newest first, with who added each one and where it is used. GET /staff/community/media answers the same list: filter with purpose, member (a customer's id) and q, and set status to removed for the images already removed.
POST /staff/community/media/{token}/remove with a reason of up to 300 characters removes an image. We delete it and its smaller copies, stop serving it and clear it from our caches, so the page that showed it shows a broken image until someone edits it. The same file cannot be added again.
Moderate listings
Section titled Moderate listingsGET /staff/community/listings lists every listing with its owner. only is all, published, hidden, held or featured, and q searches.
POST /staff/community/listings/{listing_id}/holdwith areasonof 3–300 characters takes a listing off the list until Tier 2 support decides.PATCH /staff/community/listings/{listing_id}withhiddenand an optionalreasonhides or shows a listing, whatever its owner chose, and ends a hold.featuredputs a listing at the top of the list.POST .../releaseputs a held listing back as its owner left it.
Caution
DELETE /staff/community/listings/{listing_id} deletes the listing and its ratings, and cannot be undone. The owner can list the server again from the start, so hide a listing that should stay off the list.
Review guides
Section titled Review guidesTier 3 support reviews guides in the staff console. Open Moderation under Community in the sidebar, then the Guides queue tab. The Proposed guides panel lists each guide that waits for a decision: its title, its author with New guide or Edit under the title, the author's change note, its status and how long ago it was sent.
Choose Review on a row, or select the row, to open the review drawer. It shows:
- The author, when they sent it, and its category, level and tags. A change note from the author sits under them, and so does the last review when it sent the guide back.
- A Preview tab with the proposed guide as readers will see it: cover, summary and text. A link in the guide opens in a new tab.
- For an edit, a Changes tab. It lists each field that changed, with the live value above the proposed one, then the lines of the guide text, added lines in green and removed lines in red. A long run of unchanged lines folds into a button such as
Show 24 unchanged lines. - A Reviews tab, with a count when there are earlier decisions, listing every earlier decision on the guide: what was decided, the note, who decided and when.
Three buttons in the drawer's footer make the decision, and each opens a dialog:
| Button | What happens | Note |
|---|---|---|
| Publish… | The guide goes live for every visitor under the author's name. For an edit, the proposed version replaces the live one. | Optional, up to 1000 characters. |
| Request changes… | The guide stays as it is, with the author. They can edit it and submit it again. | Required, 3 to 1000 characters. |
| Reject… | The proposal is not accepted. The author can still edit the guide and submit it again. | Required, 3 to 1000 characters. |
We email the author the decision with your note. They also read the note on My articles and in the editor, as Write a guide describes. The author never sees who decided. After a decision the drawer closes, a message names what you did, and the queue and the tab's count update.
The drawer sends the version you read. When the author changed the guide after you opened it, or someone else already decided, the dialog closes and the drawer says This guide changed after you opened it. Reload it to see the new version. Choose Reload to read the new version, then decide again. The three buttons stay dimmed until you reload. A guide with nothing waiting says This guide has nothing waiting for review.
The row's menu holds the same three decisions without opening the drawer, as Publish…, Request changes… and Reject…. Use it when you have already read the guide. Publishing from the menu asks you to confirm and sends no note.
Guide moderators are customers you trust to do the same from your site. An admin adds one with POST /staff/community/guides/moderators and the customer's customer_id, and removes one with DELETE .../moderators/{customer_id}. A moderator works through GET /portal/community/guides/moderation with their own token, and on the storefront's Moderation page at /community/guides/moderation. That page shows each proposal's changes and a Note for the author box that serves all three decisions, with the buttons Approve & apply, Request changes and Reject. The note is optional for Approve & apply and takes 3 to 1000 characters for the other two. Other customers get 403 Moderator access required.
Review guides with the API
Section titled Review guides with the APIGET /staff/community/guides/queuelists the proposals inarticles. Each hasproposed_revision_id,is_new,change_noteandproposal_status, next to its title, author andpublic_path. The queue also listscommentsandreports.GET /staff/community/guides/articles/{article_id}/reviewreturns what the drawer shows:article,is_new,proposed_revision_id,change_note,proposedandlive(each withtitle,summary,body_html,toc,cover,category,tagsanddifficulty, andliveisnullfor a new guide),field_diff,body_diffandreviews.body_diffis a list of{ op, text }lines in order, withopset toequal,insertordelete, and is empty for a new guide.body_htmlis safe to show as it is.POST .../articles/{article_id}/approvetakesrevision_idand an optionalnoteof up to 1000 characters.POST .../rejecttakesrevision_idand areasonof 3 to 1000 characters.POST .../request-changestakesrevision_idand anoteof 3 to 1000 characters. Each answers with the guide's newproposal_status.revision_idisproposed_revision_idfrom the review, and a decision without it, or with a number the guide no longer waits on, is refused.- A refusal because the proposal moved answers
409withThis guide changed after you opened it. Reload it to see the new version.A guide with nothing waiting answers409withThis guide has nothing waiting for review. - A moderator's token does the same under
/portal/community/guides/moderation/articles/{article_id}/:approvewith an optionalnote,rejectwith areasonandrequest-changeswith anote, with the same lengths.revision_idis optional there, and a number that is no longer current answers409. POST /staff/community/guides/comments/{comment_id}/rejectandPOST .../reports/{report_id}/resolvework as before. Rejecting a comment needs areasonof 3 to 500 characters.
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/staff/community/guides/articles/72/request-changes" \
-H "Authorization: Bearer $STAFF_TOKEN" \
-H "Content-Type: application/json" \
-d '{"revision_id": 722, "note": "Add the Spigot steps and say which view distance you tested."}'
These staff routes replace the guide routes under /admin/community/guides/, which are deprecated and may stop answering after 31 March 2027. The staff routes record each decision in the audit log. When you move to them, adding a moderator takes customer_id in place of org_customer_id, the moderator list is a plain array, and a rejection reason needs at least 3 characters.
The moderation filter
Section titled The moderation filterForum posts, guide comments and chat messages go through a moderation filter. Text with a slur is refused with 422. In chat messages and guide comments, other words the filter lists are replaced with asterisks. A customer the chat refuses more than three times in an hour is muted there for an hour. Usernames are held to the same filter. Messages from your Discord server go through it too on their way to your site: a slur is not mirrored, and other words are asterisked on your site only. An admin adds the words your community should not see on the staff console's Chat page, as Add your community's own words to the filter describes.
Keep the forum in search engines
Section titled Keep the forum in search enginesWhen Coritan serves your storefront's site, its sitemap and llms.txt list the forum's best threads. We score each thread and member page, and the score puts it in one of three tiers:
| Tier | What it means |
|---|---|
excluded |
Kept out of search engines. |
index |
In the sitemap, highest scores first. |
llms |
Also in llms.txt, with the accepted answer. It needs a higher score, and an accepted answer or a reply from forum staff. |
A thread scores for how much it says, its replies and the people taking part, its votes, reactions and views, whether it was answered, and how recently it was active. A thread whose first post is under 50 words and has no replies stays excluded. A thread whose first post has 50 words or more goes in the sitemap whatever its score, once it is a day old and passes moderation. Threads on a board that search engines do not index stay excluded, a member can keep their own profile out with index_opt_out, and a placeholder's profile is never indexed or counted in the totals. We score a thread again each time it changes, such as a reply, a vote, an accepted answer or a moderator's action.
Every thread page also tells search engines what it is: a forum discussion, or for a question with an accepted answer, a question and its answers, with the author and the time of each post. Member pages say they are profiles. A thread or profile kept out of search says noindex as well, so search engines read it but do not list it. A post whose author's account was deleted names the author "Deleted member", as the page does.
An owner or admin reads the totals, the reasons threads are left out and the scoring policy with GET /admin/community/forum/seo. POST /admin/community/forum/seo/preview with thread_id or handle explains one verdict, and POST /admin/community/forum/seo/rescore scores every thread and profile again.
Result
Section titled ResultGET /storefront/branding shows enabled: true for each part you turned on, and its public routes answer anyone. Customers list their servers, post, write guides and chat from your site, and what they report reaches your team on the staff console's community page.
Troubleshooting
Section titled Troubleshooting404 Community forum is not enabled,Community guides are not enabledorCommunity server list is not enabled- That part is off for your organization. Ask support to turn it on.
The community forum is not enabled for this brandorCommunity guides are not enabled for this brand- A staff route for a part that is off. Ask support to turn it on.
404 Community chat is not enabled- Tick Mirror public channels on the storefront in your Discord settings, and check that Integration enabled is ticked.
- The chat shows no channels
- A channel shows only when Discord lets
@everyoneread it and send messages in it, and it is not in Hidden channels. After you change a channel's permissions in Discord, choose Sync community channels. No Discord server configured- Syncing the channels needs your server's ID. Enter the Server (guild) ID and save.
403 Support access required,403 Tier 2 support access requiredor403 Admin access required- The member's role is below what the task needs. Moderate the community lists the lowest role for each.
Your tier mutes for up to 7 days; ask Tier 3 for longer- Tier 1 and Tier 2 support mute for up to 168 hours. Ask a member with Tier 3 support or a higher role.
Featuring a listing is for Tier 3- Ask a member with Tier 3 support or a higher role to feature it.
This report's content is quarantined; restore it or remove it instead- A quarantined report closes when Tier 2 support restores or removes the content.
Publishing requires at least one tag- Add a tag from your list to
tags. Publishing requires an active join address for this server- Your list takes only servers that players can join. Publish once the server's join address is active.
That community URL slug is already taken- Another listing in your organization uses that
slug. Choose another. 429 You are posting too quickly. Try again a little later.- The member passed an hourly limit for threads, replies, wall posts or wall comments.
429 You are muted in the community for another …- Your staff muted the member.
Retry-Aftergives the seconds left. 403 Your forum access is suspended.- Your staff suspended the member from the forum. When they gave a reason, the message is the reason instead.
422 That message breaks the community rules. Keep it civil and try again.- The moderation filter refused the text. In the chat, more than three refusals in an hour mute the customer for an hour.
429 You cannot post in community chat right now. Try again in …- The customer is muted in the chat.
muted_secondsinGET /storefront/community/chat/statuscounts down. 429withYou can send one message every 8 seconds from the web. …- The customer sent a message less than the channel's slow mode ago. Wait for
Retry-After, or forcooldown_secondsfromchat/statusto reach0. 403 You cannot post in community chat. …- Your team banned the account, or the network it posts from, from the chat. When they gave a reason, the message says it. Moderate the community chat lifts a ban.
403 Chat from the website is paused. You can still read along.- Your team paused web chat, as Pause web chat during a raid describes. Your team's own notice replaces this sentence when they wrote one.
422 Links to other sites cannot be posted from the website.- Your chat allows links to your storefront's own sites and the sites your team trusts. Your team lists more in the chat's settings.
422 You already sent that.- The customer sent the same words in the channel in the last 10 minutes.
Invite links to other servers are not allowed here.- Chat messages cannot carry a Discord invite link.
Keep it under 500 characters. …- Chat messages take up to 500 characters. Read
max_lengthfromchat/channelsand hold your composer to it. 403 Customer contributions are disabled- Your guides do not take guides from customers. Ask support to turn contributions on.
A proposal is already pending validation- The guide has an edit waiting for a moderator. Withdraw it with
POST .../proposal/withdraw, or wait for the decision. 409 This guide changed after you opened it. Reload it to see the new version.- The
revision_idof a decision is not the guide's current proposal, because the author sent a new version. Read the review again and send itsproposed_revision_id. 409 This guide has nothing waiting for review.- Someone already decided, or the author withdrew the proposal. Reload the queue.
403 Moderator access requiredor403 Forum staff only- The customer is not a guide moderator, or holds no staff role in the forum.
Related
Section titled Related- Build a storefront on the Organization API
- Show your catalogue with the Storefront API
- Let customers run their servers
- Connect a Discord server
- The staff console
- Organization roles and permissions
- Read the organization audit log
With the API
Section titled With the APIEach group of routes takes its own credential, sent as Authorization: Bearer:
| Routes | Credential |
|---|---|
/storefront/community/... |
None to read. Rating a server, commenting on a guide, voting on it or reporting it, sending, reporting or deleting a chat message, chat/status and handle-available take the customer's token, $CUSTOMER_TOKEN. |
/portal/community/... and /portal/services/{service_id}/community-listing |
The customer's token. |
/staff/community/... |
A member's console session or Coritan access token, $STAFF_TOKEN, as The staff console explains. |
/admin/community/... |
An owner's or admin's Coritan access token, $CORITAN_TOKEN. |
Start a thread as a customer:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/community/forum/threads" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"category_slug": "help", "title": "Players cannot join after the 1.21 update", "body_markdown": "Since the update, players are disconnected as they join. What should I change?", "kind": "question"}'
Quarantine what a report points at, as a member with Tier 1 support or a higher role:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/staff/community/forum/reports/318/quarantine" \
-H "Authorization: Bearer $STAFF_TOKEN" \
-H "Content-Type: application/json" \
-d '{"note": "Advertises another host"}'
The answer names what was hidden, such as {"ok": true, "quarantined": "post", "id": 9051}.
Explain why a thread is in search engines or left out, as an owner or admin:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/admin/community/forum/seo/preview?thread_id=2207" \
-H "Authorization: Bearer $CORITAN_TOKEN"
The API reference lists every route with its parameters and answers:
| Routes | Reference |
|---|---|
/storefront/community/... |
Storefront |
/portal/community/... |
Customer portal community |
/portal/services/{service_id}/community-listing |
Customer portal services |
/staff/community/... |
Staff community, with the forum member routes under Staff forum members |
/admin/community/forum/... |
Community forum |
/admin/community/guides/... |
Community guides. These routes are deprecated and may stop answering after 31 March 2027; use the guide routes under /staff/community/guides/. |