# Pubb: stack-aware AI integration guide

Use this reference to add Pubb realtime features to an existing project.
Read the project's own instructions, inspect languages, runtimes, manifests,
lockfiles, code structure and authentication. Choose dependencies independently
for the client and trusted backend. Follow existing conventions and use the
project's package manager. Do not introduce Node.js, npm or a new backend simply
to integrate Pubb into a different stack. Adapt examples to the requested feature.

## Start here

1. Create an application at https://app.pubb.io/dashboard/apps/new.
2. Use placeholders while coding. The developer adds their app ID, public key and
   secret to the appropriate environment variables locally or at deployment.
3. Connect a client, subscribe to a channel, and publish an event from the server.
4. Explain how to run the integration and verify it using the application’s live
   console. Do not claim an integration was tested unless it was actually tested.

Your application’s end users continue using your existing authentication;
do not replace it to integrate messaging.

## Choose the SDK for this project

Official SDK sources are public under https://github.com/pubbio. All repositories
use main as their default branch. Installation guides use Git or locally built
packages; registry publication is a separate release step. Check the exact
runtime and installation instructions instead of guessing package names.

| Language | Scope | Installation and examples | Source |
| --- | --- | --- | --- |
| JavaScript / TypeScript | Client and server | https://pubb.io/docs/sdk/js | https://github.com/pubbio/sdk-js |
| .NET | Server | https://pubb.io/docs/sdk/dotnet | https://github.com/pubbio/sdk-dotnet |
| Swift | Apple client | https://pubb.io/docs/sdk/swift | https://github.com/pubbio/sdk-swift |
| Kotlin | Android/JVM client | https://pubb.io/docs/sdk/kotlin | https://github.com/pubbio/sdk-kotlin |
| Python | Server | https://pubb.io/docs/sdk/python | https://github.com/pubbio/sdk-python |
| Go | Server | https://pubb.io/docs/sdk/go | https://github.com/pubbio/sdk-go |
| PHP | Server | https://pubb.io/docs/sdk/php | https://github.com/pubbio/sdk-php |
| Java | Server | https://pubb.io/docs/sdk/java | https://github.com/pubbio/sdk-java |
| Flutter / Dart | Client | https://pubb.io/docs/sdk/dart | https://github.com/pubbio/sdk-dart |
| Ruby | Server | https://pubb.io/docs/sdk/ruby | https://github.com/pubbio/sdk-ruby |

Use the matching SDK for each part of a mixed-stack project. JavaScript's
@pubb/sdk/server is an import from @pubb/sdk, not a second npm package. Server
SDKs publish events and sign channel authorization; they must not be placed in
distributed clients. Client SDKs handle subscriptions and reconnects with a public
app key. If no SDK matches the runtime, use the HTTP/WebSocket protocol below with
its standard library or a suitable existing networking dependency. If the project
has no trusted backend, implement the subscriber and document the required server
publisher rather than putting secrets in the client or inventing another service.

## Addresses and credentials

| Purpose | Address |
| --- | --- |
| Console | https://app.pubb.io |
| Human-readable docs | https://pubb.io/docs |
| WebSocket connection | wss://ws.pubb.io/socket?appKey=YOUR_APP_KEY |
| Publish an event | POST https://api.pubb.io/api/apps/YOUR_APP_ID/events |
| Authorize a private subscription | POST https://api.pubb.io/api/apps/YOUR_APP_ID/auth |
| .NET integration guide | https://pubb.io/AGENTS-dotnet.md |

Server-side environment variables:

```env
PUBB_APP_ID=YOUR_APP_ID
PUBB_APP_KEY=YOUR_APP_KEY
PUBB_APP_SECRET=YOUR_APP_SECRET
```

Expose only the public app key to browser code using your framework’s public
configuration convention. Never put the app secret in a public-prefixed variable,
browser bundle, committed file, copied prompt or client-facing response.

The app ID and public key are different values. Publishing and signing requests
require `Authorization: Bearer YOUR_APP_SECRET`. Management endpoints are reserved
for the authenticated console; an app ID or user ID header grants no access.

## Browser client: native WebSocket

No SDK is required. This minimal example connects to a public channel:

```javascript
const channel = "notifications";
const socket = new WebSocket(
  "wss://ws.pubb.io/socket?appKey=YOUR_APP_KEY"
);

socket.onopen = () => {
  socket.send(JSON.stringify({ action: "subscribe", channel }));
};

socket.onmessage = ({ data }) => {
  const packet = JSON.parse(data);

  if (packet.event === "subscription_error") {
    console.error("Subscription failed", packet.data);
    return;
  }
  if (packet.channel !== channel) return;
  if (packet.event === "pusher_internal:subscription_succeeded") {
    console.log("Listening on", channel);
    return;
  }
  if (packet.event) return;

  const event = JSON.parse(packet.data);
  console.log(event.name, event.data);
};

socket.onerror = () => console.error("WebSocket connection failed");
socket.onclose = () => console.log("Disconnected");

// Call when the component or page is disposed:
// socket.close();
```

For React, create the connection inside an effect and close it in the effect’s
cleanup. Handle malformed messages, display connection status, and implement
bounded reconnect backoff with resubscription for production use. Re-fetch durable
application state after reconnecting. Do not create connections during render.

## Publish from the server

Call this from your trusted server logic after authenticating the caller and
checking that they may perform the underlying action. Do not expose an endpoint
that accepts arbitrary channels and publishes without an authorization check.

