# Connecting and Sending a message to a Planet After logging in and joining a planet, you need to open a real-time connection before you can interact with it. This sets up the SignalR connection that delivers live events. > **Note:** Due to a bug in the Valour SDK the built-in channel cache is not working right now, so we use our own dictionary as a workaround. ### Creating a channel cache We store each channel by its ID so we can look them up quickly later. ```c# // Make your own channel cache using the channel's ID as the key Dictionary channelCache = new(); ``` ### Loading planet data Before we can read a planet's channels we need to fetch its data. We also loop through every channel and add it to the cache. ```c# // Get the first planet the bot joined Planet planet = client.PlanetService.JoinedPlanets.First(); // Load the planet's data await planet.EnsureReadyAsync(); await planet.FetchInitialDataAsync(); // Add every channel to the cache foreach (Channel chan in planet.Channels) { channelCache[chan.Id] = chan; } ``` ### Finding the default channel Now that the cache is filled we can grab the planet's primary chat channel to send messages to. ```c# // Fetch the default chat channel if (!channelCache.TryGetValue(planet.PrimaryChatChannel.Id, out var channel)) return; // Fall back to the first chat channel if the default wasn't found if (channel is null) { channel = planet.Channels.FirstOrDefault( c => c.ChannelType == ChannelTypeEnum.PlanetChat ); } // One final check if the channel is still null (very rare!) if (channel is null) { Console.WriteLine("Unable to find the Default or First channel"); } ``` ### Sending a message With a channel in hand, sending a message is just one line. ```c# // Send a message to the channel await channel.SendMessageAsync("Hello from my bot!"); ``` Great, your bot has sent its first message in your Planet!

### Full code below ```c# using Valour.Sdk.Client; using Valour.Shared; using DotNetEnv; using Valour.Sdk.Models; using Valour.Shared.Models; ValourClient client = new ValourClient("https://api.valour.gg/"); client.SetupHttpClient(); Env.Load(); string token = Environment.GetEnvironmentVariable("TOKEN") ?? string.Empty; // Make your own channel cache using the channel's ID as the key Dictionary channelCache = new(); if (string.IsNullOrWhiteSpace(token)) { Console.WriteLine($"Token invalid. Please make sure you set a valid token in your .env"); return; } TaskResult loginResult = await client.InitializeUser(token); if (!loginResult.Success) { Console.WriteLine($"Login failed: {loginResult.Message}"); } Console.WriteLine($"Logged in as {client.Me.Name} (ID: {client.Me.Id})"); // Get the first planet the bot joined Planet planet = client.PlanetService.JoinedPlanets.First(); // Load the planet's data await planet.EnsureReadyAsync(); await planet.FetchInitialDataAsync(); // Add every channel to the cache foreach (Channel chan in planet.Channels) { channelCache[chan.Id] = chan; } // Fetch the default chat channel if (!channelCache.TryGetValue(planet.PrimaryChatChannel.Id, out var channel)) return; // Fall back to the first chat channel if the default wasn't found if (channel is null) { channel = planet.Channels.FirstOrDefault( c => c.ChannelType == ChannelTypeEnum.PlanetChat ); } // One final check if the channel is still null (very rare!) if (channel is null) { Console.WriteLine("Unable to find the Default or First channel"); } // Send a message to the channel await channel.SendMessageAsync("Hello from my bot!"); await Task.Delay(Timeout.Infinite); ``` --- ## [The Next step is Receiving Messages and Commands](4.MessagesAndCommands.md)