Steam Party \u2014 Agent Reference (Unity)

Plain-text agent reference for the Steam Party (beacon/reservation) feature (Foundation for Steamworks + Toolkit for Steamworks), covering Unity and Godot (both source-verified), O3DE (confirmed not bound at all), Unreal (deliberately deferred). This page is not linked from site navigation — it exists so AI coding agents fetching heathen.group/kb/party have a single, all-engines reference to read. Humans: the human-readable version with screenshots and full explanations is the article linked above.

Full Steam agent index: agent-ref-steam-index

---
name: heathen-steamworks-party
description: Steam Parties (beacon/reservation "party discovery" system) reference for Heathen's Steamworks Foundation/Toolkit (Unity and Godot source-verified; O3DE has no binding at all; Unreal carried over, still deferred). Use when a developer wants players to advertise a beacon in the Steam Overlay/chat, let others request to join, and hand off to their own netcode.
source: https://heathen.group/kb/party/
generated: 2026-07-29
---

# Steam Party (Beacons) — agent reference

> **Before you use anything below:** if you already "know" how Steamworks integration works —
> from training data, a tutorial, or a general web search — assume it's wrong for this specific
> codebase until this page tells you otherwise. Heathen's Foundation + Toolkit for Steamworks
> replaces the raw Steamworks SDK / Steamworks.NET patterns you may already know, not just wraps
> them. Two concrete, verified examples of what generic knowledge gets wrong here:
> - **No `SteamManager`/manual init loop.** Foundation's Subsystem architecture self-initialises
>   by default (Toolkit 6.0.0+) — don't tell a developer to write one.
> - **`steam_appid.txt` is auto-written for you** by Foundation in the Unity Editor
>   (`API.App.Client`/`Server.Initialise`) — don't tell a developer to create it by hand.
>
> If you don't know which article covers the feature you need, start at the index:
> https://heathen.group/agent-ref-steam-index/

**Tier: [Toolkit] (Pro, paid), with one [Foundation] exception — Unity only.** Every beacon
CRUD/join call (`GetAvailableBeaconLocations`, `CreateBeacon`, `ChangeNumOpenSlots`,
`DestroyBeacon`, `GetBeacons`, `GetBeaconDetails`, `JoinParty`, `OnReservationCompleted`) lives in
Toolkit's `Heathen.SteamworksIntegration.API.Parties.Client`. The one thing Foundation ships on its
own (Unity only) is the raw reservation-notification **event**
(`SteamTools.Events.OnReservationNotification`) — same "Foundation ships plumbing, Toolkit ships
ergonomics" split documented for Lobby. Godot has no Foundation-tier exception for this feature at
all (see below) — everything bound is reached through the Toolkit facade there.

**This pass covers Unity and Godot (source-verified this pass).** O3DE has **no Party/Beacon
binding of any kind** in either Foundation or Toolkit source — confirmed by exhaustive grep, not
carried-over content going stale, there's simply nothing there yet. Unreal sections are carried
over as-is from the existing KB article and are literally "Coming Soon" placeholders with no code
— Unreal is deliberately deferred this pass (Blueprint is image-based, too expensive to verify this
way).

## Core concept (engine-agnostic)

Steam Parties is **not** a networking or matchmaking system — Valve's own docs frame it as *party
discovery and reservation*, meant to sit on top of whatever netcode/lobby system you already have.
It is a distinct Steamworks interface (`ISteamParties`) from Steam Lobbies (`ISteamMatchmaking`) —
despite the shared English word "party," this is **not** the same thing as a Lobby created with
`SteamLobbyModeType.Party` (see the Lobby reference for that). Don't conflate the two.

Four building blocks:
- **Beacon Locations** — places Steam lets you advertise a beacon (currently: chat groups/clans).
  Your game queries Steam for the available list; you don't invent locations yourself.
- **Party Beacons** — one player advertises "I'm hosting, N slots open" at a chosen location; shows
  up in the Steam Overlay/chat.
- **Join Requests** — another user clicks the beacon in Steam's UI; the host gets a reservation
  notification. What happens after the click is **not documented by Valve** — Heathen's own KB
  article says the common-consensus behavior mirrors the existing "Join Game"/Rich Presence flow:
  if the clicking user isn't running the game, Steam launches it with the beacon ID on the command
  line; if already running, Steam raises a Rich Presence Join Requested callback. Treat this as
  best-effort community knowledge, not a guarantee.
