Plugin Protocol
The FluxStore Minecraft plugin is open source. If you want to build your own plugin for a platform we don’t officially support, or you want to customize how commands are delivered, you can implement your own client as long as it follows the protocol described on this page.
You don’t need any of this to use FluxStore normally. This page is for developers who want to build a custom plugin implementation.
Our API is rate limited. Be reasonable with how often you make requests. Excessive or abusive usage (spamming FetchPendingCommands, reconnecting in tight loops, etc.) may result in your server being temporarily or permanently blocked. If you’re unsure whether your usage pattern is acceptable, reach out to support before deploying.
Delivery methods
FluxStore supports two ways to deliver commands to your plugin, and you can use either or both:
WebSocket (recommended) maintains a persistent connection using SignalR. When a customer makes a purchase, commands are pushed to your plugin instantly. This is the fastest and most efficient approach since there’s no delay and no unnecessary requests.
Polling lets your plugin periodically call FetchPendingCommands to check for new commands. This is simpler to implement but adds latency since commands are only picked up on the next poll. If you use polling, respect the NextCheckSeconds value returned by the server and don’t poll more frequently than that.
You can combine both. Keep a WebSocket connection open for instant delivery, and use occasional polling as a fallback to catch anything that might have been missed during a brief disconnect.
Connection
FluxStore uses SignalR for real-time communication between your server and the FluxStore platform. SignalR is built on WebSocket with automatic fallback to other transports if needed.
SignalR client libraries are available for most languages including Java, C#, JavaScript, Python, and Go.
Hub endpoint: wss://api.fluxstore.net/plugin-hub
Authentication
Authentication must be the first message sent after connecting. The combined key is in the format serverId:secret, where serverId is the GUID of your server and secret is the 32 character token generated when you add a server in your dashboard.
If authentication fails, the connection is closed immediately with no error message.
Authenticate
Direction: Plugin to server
Method: Authenticate(HandshakeRequest request, string combinedKey)
HandshakeRequest {
ServerSoftware: string // Server platform, e.g. "Spigot 1.20.1"
}
Returns: HandshakeResponse {
ServerId: guid // Your server's unique identifier
StoreName: string // The store name
NextCheckSeconds: int // Recommended interval before next check (default 300)
PendingCommandCount: int // Number of commands waiting to be delivered
}Plugin to server methods
These are methods your plugin calls on the hub.
PlayerJoin
Call this when a player joins your server. FluxStore checks for any commands waiting for that player and pushes them immediately.
Method: PlayerJoin(string playerUuid, string playerUsername)PlayerLeave
Call this when a player leaves your server.
Method: PlayerLeave(string playerUuid)FetchPendingCommands
Forces an immediate check for all pending commands for your server. If any exist, the server responds with an ExecuteCommands message. Don’t call this more frequently than the NextCheckSeconds interval.
Method: FetchPendingCommands()AcknowledgeCommands
After executing commands, send back the results so FluxStore can update the order status. Always send results in a batch, not individually.
Method: AcknowledgeCommands(List<CommandResult> results)
CommandResult {
CommandId: guid // The ID of the command (from PluginCommandDto.Id)
Status: string // "success", "failed", or "player_offline"
Error: string (optional) // Error message if status is "failed"
}
Returns: int // Number of commands successfully acknowledgedStatus values:
| Status | Meaning | What FluxStore does |
|---|---|---|
success | Command ran successfully | Marks as completed |
failed | Command execution failed | Retries with backoff (30s, 60s, 120s), up to 3 attempts |
player_offline | Player not on the server | Holds command until next PlayerJoin for that player |
Server to plugin messages
These are messages the server pushes to your plugin over the WebSocket connection. Listen for them on your SignalR client.
ExecuteCommands
Sent when there are commands for your server to execute. This is triggered by purchases, PlayerJoin events, FetchPendingCommands calls, or the background sweep service.
Message: ExecuteCommands(List<PluginCommandDto> commands)
PluginCommandDto {
Id: guid // Unique command ID (include in AcknowledgeCommands)
Command: string // The command to execute, e.g. "give Steve diamond 64"
PlayerUsername: string // Target player's username
PlayerUuid: string // Target player's UUID (may be null)
RequireOnline: bool // Only execute if the player is currently online
CommandType: string // e.g. "Initial", "Chargeback", "Expiry"
PackageName: string // Name of the package (may be null)
ExecutionOrder: int // Execute in this order (lower first)
Conditions: { // Optional execution conditions
Slots: int // Only execute if player has this many empty inventory slots
DelaySeconds: int // Wait this many seconds before executing
}
}Typical lifecycle
Here’s the expected flow for a custom plugin implementation:
- Connect to
wss://api.fluxstore.net/plugin-hubusing a SignalR client - Call
Authenticatewith your combined key and server info - Register a listener for
ExecuteCommandsmessages - Call
PlayerJoinandPlayerLeaveas players connect and disconnect - When you receive
ExecuteCommands, execute each command on your server and callAcknowledgeCommandswith the results - Optionally call
FetchPendingCommandson an interval as a polling fallback - If the connection drops, reconnect and re-authenticate. Any commands that were pending will be re-sent.
Building a custom plugin
If you’re building your own implementation, here are some things to keep in mind:
- Authentication must come first. Any other method call before
Authenticatewill fail. - Always acknowledge commands. If you don’t send
AcknowledgeCommands, FluxStore assumes the commands weren’t delivered and will keep retrying. - Handle reconnection gracefully. Network interruptions are normal. Reconnect, re-authenticate, and pending commands will be pushed again. Don’t reconnect in a tight loop. Use exponential backoff.
- Respect RequireOnline. If a command has
RequireOnlineset to true and the player isn’t on the server, reportplayer_offlinein your acknowledgment rather than skipping it silently. - Execute in order. Sort commands by
ExecutionOrderbefore executing them. - Check Conditions. If a command has
Conditions.DelaySeconds, wait before executing. If it hasConditions.Slots, check the player’s inventory first. - Respect rate limits. Don’t poll more often than
NextCheckSecondssuggests. Don’t spam methods in a loop. If you’re rate limited, back off.
The official FluxStore plugin is open source and serves as a reference implementation. If you’re unsure about any part of the protocol, reading the plugin source code is the best way to understand the expected behaviour.