# Getting Started with Events (/learn/events/getting-started)



<Callout type="info">
  **Prerequisites:** KubeMQ server running on `localhost:50000` and your SDK installed. See [Getting Started](/deploy) for setup.
</Callout>

## What You Will Build [#what-you-will-build]

A notification publisher that sends order events and a subscriber that receives them in real time.

<Mermaid
  chart="graph LR
  PUB[&#x22;Publisher&#x22;]
  EV{{&#x22;Events channel<br/>order-notifications&#x22;}}
  S1[&#x22;Subscriber A&#x22;]
  S2[&#x22;Subscriber B&#x22;]
  S3[&#x22;Subscriber C<br/>(offline)&#x22;]

  PUB -- publish --> EV
  EV -- &#x22;at-most-once&#x22; --> S1
  EV -- &#x22;at-most-once&#x22; --> S2
  EV -. &#x22;missed&#x22; .-> S3

  class EV events
  class PUB,S1,S2 client
  class S3 external"
/>

The publisher fans out one event to every connected subscriber. Because Events are **at-most-once**, a subscriber that is offline (Subscriber C) misses the message — there is no replay.

<JsonLdHowTo
  name="Send your first KubeMQ event"
  step="[
  { name: 'Install the SDK', text: 'Install the KubeMQ client SDK for your language using its package manager (Go, Python, Node.js, Java, C#, Kotlin, C++, Rust, Ruby, or Elixir).' },
  { name: 'Create a Subscriber', text: 'Connect to KubeMQ and subscribe to the order-notifications channel before publishing, since Events are fire-and-forget and delivered only to subscribers already connected.' },
  { name: 'Create a Publisher', text: 'In a separate terminal, connect to KubeMQ and publish an order event to the order-notifications channel.' },
  { name: 'Run the Example', text: 'Start the subscriber first, then run the publisher in a separate terminal; the subscriber receives the event in real time.' },
  { name: 'Verify', text: 'Confirm the subscriber terminal logs the received event and the publisher terminal logs that the event was published.' },
]"
/>

## Steps [#steps]

<Steps>
  <Step>
    ### Install the SDK [#install-the-sdk]

    <Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
      <Tab value="Go">
        ```bash
        go get github.com/kubemq-io/kubemq-go/v2
        ```
      </Tab>

      <Tab value="Python">
        ```bash
        pip install kubemq
        ```
      </Tab>

      <Tab value="Node.js">
        ```bash
        npm install kubemq-js
        ```
      </Tab>

      <Tab value="Java">
        ```xml
        <dependency>
            <groupId>io.kubemq.sdk</groupId>
            <artifactId>kubemq-sdk-Java</artifactId>
            <version>3.1.1</version>
        </dependency>
        ```
      </Tab>

      <Tab value="C#">
        ```xml
        <PackageReference Include="KubeMQ.SDK.CSharp" Version="3.0.1" />
        ```
      </Tab>

      <Tab value="Kotlin">
        ```kotlin
        implementation("io.kubemq.sdk:kubemq-sdk-kotlin:1.0.1")
        ```
      </Tab>

      <Tab value="C++">
        ```bash
        vcpkg install kubemq
        ```
      </Tab>

      <Tab value="Rust">
        ```toml
        [dependencies]
        kubemq = "1.0"
        tokio = { version = "1", features = ["full"] }
        ```
      </Tab>

      <Tab value="Ruby">
        ```bash
        gem install kubemq
        ```
      </Tab>

      <Tab value="Elixir">
        ```elixir
        # mix.exs
        def deps do
          [{:kubemq, "~> 1.0"}]
        end
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step>
    ### Create a Subscriber [#create-a-subscriber]

    Start the subscriber first. Events are fire-and-forget, so the subscriber must be connected before the publisher sends events.

    <Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
      <Tab value="Go">
        ```go title="subscriber.go"
        package main

        import (
            "context"
            "fmt"
            "log"

            "github.com/kubemq-io/kubemq-go/v2"
        )

        func main() {
            ctx := context.Background()
            client, err := kubemq.NewClient(ctx,
                kubemq.WithAddress("localhost", 50000),
            )
            if err != nil {
                log.Fatal(err)
            }
            defer client.Close()

            sub, err := client.SubscribeToEvents(ctx, "order-notifications", "",
                kubemq.WithOnEvent(func(event *kubemq.Event) {
                    fmt.Printf("Received: %s\n", string(event.Body))
                }),
                kubemq.WithOnError(func(err error) {
                    log.Println("Subscription error:", err)
                }),
            )
            if err != nil {
                log.Fatal(err)
            }
            defer sub.Unsubscribe()

            log.Println("Subscriber listening on 'order-notifications'...")
            <-ctx.Done()
        }
        ```
      </Tab>

      <Tab value="Python">
        ```python title="subscriber.py"
        import time
        from kubemq.pubsub import Client as PubSubClient
        from kubemq.pubsub import EventsSubscription, CancellationToken

        def on_event(event):
            print(f"Received: {event.body.decode('utf-8')}")

        def on_error(err):
            print(f"Subscription error: {err}")

        client = PubSubClient(address="localhost:50000")
        cancel = CancellationToken()
        client.subscribe_to_events(
            subscription=EventsSubscription(
                channel="order-notifications",
                on_receive_event_callback=on_event,
                on_error_callback=on_error,
            ),
            cancel=cancel,
        )
        print("Subscriber listening on 'order-notifications'...")
        time.sleep(120)
        client.close()
        ```
      </Tab>

      <Tab value="Node.js">
        ```javascript title="subscriber.js"
        const { KubeMQClient } = require("kubemq-js");

        const client = new KubeMQClient({ address: "localhost:50000" });

        client.subscribeToEvents({
          channel: "order-notifications",
          onEvent: (msg) =>
            console.log(`Received: ${Buffer.from(msg.body).toString()}`),
          onError: (err) => console.error("Subscription error:", err.message),
        });

        console.log("Subscriber listening on 'order-notifications'...");
        ```
      </Tab>

      <Tab value="Java">
        ```java title="Subscriber.java"
        import io.kubemq.sdk.pubsub.PubSubClient;
        import io.kubemq.sdk.pubsub.EventsSubscription;

        PubSubClient client = PubSubClient.builder()
            .address("localhost:50000")
            .clientId("order-subscriber")
            .build();

        client.subscribeToEvents(EventsSubscription.builder()
            .channel("order-notifications")
            .onReceiveEventCallback(event ->
                System.out.println("Received: " + new String(event.getBody())))
            .onErrorCallback(err ->
                System.err.println("Subscription error: " + err.getMessage()))
            .build());

        System.out.println("Subscriber listening on 'order-notifications'...");
        Thread.sleep(120_000);
        client.close();
        ```
      </Tab>

      <Tab value="C#">
        ```csharp title="Subscriber.cs"
        using KubeMQ.Sdk.Client;
        using KubeMQ.Sdk.Events;
        using System.Text;

        await using var client = new KubeMQClient(new KubeMQClientOptions());
        await client.ConnectAsync();

        Console.WriteLine("Subscriber listening on 'order-notifications'...");
        await foreach (var msg in client.SubscribeToEventsAsync(
            new EventsSubscription { Channel = "order-notifications" }))
        {
            Console.WriteLine($"Received: {Encoding.UTF8.GetString(msg.Body.Span)}");
        }
        ```
      </Tab>

      <Tab value="Kotlin">
        ```kotlin title="Subscriber.kt"
        import io.kubemq.sdk.client.KubeMQClient
        import kotlinx.coroutines.runBlocking

        fun main() = runBlocking {
            val pubsub = KubeMQClient.pubSub {
                address = "localhost:50000"
                clientId = "order-subscriber"
            }

            println("Subscriber listening on 'order-notifications'...")
            pubsub.subscribeToEvents {
                channel = "order-notifications"
            }.collect { event ->
                println("Received: ${String(event.body)}")
            }
        }
        ```
      </Tab>

      <Tab value="C++">
        ```cpp title="subscriber.cpp"
        #include <kubemq/client.h>
        #include <iostream>

        auto client = kubemq::PubSubClient("localhost:50000");

        client.subscribeToEvents("order-notifications", "",
            [](const kubemq::Event& event) {
                std::cout << "Received: " << event.body << std::endl;
            },
            [](const std::string& err) {
                std::cerr << "Subscription error: " << err << std::endl;
            }
        );

        std::cout << "Subscriber listening on 'order-notifications'..." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(120));
        ```
      </Tab>

      <Tab value="Rust">
        ```rust title="subscriber.rs"
        use kubemq::prelude::*;
        use kubemq::Subscription;
        use std::time::Duration;

        #[tokio::main]
        async fn main() -> kubemq::Result<()> {
            let client = KubemqClient::builder()
                .host("localhost")
                .port(50000)
                .build()
                .await?;

            let sub: Subscription = client
                .subscribe_to_events(
                    "order-notifications",
                    "",
                    |event| {
                        Box::pin(async move {
                            println!("Received: {}", String::from_utf8_lossy(&event.body));
                        })
                    },
                    None,
                )
                .await?;

            println!("Subscriber listening on 'order-notifications'...");
            tokio::time::sleep(Duration::from_secs(120)).await;

            sub.unsubscribe().await;
            client.close().await?;
            Ok(())
        }
        ```
      </Tab>

      <Tab value="Ruby">
        ```ruby title="subscriber.rb"
        require 'kubemq'

        client = KubeMQ::PubSubClient.new(address: "localhost:50000", client_id: "order-subscriber")
        cancel = KubeMQ::CancellationToken.new

        sub = KubeMQ::PubSub::EventsSubscription.new(channel: "order-notifications")
        client.subscribe_to_events(sub, cancellation_token: cancel,
                                   on_error: ->(e) { puts "Subscription error: #{e.message}" }) do |event|
          puts "Received: #{event.body}"
        end

        puts "Subscriber listening on 'order-notifications'..."
        sleep 120
        cancel.cancel
        client.close
        ```
      </Tab>

      <Tab value="Elixir">
        ```elixir title="subscriber.exs"
        {:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "order-subscriber")

        {:ok, sub} =
          KubeMQ.Client.subscribe_to_events(client, "order-notifications",
            on_event: fn event -> IO.puts("Received: #{event.body}") end,
            on_error: fn err -> IO.puts("Subscription error: #{err.message}") end
          )

        IO.puts("Subscriber listening on 'order-notifications'...")
        Process.sleep(120_000)

        KubeMQ.Subscription.cancel(sub)
        KubeMQ.Client.close(client)
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step>
    ### Create a Publisher [#create-a-publisher]

    In a separate terminal, run the publisher. The subscriber receives the event instantly.

    <Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
      <Tab value="Go">
        ```go title="publisher.go"
        package main

        import (
            "context"
            "log"

            "github.com/kubemq-io/kubemq-go/v2"
        )

        func main() {
            ctx := context.Background()
            client, err := kubemq.NewClient(ctx,
                kubemq.WithAddress("localhost", 50000),
            )
            if err != nil {
                log.Fatal(err)
            }
            defer client.Close()

            err = client.SendEvent(ctx, kubemq.NewEvent().
                SetChannel("order-notifications").
                SetBody([]byte(`{"orderId":"ORD-1234","status":"created"}`)),
            )
            if err != nil {
                log.Fatal(err)
            }
            log.Println("Event published to 'order-notifications'")
        }
        ```
      </Tab>

      <Tab value="Python">
        ```python title="publisher.py"
        from kubemq.pubsub import Client as PubSubClient
        from kubemq.pubsub import EventMessage

        client = PubSubClient(address="localhost:50000")
        client.send_event(
            EventMessage(
                channel="order-notifications",
                body=b'{"orderId":"ORD-1234","status":"created"}',
            )
        )
        print("Event published to 'order-notifications'")
        client.close()
        ```
      </Tab>

      <Tab value="Node.js">
        ```javascript title="publisher.js"
        const { KubeMQClient } = require("kubemq-js");

        const client = new KubeMQClient({ address: "localhost:50000" });

        await client.sendEvent({
          channel: "order-notifications",
          body: Buffer.from(JSON.stringify({ orderId: "ORD-1234", status: "created" })),
        });

        console.log("Event published to 'order-notifications'");
        ```
      </Tab>

      <Tab value="Java">
        ```java title="Publisher.java"
        import io.kubemq.sdk.pubsub.PubSubClient;
        import io.kubemq.sdk.pubsub.EventMessage;

        PubSubClient client = PubSubClient.builder()
            .address("localhost:50000")
            .clientId("order-publisher")
            .build();

        client.sendEventsMessage(EventMessage.builder()
            .channel("order-notifications")
            .body("{\"orderId\":\"ORD-1234\",\"status\":\"created\"}".getBytes())
            .build());

        System.out.println("Event published to 'order-notifications'");
        client.close();
        ```
      </Tab>

      <Tab value="C#">
        ```csharp title="Publisher.cs"
        using KubeMQ.Sdk.Client;
        using KubeMQ.Sdk.Events;
        using System.Text;

        await using var client = new KubeMQClient(new KubeMQClientOptions());
        await client.ConnectAsync();

        await client.SendEventAsync(new EventMessage
        {
            Channel = "order-notifications",
            Body = Encoding.UTF8.GetBytes(
                "{\"orderId\":\"ORD-1234\",\"status\":\"created\"}")
        });

        Console.WriteLine("Event published to 'order-notifications'");
        ```
      </Tab>

      <Tab value="Kotlin">
        ```kotlin title="Publisher.kt"
        import io.kubemq.sdk.client.KubeMQClient
        import io.kubemq.sdk.pubsub.eventMessage
        import kotlinx.coroutines.runBlocking

        fun main() = runBlocking {
            val pubsub = KubeMQClient.pubSub {
                address = "localhost:50000"
                clientId = "order-publisher"
            }

            pubsub.publishEvent(eventMessage {
                channel = "order-notifications"
                body = """{"orderId":"ORD-1234","status":"created"}""".toByteArray()
            })

            println("Event published to 'order-notifications'")
        }
        ```
      </Tab>

      <Tab value="C++">
        ```cpp title="publisher.cpp"
        #include <kubemq/client.h>
        #include <iostream>

        auto client = kubemq::PubSubClient("localhost:50000");

        kubemq::EventMessage event;
        event.channel = "order-notifications";
        event.body = R"({"orderId":"ORD-1234","status":"created"})";

        client.sendEvent(event);
        std::cout << "Event published to 'order-notifications'" << std::endl;
        ```
      </Tab>

      <Tab value="Rust">
        ```rust title="publisher.rs"
        use kubemq::prelude::*;
        use kubemq::EventBuilder;

        #[tokio::main]
        async fn main() -> kubemq::Result<()> {
            let client = KubemqClient::builder()
                .host("localhost")
                .port(50000)
                .build()
                .await?;

            let event = EventBuilder::new()
                .channel("order-notifications")
                .body(br#"{"orderId":"ORD-1234","status":"created"}"#.to_vec())
                .build();

            client.send_event(event).await?;
            println!("Event published to 'order-notifications'");

            client.close().await?;
            Ok(())
        }
        ```
      </Tab>

      <Tab value="Ruby">
        ```ruby title="publisher.rb"
        require 'kubemq'

        client = KubeMQ::PubSubClient.new(address: "localhost:50000", client_id: "order-publisher")

        client.send_event(KubeMQ::PubSub::EventMessage.new(
          channel: "order-notifications",
          body: '{"orderId":"ORD-1234","status":"created"}'
        ))

        puts "Event published to 'order-notifications'"
        client.close
        ```
      </Tab>

      <Tab value="Elixir">
        ```elixir title="publisher.exs"
        {:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "order-publisher")

        event = KubeMQ.Event.new(
          channel: "order-notifications",
          body: ~s({"orderId":"ORD-1234","status":"created"})
        )

        :ok = KubeMQ.Client.send_event(client, event)
        IO.puts("Event published to 'order-notifications'")

        KubeMQ.Client.close(client)
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step>
    ### Run the Example [#run-the-example]

    1. Start the **subscriber** in one terminal
    2. Run the **publisher** in a separate terminal
    3. The subscriber receives the event in real time
  </Step>

  <Step>
    ### Verify [#verify]

    The subscriber terminal should display:

    ```text
    Subscriber listening on 'order-notifications'...
    Received: {"orderId":"ORD-1234","status":"created"}
    ```

    The publisher terminal should display:

    ```text
    Event published to 'order-notifications'
    ```
  </Step>
</Steps>

## What Just Happened [#what-just-happened]

<Mermaid
  chart="sequenceDiagram
    participant P as Publisher
    participant K as KubeMQ
    participant S as Subscriber
    S->>K: subscribe(&#x22;order-notifications&#x22;)
    P->>K: publish(&#x22;order-notifications&#x22;, event)
    K->>S: deliver event
    Note over S: Event received!"
/>

1. The **subscriber** connected to KubeMQ and registered interest in `order-notifications`
2. The **publisher** sent an event containing an order payload to the same channel
3. KubeMQ delivered the event to the subscriber in real time
4. Because Events are fire-and-forget, the publisher does not wait for acknowledgment

<Callout type="warn">
  Events have **at-most-once** delivery. If the subscriber was not connected when the event was published, the message would be lost. For persistent delivery with replay, use [Events Store](/learn/events-store/getting-started).
</Callout>

## Next Steps [#next-steps]

<Cards>
  <Card title="Publish & Subscribe" href="/learn/events/tutorials/publish-subscribe" description="Multiple subscribers, metadata, and tags." />

  <Card title="Consumer Groups" href="/learn/events/tutorials/consumer-groups" description="Load balance across subscribers." />

  <Card title="Events Reference" href="/learn/events/reference" description="Message structure and validation rules." />
</Cards>