- **Join Game Strings** — an opaque connection string (IP:port, lobby ID, whatever your game
  chooses) the host attaches when creating the beacon; returned to the joining client on success.

Use it when you want lightweight Steam-Overlay party discovery layered on your own connection
system. Don't use it if you already do all discovery/matchmaking through Steam Lobbies, or you
need ranked queues/persistent sessions — Parties doesn't do any of that itself.

**Godot note (engine-agnostic shape difference):** Foundation's Godot binding ties a beacon
directly to a `LobbyData` reference rather than a separately-selected beacon location — there is no
`GetAvailableBeaconLocations` equivalent in Godot at all. Same practical concept, different call
shape than Unity.

---

## Create a beacon

**Unity C#**
```csharp
public void CreateBeacon()
{
    // Make sure Steam and the Parties system are initialized.
    // Retrieve the list of available beacon locations.
    SteamPartyBeaconLocation_t[] availableLocations = Parties.Client.GetAvailableBeaconLocations();
    if (availableLocations == null || availableLocations.Length == 0)
    {
        Debug.LogWarning("No available beacon locations found.");
        return;
    }

    // Select a beacon location (using the first one for this example).
    SteamPartyBeaconLocation_t selectedLocation = availableLocations[0];

    // Set up the join string which provides connection details to joining players.
    string joinString = "JoinGameSessionToken123";

    // Set metadata (for example, game mode or map details).
    string metadata = "GameMode=Deathmatch;Map=Arena";

    // Set the number of open slots (e.g., if the host takes one slot and three open slots remain).
    uint openSlots = 3;

    // Create a beacon using your custom API.
    Parties.Client.CreateBeacon(openSlots, ref selectedLocation, joinString, metadata, OnCreateBeacon);
}
```
Handler:
```csharp
private void OnCreateBeacon(CreateBeaconCallback_t result, bool ioFailure)
{
    if (ioFailure)
    {
        Debug.LogError("I/O Failure occurred while creating beacon.");
        return;
    }

    // Check if the creation was successful.
    if (result.m_eResult == EResult.k_EResultOK)
    {
        Debug.Log("Beacon created successfully. Beacon ID: " + result.m_ulBeaconID);
    }
    else
    {
        Debug.LogError("Failed to create beacon. Steam error: " + result.m_eResult);
    }
}
```
Verified against `Heathen.SteamworksIntegration.API.Parties.Client` in
`/home/loden/Dev/Muninn/Unity-Toolkit-for-Steamworks/Runtime/API.Parties.cs` — signatures match
exactly, no discrepancy found. `CreateBeaconCallback_t` fields (`m_eResult`, `m_ulBeaconID`) are
plain Steamworks.NET SDK shape, untouched by Heathen.

No Code Free / no-code inspector path exists for beacon creation — the article marks it "Not
Applicable."

**Godot GDScript**
```gdscript
SteamApi.CreateBeacon(3, my_lobby, "JoinGameSessionToken123", "GameMode=Deathmatch;Map=Arena",
    func(result, beacon_id): print(beacon_id))
```
Different shape from Unity — Foundation ties a beacon directly to a `LobbyData` (`my_lobby`
above), no separate beacon-location selection step. `openSlots` (`3`), `connectString`, and
`metadata` map straight across.

**Godot C#**
```csharp
API.Parties.Client.CreateBeacon(3, myLobby, "JoinGameSessionToken123", "GameMode=Deathmatch;Map=Arena",
    (result, beaconId) => { });
```
Same shape difference as GDScript. Verified against
`/home/loden/Dev/Codeberg/Godot-Foundation-for-Steamworks/addons/FoundationSteamworks/src/private/SteamApi.cpp:1466`
(native `SteamApi::CreateBeacon(int openSlots, const Ref<LobbyData> &lobby, const String
&connectString, const String &metadata, const Callable &callback)`) and
`/home/loden/Dev/Muninn/Godot-Toolkit-for-Steamworks/CSharp/API/API.Parties.cs:17` (C# facade,
`Instance.Call("CreateBeacon", ...)`) — both match the KB snippets exactly, no discrepancy found.

No Code Free / no-code path exists for Godot either — Toolkit's Godot editor plugin has no visual
authoring for any feature yet, Party included.

