Official C++ SDK for OddSockets real-time messaging platform. Modern C++17, async, header-only option. libcurl + libwebsockets.
mkdir build && cd build
cmake ..
make#include <oddsockets/OddSockets.hpp>
oddsockets::Config config;
config.apiKey = "YOUR_API_KEY";
config.userId = "my-agent";
oddsockets::OddSockets client(config);
auto channel = client.channel("my-channel");
channel->subscribe([](const std::string& msg) { std::cout << msg << std::endl; });
channel->publish("{\"text\":\"Hello from C++\"}");Enhanced (Slack-like) events layer on top of the core pub/sub. The send side
lives on client.enhanced(); each call is fire-and-forget (void) and emits a real
worker event over the live socket. The matching broadcast arrives on the raw
client.on("<event>", ...) surface as a JSON payload string, so any subscriber in
the channel room can react.
#include <oddsockets/OddSockets.hpp>
#include <iostream>
oddsockets::Config config;
config.apiKey = "YOUR_API_KEY";
config.userId = "alice";
config.autoConnect = false;
oddsockets::OddSockets client(config);
client.connect().get();
auto channel = client.channel("room-42");
channel->subscribe([](const std::string&) {}).get();
// Receive-path: enhanced broadcasts arrive on the raw on() surface as JSON strings
client.on("user_typing", [](const std::string& payload) { std::cout << "typing: " << payload << "\n"; });
client.on("reaction_added", [](const std::string& payload) { std::cout << "reaction: " << payload << "\n"; });
// Send-path: fire enhanced actions over the live socket
client.enhanced().startTyping("alice", "room-42");
client.enhanced().addReaction("msg-1", "room-42", ":thumbsup:", "alice", "Alice");| Area | Send (client.enhanced()) |
Broadcast (client.on(...)) |
|---|---|---|
| Typing | startTyping(userId, channel) · stopTyping(userId, channel) |
user_typing · user_stopped_typing |
| Reactions | addReaction(messageId, channel, emoji, userId, userName) · removeReaction(messageId, channel, emoji, userId) |
reaction_added · reaction_removed |
The C++ enhanced surface is deliberately focused on typing and reactions. Any other
worker event your channel emits is still available directly on client.on("<event>", ...).
Ship game clients without embedding an API key. Give the config a tokenProvider
callback instead: your backend verifies the player (its own session/JWT), calls the
OddSockets POST /v1/token mint endpoint with its API key server-side, and returns
the short-lived token. The SDK invokes your callback for a fresh token before every
connect, and silently re-mints it before expiry on a background thread while the client
stays connected.
#include <oddsockets/OddSockets.hpp>
oddsockets::Config config;
config.userId = "player-1";
// No apiKey. The SDK calls this whenever it needs a fresh token
// (every connect + each pre-expiry refresh). Throw on failure.
config.tokenProvider = []() -> oddsockets::Token {
// Ask YOUR backend for an OddSockets token, e.g.
// POST https://your-game-backend.example.com/oddsockets/token
// (authenticated with the player's own session).
oddsockets::Token t;
t.token = fetchTokenFromMyBackend(); // the minted JWT
// Optional: t.exp (epoch seconds) or t.expiresAt (ISO 8601).
// Leave both unset and the SDK reads the JWT's own exp claim.
return t;
};
auto client = std::make_unique<oddsockets::OddSockets>(config);
client->on("token_refreshed", [](const std::string& payload) {
// {"expiresAt":<epoch ms>}
});
client->connect().get();Notes:
- Either an
apiKeyor atokenProvideris required — the constructor throwsInvalidApiKeywhen the config has neither. - The refreshed token is re-minted
config.tokenRefreshLeadMs(default120000) before the current one expires, on a dedicated background thread that is joined ondisconnect(). A failed refresh emitstoken_refresh_failedand keeps the current connection; the next connect mints fresh. - Expiry resolution order:
Token::exp(epoch seconds) →Token::expiresAt(ISO 8601) → theexpclaim decoded from the JWT itself.
curl -X POST https://oddsockets.com/api/agent-signup \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "agentName": "my-agent", "platform": "cpp"}'
curl -X POST https://oddsockets.com/api/agent-signup/verify \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "code": "123456", "agentName": "my-agent"}'| Free | Starter | Pro | |
|---|---|---|---|
| Price | $0/mo | $49.99/mo | $299/mo |
| MAU | 100 | 1,000 | 50,000 |
| Concurrent connections | 50 | 1,000 | Unlimited |
| Messages/day | 10,000 | 4,320,000 | Unlimited |
| Channels | 10 | Unlimited | Unlimited |
| Storage | 100MB (24h) | 50GB (6 months) | Unlimited |
Prove you can build and operate real-time features on OddSockets — channels, presence, pub/sub, delivery guarantees and production liveops — on the stack itself. Three tiers (TCU / TCA / TCP), certified through tyga.games and delivered on ClassaaS.
Get accredited on tyga.games →
MIT License - Copyright (c) 2026 Joe Wee, Tyga.Cloud Ltd. See LICENSE for details.