Guilds, ranks and bans for multiplayer games

One API for groups, roles, permissions, moderation and a live stream of every change. SDKs for TypeScript, React, Java, Roblox, C++ and Unreal Engine.

guild.ts
const guild = await junjo.groups.create({
  kind: "guild",
  name: "Crimson Dawn",
});

await junjo.groups.inviteByUserId(guild.id, "steve");

const ok = await junjo.can("steve", guild.id, "invite");

Crimson Dawn

guild, 4 of 25
  • ariaLeader
  • brambleOfficer
  • kestrelMember
  • steve joined by inviteMember

steve can invite: yes, from Member

Built for game servers

The Java SDK runs inside a Minecraft or any JVM server. Ranks and bans live in Junjo, so every server, your website and your bot agree.

Permissions per world
Grant build in creative and deny it in survival on the same rank. Worlds inherit from each other, nearest first.
Checks without a round trip
The Java mirror keeps bans, ranks and the players you track in memory and answers from memory, then follows the stream to stay current.
Writes that survive a restart
A write queue on disk replays bans and promotions after an outage, with versions so a stale write never wins.
One stream for the whole game
Every change in order, with a position to resume from. Your other servers and your website see the same thing.
BuildListener.java
var checker = mirror.checker(
    playerId, guildId, Context.of("world", world));

if (checker.can("build.place") != Answer.YES) {
    event.setCancelled(true);
}

// a ban from the website reaches
// every server through the stream
if (mirror.isBanned(playerId) == Answer.YES) {
    player.kick("Banned");
}

The whole surface

The same names in the HTTP API, every SDK and the React hooks.

groups
Guilds, clans, parties and sub-groups, with per-kind limits.
roles
Ranks with grants, denies, inheritance and per-world entries.
members
Rosters, joins, kicks, promotions and bulk import.
permissions
One check or a hundred, answered by the deciding rule.
bans
Game and group bans with full history.
sanctions
Mutes and any other timed restriction your game defines.
identities
Linked accounts across platforms, and display names.
friends
Requests, tags, suggestions and blocks.
invitations
Direct invites and links, with expiry.
events
One ordered stream of every change, resumable.

Keeps your auth

Junjo never touches your login. It takes the user id your auth already issues and links ids across platforms when a player connects a second account. Clerk, Supabase and plain JWT adapters are built in.

junjo.ts
const junjo = new Junjo({
  apiKey: process.env.JUNJO_API_KEY,
  authAdapter: clerkAdapter(clerk),
});

Run it yourself

Source-available (ELv2) and free to run for your own game: one Docker image and one Postgres, the same API as hosted.

Self-hosting guide

Or let me host it

Dashboard and database included, free during the beta. Email me and I will set up your game.

Request access