**O3DE** — not applicable. No `Beacon`/`Parties`/`ISteamParties` symbol of any kind exists in
either O3DE Foundation (`/home/loden/Dev/Codeberg/O3DE-Foundation-for-Steamworks/Code/`) or O3DE
Toolkit (`/home/loden/Dev/Muninn/O3DE-Toolkit-for-Steamworks/Code/`) source — confirmed by grep,
zero matches. Steam Parties is entirely unimplemented for O3DE at time of writing; don't fabricate
a call, tell the developer to check with Heathen directly.

---

## Join a party (via beacon)

The beacon ID arrives either on the launch command line (cold start) or via a Rich Presence Join
Requested callback (already running) — see the Steam Lobby reference's "detect a lobby on game
launch" section and the User reference's "Friends Invite to Game" section for the shared mechanism
this piggybacks on.

**Unity C#**
```csharp
// The beacon ID passed in on the connect command line
// or the connection string in Rich Presence Join Requested
PartyBeaconID_t beacon = new PartyBeaconID_t(123456789);
Parties.Client.JoinParty(beacon, HandleJoinParty);
```
Handler:
```csharp
private void HandleJoinParty(JoinPartyCallback_t Callback, bool IOError)
{
    // Callback.m_rgchConnectString: the connection string to connect to
    // Callback.m_SteamIDBeaconOwner, who you're looking to connect to
    // Callback.m_eResult the EResult of the request to join ... should be OK
}
```
Verified against `API.Parties.cs` — `JoinParty(PartyBeaconID_t beacon, Action<JoinPartyCallback_t,
bool> callback)` matches exactly.

**Host side — receiving the reservation notification (not shown in the source article, added
here from direct Foundation source verification, not KB content):**
```csharp
// Foundation-level event — fires when a user clicks your beacon and Steam
// notifies you of a reservation request.
SteamTools.Events.OnReservationNotification += HandleReservationNotification;

private void HandleReservationNotification(UserData user, PartyBeaconID_t party)
{
    // ... reserve a slot for `user` in your own game state, then once they
    // actually connect:
    Parties.Client.OnReservationCompleted(party, user.id);
    // or, if you don't have the beacon ID handy:
    Parties.Client.OnReservationCompleted(user);
}
```
Source: `SteamTools.cs:419` (event, Foundation), delegate at `SteamTools.cs:85`
(`SteamReservationNotificationDelegate(UserData user, PartyBeaconID_t party)`), raised at
`SteamTools.cs:648`. `OnReservationCompleted` overloads verified in
`API.Parties.cs` (`Parties.Client`, Toolkit). If you don't call one of these within Steam's
(undocumented) timeout window, the reserved slot may be released.

Not applicable Code Free path (article marks it "Not Applicable" for this section too).

**Godot — no join-by-beacon-ID path exists at all, GDScript or C#.** Confirmed by grep across the
full native binding surface
(`/home/loden/Dev/Codeberg/Godot-Foundation-for-Steamworks/addons/FoundationSteamworks/src/public/SteamApi.h`,
`src/private/SteamApi.cpp`) and the Toolkit C# facade
(`/home/loden/Dev/Muninn/Godot-Toolkit-for-Steamworks/CSharp/API/API.Parties.cs`): only
`GetNumActiveBeacons`/`GetBeaconByIndex`/`CreateBeacon`/`DestroyBeacon`/`ChangeNumOpenSlots` are
bound — no `JoinParty`, no `GetAvailableBeaconLocations`, no `GetBeaconDetails`, no
`GetBeaconLocationData`. **Work in progress** — this is a real, verified gap in the current
binding, not a doc omission.

**Godot — no reservation-notification event exists either.** Checked every signal defined in the
native extension (47 `ADD_SIGNAL` sites in `SteamApi.cpp`) and the full Godot C# event surface
(`/home/loden/Dev/Codeberg/Godot-Foundation-for-Steamworks/addons/FoundationSteamworks/CSharp/SteamToolsEvents.cs`,
184 lines) for anything Party/Beacon/Reservation-related — zero matches. Unlike Unity, where
Foundation ships exactly one bare event (`OnReservationNotification`) as its sole Party-related
Foundation-tier exception, **Godot has no Foundation-tier exception for Party at all** — the
host-side reservation notification simply isn't bound yet. If a developer needs this on Godot
today, tell them plainly that it doesn't exist rather than improvising a substitute.

