BlazeBans API/Working with data
Reading punishments
Everything on `api.punishments()` that reads. All of it returns a `CompletableFuture`, so read [Threading](/docs/blazebans-api/threading) first if you have not.
Boolean checks
The cheapest question: is this player punished right now?
api.punishments().isBanned(name, uuid).thenAccept(banned -> { /* ... */ });
api.punishments().isMuted(name, uuid).thenAccept(muted -> { /* ... */ });Both have an overload that also matches IP punishments:
api.punishments().isBanned(name, uuid, ipAddress);
api.punishments().isMuted(name, uuid, ipAddress);Pass the address raw, exactly as player.getAddress() gives it to you. BlazeBans applies its own hashing and privacy rules on the way in, so pre-hashing it will just fail to match.
These answer only about punishments that apply on this server. A record scoped to another server on the network returns false here, which is the same answer enforcement would give.
Fetching the record
When you need the reason, the expiry, or who issued it:
api.punishments().activeBan(name, uuid)
.thenAccept(activeBan -> activeBan.ifPresent(punishment ->
getLogger().info("Banned for " + punishment.reason())
));
api.punishments().activeMute(name, uuid);activeBan covers BAN and IP_BAN; activeMute covers MUTE and IP_MUTE. Each returns the newest applicable one. Both have the same IP-aware overload as the boolean checks.
For exactly one type and nothing else:
api.punishments().activePunishment(PunishmentType.WARN, name, uuid);
api.punishments().activePunishment(PunishmentType.VOICE_MUTE, name, uuid);This is how you check for an active warning, which has no dedicated accessor, and how you check voice mutes when the voice chat addon is installed.
By ID
api.punishments().punishmentById("#ABC123")
.thenAccept(found -> found.ifPresent(punishment ->
getLogger().info(punishment.targetName() + ": " + punishment.reason())
));The # is optional. ABC123 and #ABC123 both resolve, so you can pass an ID straight from user input without stripping it.
This finds the record whatever its state: active, expired, or revoked. Check status() if that matters.
Full history
api.punishments().history(target)
.thenAccept(records -> records.forEach(punishment ->
getLogger().info(punishment.id() + " " + punishment.type() + " " + punishment.status())
));target accepts a player name, a UUID string, or a raw IP address. Results are newest first and include every record: active, expired, and revoked, from every server scope.
That last part is worth remembering. Unlike the boolean checks, history is not filtered to this server, because a moderation decision usually should account for what happened elsewhere.
Server-wide lists
api.punishments().activeBans();
api.punishments().activeMutes();
api.punishments().activeWarns();Every active record of that kind applying to this server. These are the same sets /banlist, /mutelist, and /warnlist show.
They are unbounded. On a server with a long history this can be a large list and a heavy query, so do not call them on a timer. Once at startup, or in response to a command, is the right shape.
What a record contains
Punishment is an immutable record.
PunishmentType is BAN, MUTE, WARN, KICK, IP_BAN, IP_MUTE, or VOICE_MUTE.
Derived state
Three convenience methods, all computed when you call them:
punishment.active(); // true only while neither revoked nor expired
punishment.permanent(); // true when expiresAt is null
punishment.status(); // ACTIVE, REVOKED, or EXPIREDstatus() compares expiresAt against the current time on every call, so a temporary punishment you fetched a minute ago will start reporting EXPIRED the moment it lapses. You never need to re-fetch a record to notice it expired.
The precedence is revoked, then expired, then active. A punishment that was revoked before its expiry reports REVOKED.
Remaining time
There is no helper for this, because Instant already has one:
if (punishment.permanent()) {
return "Permanent";
}
Duration remaining = Duration.between(Instant.now(), punishment.expiresAt());
if (remaining.isNegative()) {
return "Expired";
}
return remaining.toDays() + "d " + remaining.toHoursPart() + "h";Format it however suits your plugin. BlazeBans' own compact format is two units at most.
Scope
serverScope() and serverId() tell you where a record applies.
boolean global = "global".equalsIgnoreCase(punishment.serverScope());
String appliesTo = global ? "the whole network" : punishment.serverId();The PunishmentScope enum (GLOBAL, SERVER) exists in the API for typed use, but records carry these as strings, so compare case-insensitively rather than assuming a case.
You rarely need this. The boolean checks and activeBan already filter to what applies here; scope matters when you are displaying history and want to say where each record came from.
Filtering history yourself
There is no query-by-type-and-date method. Pull the history and filter in Java:
api.punishments().history(playerName).thenAccept(records -> {
List<Punishment> recentBans = records.stream()
.filter(punishment -> punishment.type() == PunishmentType.BAN)
.filter(punishment -> punishment.createdAt().isAfter(Instant.now().minus(Duration.ofDays(30))))
.toList();
long activeWarnings = records.stream()
.filter(punishment -> punishment.type() == PunishmentType.WARN)
.filter(Punishment::active)
.count();
});One player's history is small enough that this costs nothing worth avoiding.