```javascript
const response = await fetch(
  `https://api.pubb.io/api/apps/${process.env.PUBB_APP_ID}/events`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${process.env.PUBB_APP_SECRET}`,
    },
    body: JSON.stringify({
      channel: "notifications",
      name: "order.created",
      data: { orderId: "1042", message: "On its way!" },
    }),
  }
);
if (response.status !== 202) throw new Error("Event publish failed");
const result = await response.json();
console.log("Accepted publication", result.publicationId);
```

`channel` may be one name or an array of 1–100 names. HTTP 202 confirms acceptance
for processing and returns `success`, `accepted`, `channels`, `publicationId` and
`duplicate`. This is not a delivery receipt. Subscribers receive
`{ "channel": "notifications", "data": "..." }`, where `data` is a JSON string
containing `{ "name": "order.created", "data": {...} }`.

Data is limited to 10 KiB of UTF-8 JSON. Use an `Idempotency-Key` header (1–128
printable nonspace ASCII characters) when retrying the same publication. Optional
`socket_id` excludes a connection. Events target connected subscribers and are not
durable history. Handle errors and backoff explicitly; server SDKs do not
retry publications automatically.

## Private and presence channels

| Name | Access |
| --- | --- |
| `notifications` | Public; anyone with the app key can subscribe |
| `private-user-42` | Requires a valid subscription signature |
| `presence-team-42` | Requires a signature and a user identity |

Use private channels for personal or restricted data. The `debug-` prefix is
reserved and cannot be subscribed to by clients.

The initial socket control message has `event: "pubb:connection_established"`.
Parse its JSON `data` field to get `socket_id`. Native clients must handle the documented control names. Legacy
`pusher:*` / `pusher_internal:*` identifiers remain for protocol compatibility;
SDKs expose known aliases as `pubb:*`. These names alone do not establish full
drop-in compatibility with unmodified Pusher clients or servers.

For a restricted channel, send `socket_id` and `channel_name` from the browser to
an authenticated endpoint in YOUR backend. That backend must determine the user
from their session and check access to the exact channel before calling Pubb:

```http
POST https://api.pubb.io/api/apps/YOUR_APP_ID/auth
Authorization: Bearer YOUR_APP_SECRET
Content-Type: application/json

{
  "socket_id": "CLIENT_SOCKET_ID",
  "channel_name": "private-user-42"
}
```

Return the resulting `auth` value to the browser. It subscribes with:

```javascript
socket.send(JSON.stringify({
  action: "subscribe",
  channel: "private-user-42",
  auth: authorization.auth,
}));
```

For presence, the server authorization request also includes `user_id` and optional
`user_info`, derived from the current user. Forward both returned `auth` and
`channel_data` unchanged in the subscribe command. The acknowledgement’s `data`
is an object containing `presence: { ids, hash, count }`. Membership updates use
`pubb:member_added` and `pubb:member_removed`. Both public events and presence
membership are isolated by application, including when channel names match.

Signatures can also be computed on your server using HMAC-SHA256:

- Private input: `socket_id:channel_name`
- Presence input: `socket_id:channel_name:channel_data`
- Output: `APP_KEY:lowercase_hex_signature`

Sign and send exactly the same serialized `channel_data` for presence.

## JavaScript SDK projects

The standalone source is https://github.com/pubbio/sdk-js. With Node.js 22+,
build the package and install its tarball into your existing JS/TS project:

```sh
git clone --branch main https://github.com/pubbio/sdk-js.git
cd sdk-js
npm ci
npm pack
# In the consumer application:
npm install /absolute/path/to/sdk-js/pubb-sdk-0.2.0.tgz
```

`@pubb/sdk/server` is the server entry point in the same package. The SDK defaults
to the Pubb hosts:

```typescript
import { Pubb as RealtimeClient } from "@pubb/sdk";
import { PubbServer as RealtimeServer } from "@pubb/sdk/server";

// Browser module. authEndpoint belongs to YOUR application.
const client = new RealtimeClient("YOUR_APP_KEY", {
  wsHost: "wss://ws.pubb.io",
  authEndpoint: "/api/realtime/auth",
});
const channel = client.subscribe("notifications");
channel.bind("order.created", data => console.log(data));
client.connect();

// Separate server-only module:
const server = new RealtimeServer({
  appId: process.env.PUBB_APP_ID!,
  key: process.env.PUBB_APP_KEY!,
  secret: process.env.PUBB_APP_SECRET!,
  apiHost: "https://api.pubb.io",
});
await server.trigger("notifications", "order.created", { orderId: "1042" });
```

For self-hosted installations, set both hosts explicitly. Review the SDK’s connection
lifecycle when adding cleanup or retries. The deployed API does not implement
`/api/apps/:id/channels`; do not use SDK channel-info helpers against that route.
Server-side diagnostics are available at `https://ws.pubb.io/channels?appKey=...`
and `/stats?appKey=...`, with the app’s Bearer secret. Do not expose these requests
to browser code because they require the secret.

## Verify your integration

- Confirm subscription acknowledgement before expecting delivery.
- Publish the same event name to the same channel and application.
- Verify browser data handling and component cleanup.
- For restricted data, check both successful access and rejection for other users.
- Try a network disconnect and confirm recovery without duplicate handlers.
- Use the console’s live event tool to diagnose delivery; historical analytics
  may be unavailable. The homepage playground is a local simulation.