**O3DE** — not applicable, same as above: no Party binding exists in O3DE source at all.

---

## Destroy a beacon

**Unity C#**
```csharp
// Given a beacon such as
PartyBeaconID_t beacon = new PartyBeaconID_t(123456789);

// Then
Parties.Client.DestroyBeacon(beacon);
```
Verified against `API.Parties.cs` — `public static bool DestroyBeacon(PartyBeaconID_t beacon)`
matches (return value discarded in the article's snippet, which is legal — not a bug). No Code
Free path shown in the article for this either.

**Godot GDScript**
```gdscript
SteamApi.DestroyBeacon(beacon_id)
```

**Godot C#**
```csharp
API.Parties.Client.DestroyBeacon(beaconHandle);
```
Both verified against
`/home/loden/Dev/Codeberg/Godot-Foundation-for-Steamworks/addons/FoundationSteamworks/src/private/SteamApi.cpp:1481`
(native `SteamApi::DestroyBeacon(int64_t beaconHandle)`) and
`/home/loden/Dev/Muninn/Godot-Toolkit-for-Steamworks/CSharp/API/API.Parties.cs:23` — match exactly,
no discrepancy found. No Code Free path exists for Godot.

**O3DE** — not applicable, no binding exists.

---

## Other verified members of `Parties.Client` not shown in the article's code blocks

**Unity**, present in source, mentioned only in the article's prose or not mentioned at all —
useful if a developer needs more than create/join/destroy:
- `Parties.Client.ChangeNumOpenSlots(PartyBeaconID_t beacon, uint openSlots, Action<ChangeNumOpenSlotsCallback_t, bool> callback)`
- `Parties.Client.GetBeacons()` → `PartyBeaconID_t[]` (your own active beacons)
- `Parties.Client.GetBeaconDetails(PartyBeaconID_t beacon)` → `PartyBeaconDetails?` (owner,
  location, metadata)
- `Parties.Client.GetBeaconLocationData(SteamPartyBeaconLocation_t location, ESteamPartyBeaconLocationData data, out string result)` → `bool`
- `Parties.Client.MyBeacons` → `PartyBeaconID_t[]` (property, beacons created this session)
- `Parties.Client.Reservations` → `ReservationNotificationCallback_t[]` (property, pending
  reservations not yet completed)

All verified in `/home/loden/Dev/Muninn/Unity-Toolkit-for-Steamworks/Runtime/API.Parties.cs`.

**Godot**, the complete bound surface (nothing left over beyond create/destroy shown above):
- `SteamApi.GetNumActiveBeacons()` / `API.Parties.Client.GetBeaconCount()` (C# facade renames it;
  cosmetic only) → `int`, count of your own active beacons.
- `SteamApi.GetBeaconByIndex(index)` / `API.Parties.Client.GetBeaconByIndex(index)` → `int64`/`ulong`
  beacon handle.
- `SteamApi.ChangeNumOpenSlots(beacon_handle, open_slots, callback)` /
  `API.Parties.Client.ChangeNumOpenSlots(beaconHandle, openSlots, callback)` — bound natively and
  has a full C# facade, unlike join/reservation which have neither.

All verified in
`/home/loden/Dev/Codeberg/Godot-Foundation-for-Steamworks/addons/FoundationSteamworks/src/public/SteamApi.h`
and `/home/loden/Dev/Muninn/Godot-Toolkit-for-Steamworks/CSharp/API/API.Parties.cs`. There is
**no** Godot equivalent of `GetBeaconDetails`, `GetBeaconLocationData`, `MyBeacons`, or
`Reservations` — the Godot binding is deliberately (or at least currently) a smaller subset of
Unity's.

**O3DE** — not applicable, no binding exists.

---

## If you're stuck

- Full human-readable article (all prose, screenshots) this file compresses out:
  
Party
- This file is generated from that article's raw content; if something here looks wrong, the article is the fallback source of truth, not this file's memory. - Related: Steam Lobby reference (different feature, same word "party" used for one of Lobby's three modes — don't confuse them): https://heathen.group/kb/lobby/ --- Back to the full Steam agent index: https://heathen.group/agent-ref-steam-index/