BlazeBans API/Working with data
Creating and revoking
Issuing punishments from your own code, revoking them, and correcting a reason. Everything here goes through the same path as a staff command, so the same events fire and the same follow-up happens.
Creating a punishment
Build a PunishmentCreateRequest and submit it.
import java.time.Duration;
import net.blazebans.api.punishment.PunishmentCreateRequest;
import net.blazebans.api.punishment.PunishmentType;
PunishmentCreateRequest request = new PunishmentCreateRequest(
PunishmentType.MUTE,
target.getName(),
target.getUniqueId(),
targetIpAddress,
"MyAddon",
null,
Duration.ofHours(2),
"Spam",
"https://example.com/proof/123",
"server",
"survival",
false
);
api.punishments().createPunishment(request)
.whenComplete((created, error) -> {
if (error != null) {
getLogger().warning("Punishment creation failed: " + error.getMessage());
return;
}
if (created.isEmpty()) {
getLogger().info("Another plugin cancelled the punishment.");
return;
}
getLogger().info("Created " + created.get().id());
});The twelve arguments
Null strings are converted to "" on the way in, so passing null for reason or proofUrl will not throw. It just means "not supplied".
Pass the IP address raw. BlazeBans applies its own hashing and privacy settings; pre-hashing it will not match anything.
Name your plugin in staffName
staffName is what appears in /history, /staffhistory, staff profiles, and the Discord post. Put your system's name there.
"Anti-cheat" // good
"Chat-Filter" // good
"CONSOLE" // useless six months later
"" // worseThis is the API equivalent of the --punisher flag on the commands, and it matters for the same reason: an operator reviewing an appeal needs to know whether a ban came from a detector, a web panel, or a person. It also makes /staffhistory Anti-cheat and /staffrollback Anti-cheat 2h work, which is how a misbehaving detector gets reviewed and undone without touching anything a human did.
Pick one name per system and keep it stable across releases, since operators will search on it.
Set staffUuid to null for anything automated. A UUID there implies a real account acted.
If your plugin punishes on behalf of a specific staff member, such as an appeals panel, use their name and UUID instead so the record credits the person who decided.
Durations
Duration.ofHours(2) // two hours
Duration.ofDays(30) // thirty days
Duration.ZERO // permanent
null // permanentKicks are stored as permanent records regardless of what you pass, because there is nothing for a kick to expire from.
Scope
// This server only
request.serverScope("server");
request.serverId("survival");
// The whole network
request.serverScope("global");
request.serverId("");Get the local server ID from an existing record, or take it from your own config. There is no API method exposing BlazeBans' configured server.id, so if your addon needs to scope to "here" the practical route is to read it from a record you already have, or let the operator set it in your own config.
What happens after
Creating a punishment through the API is not a bare database insert. In order:
BlazeBansPunishmentCreateEventfires, and listeners can modify or cancel it.- The record is stored.
BlazeBansPunishmentCreatedEventfires.- Enforcement runs: the player is removed for a ban, or the mute takes effect.
- The victim is notified, staff are broadcast to, Discord is posted, and any template console commands run.
An empty Optional means step 1 cancelled it. Nothing was stored.
Revoking by ID
api.punishments()
.revokePunishment("#ABC123", "MyAddon", "Appeal accepted")
.thenAccept(revoked -> revoked.ifPresent(punishment ->
getLogger().info("Revoked " + punishment.id())
));The # is optional. An empty result means no punishment with that ID was found and active, or a listener cancelled the revocation.
Revoking the newest match
When you have a player rather than an ID:
import java.util.List;
import net.blazebans.api.punishment.PunishmentRevokeRequest;
import net.blazebans.api.punishment.PunishmentType;
PunishmentRevokeRequest request = new PunishmentRevokeRequest(
List.of(PunishmentType.MUTE, PunishmentType.IP_MUTE),
targetNameOrUuid,
"MyAddon",
"Mute lifted early"
);
api.punishments().revokeActive(request);The type list is how you say "any kind of mute". Pass both BAN and IP_BAN to match what /unban does, or a single type to be precise.
target accepts a name or a UUID string. Staff name and reason are mutable on the request, which is what lets a BlazeBansPunishmentRevokeEvent listener adjust them before it goes through.
Editing a reason
api.punishments().editReason("#ABC123", "Corrected reason");Changes the stored reason and nothing else. A blank reason is rejected with an empty result.
There is no API method for changing a duration. /editpunishment does that in game.
Revocation semantics
A revoked punishment is not deleted. It keeps its record with revokedAt, revokedBy, and revokeReason filled in, and status() reports REVOKED.
Cancelling BlazeBansPunishmentRevokedEvent does not put the punishment back. It only suppresses the follow-up output. By the time that event fires, the revocation is stored.
Preferring commands
Sometimes dispatching the console command is the better tool:
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
"ban " + player.getName() + " 30d Cheating --proof " + url);Use a command when you want a template applied by ID, a ladder step chosen automatically, or any flag the API does not model. Use the API when you want the created record back, structured error handling, or to avoid string-building user input into a command line.
If you do dispatch commands, be careful with player-supplied text. A reason containing --silent will be parsed as a flag.
A complete example
Muting a player for a fixed period when your own plugin detects something:
public void muteForSpam(Player target, Duration duration) {
String ip = target.getAddress() == null
? ""
: target.getAddress().getAddress().getHostAddress();
PunishmentCreateRequest request = new PunishmentCreateRequest(
PunishmentType.MUTE,
target.getName(),
target.getUniqueId(),
ip,
"MyAddon",
null,
duration,
"Automated: chat spam",
"",
"server",
this.serverId,
false
);
this.blazeBans.punishments().createPunishment(request)
.whenComplete((created, error) -> {
if (error != null) {
getLogger().warning("Could not mute " + target.getName() + ": " + error.getMessage());
return;
}
created.ifPresent(punishment ->
getLogger().info("Muted " + target.getName() + " as " + punishment.id())
);
});
}Note that nothing here touches Bukkit from the callback. If you wanted to message the player, you would schedule back first. See Threading.

