Table of Contents

Class PlayitApiService

Namespace
McServerLauncher.Services
Assembly
McServerLauncher.dll

Playit.gg API client.

  • Preferred: a per-user self-managed agent secret key from the partner setup-code flow (PlayitPartnerService), set app-wide via SetAgentKey(string?) and used as agent-key for both reads AND writes.
  • Fallback (legacy): the agent's secret_key from playit.toml (reads) and a user-pasted write key (writes, sent as Api-Key/Agent-Key). Auth is resolved by trying the schemes in order, so a caller doesn't need to know which kind of key it holds.
public class PlayitApiService
Inheritance
PlayitApiService
Inherited Members

Methods

CanManageTunnelsAsync(string, CancellationToken)

Whether this key may change tunnels, found out without changing any: a rename of a tunnel id that does not exist. Null when Playit could not be asked.

public Task<bool?> CanManageTunnelsAsync(string key, CancellationToken ct = default)

Parameters

key string
ct CancellationToken

Returns

Task<bool?>

Remarks

A key that can write is told the tunnel does not exist; a read-only one is refused before Playit looks. Asked once per key and remembered — the answer does not change while the app runs.

DeleteTunnelAsync(string, string, CancellationToken)

Deletes one specific tunnel. For duplicates, where "the tunnel on port 25565" is ambiguous and DeleteTunnelForPortAsync(string, int, bool, CancellationToken) would remove whichever the account lists first.

public Task DeleteTunnelAsync(string key, string tunnelId, CancellationToken ct = default)

Parameters

key string
tunnelId string
ct CancellationToken

Returns

Task

DeleteTunnelForPortAsync(string, int, bool, CancellationToken)

Deletes the tunnel with this local port and this protocol. True if one was deleted. key is the per-user agent secret key (preferred) or a legacy write key.

public Task<bool> DeleteTunnelForPortAsync(string key, int localPort, bool udp, CancellationToken ct = default)

Parameters

key string
localPort int
udp bool
ct CancellationToken

Returns

Task<bool>

Remarks

The protocol is half the identity, the same as in GetTunnelAsync(int, bool, bool, CancellationToken) and EnsureMinecraftTunnelAsync(string, string, int, TunnelEdition, CancellationToken): a crossplay server owns two tunnels, Java over TCP and Bedrock over UDP, and matching on the port alone deletes whichever the account happens to list first. Deleting a tunnel is not undoable, so this is the one place where guessing is least acceptable.

EnsureMinecraftTunnelAsync(string, string, int, TunnelEdition, CancellationToken)

Creates a tunnel for the server if one doesn't already exist for that port and edition. Returns true if it created one, false if it already existed. key is the per-user agent secret key (preferred) or a legacy write key.

public Task<bool> EnsureMinecraftTunnelAsync(string key, string name, int localPort, PlayitApiService.TunnelEdition edition = TunnelEdition.Java, CancellationToken ct = default)

Parameters

key string
name string
localPort int
edition PlayitApiService.TunnelEdition
ct CancellationToken

Returns

Task<bool>

GetRunDataAsync(string, CancellationToken)

Reads agent_id and tunnels using key (agent secret or write key).

public Task<(string AgentId, List<PlayitApiService.PlayitTunnel> Tunnels)> GetRunDataAsync(string key, CancellationToken ct = default)

Parameters

key string
ct CancellationToken

Returns

Task<(string AgentId, List<PlayitApiService.PlayitTunnel> Tunnels)>

GetTunnelAsync(int, bool, bool, CancellationToken)

The tunnel on a local port for one protocol, or null.

public Task<PlayitApiService.PlayitTunnel?> GetTunnelAsync(int localPort, bool udp, bool fresh = false, CancellationToken ct = default)

Parameters

localPort int

The port on this machine the tunnel forwards to.

udp bool

True for the Bedrock half of a crossplay server.

fresh bool

Skips the shared cache. See GetTunnelsSharedAsync(CancellationToken, bool).

ct CancellationToken

Cancels the wait, not the shared fetch itself.

Returns

Task<PlayitApiService.PlayitTunnel>

Remarks

Matched on the protocol as well as the port, because a crossplay server has two tunnels and the port alone would return whichever came first. There used to be a second lookup beside this one that returned an address and nothing else, and it did match on the port alone — so the box labelled Java could show the address players are meant to type into Bedrock, which is an answer that looks entirely plausible and does not connect.

The whole tunnel rather than its address: the callers need to tell a tunnel playit has not published an address for yet, which resolves itself in seconds, from no tunnel at all, which needs the user to press a button. A null address cannot say which of the two it is.

GetUdpTunnelPortsAsync(CancellationToken)

Local ports of every UDP tunnel on the account, or null when the account could not be asked.

public Task<IReadOnlyCollection<int>?> GetUdpTunnelPortsAsync(CancellationToken ct = default)

Parameters

ct CancellationToken

Returns

Task<IReadOnlyCollection<int>>

Remarks

For picking a Bedrock port. The system's UDP table only knows what is bound right now, and the app only knows its own servers, so neither sees a tunnel left behind by a deleted server, one made by hand on playit's site, or one belonging to another machine on the same account. Creating a tunnel on a port one of those already holds does not fail — it silently adopts the other tunnel, and two servers end up advertising one address.

Null rather than an empty set on failure, so "the account has no UDP tunnels" cannot be confused with "I could not reach playit".

ReadSecretKey()

Reads the (read-only) secret_key from playit.toml (cached ~30 s). Null if not found.

public string? ReadSecretKey()

Returns

string

RenameTunnelAsync(string, string, string, CancellationToken)

Gives a tunnel a new name. The name is the only thing about a tunnel that is ours to change.

public Task RenameTunnelAsync(string key, string tunnelId, string name, CancellationToken ct = default)

Parameters

key string
tunnelId string
name string
ct CancellationToken

Returns

Task

Remarks

Named by id, not by port: a rename is harmless, but the id is what the account actually keys a tunnel on, and two tunnels can share a port (that is one of the things the tunnels screen exists to point out).

SetAgentKey(string?)

Sets (or clears) the per-user agent secret key used for all Playit API auth. Called once at startup from settings and again after the setup-code flow mints a new key. Drops the shared tunnel cache so the next refresh uses the new credential.

public static void SetAgentKey(string? agentSecretKey)

Parameters

agentSecretKey string

TryGetTunnelsAsync(bool, CancellationToken)

The account's tunnels from the shared cache, or null when the account could not be asked. An empty list is an answer: "there are none". fresh skips the cache.

public Task<List<PlayitApiService.PlayitTunnel>?> TryGetTunnelsAsync(bool fresh = false, CancellationToken ct = default)

Parameters

fresh bool
ct CancellationToken

Returns

Task<List<PlayitApiService.PlayitTunnel>>