Paanj Paanj

Admin SDK

For trusted server-to-server communication. Requires your secret API key.

Installation

Install the Paanj Admin SDK for your server-side environment.

npm install @paanj/admin @paanj/chat-admin
go get github.com/paanj-cloud/paanj-go

Initialization & Connection

Initialize the client with your secret API key. This is a one-time setup for your server.

import { PaanjAdmin } from '@paanj/admin';
import { AdminChat } from '@paanj/chat-admin';

const admin = new PaanjAdmin('YOUR_SECRET_API_KEY');
await admin.connect();

const chat = new AdminChat(admin);

(async () => {
  try {
    // Listen to events
    chat.messages.onCreate((msg) => console.log('New message:', msg));
    console.log('Successfully connected to Paanj!');
  } catch (error) {
    console.error('Failed to connect:', error);
  }
})();
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
)

func main() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    if err := admin.Connect(); err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer admin.Disconnect()
    log.Println("Successfully connected to Paanj!")
}

Create a Participant

Provision a new participant (user) in your system.

(async () => {
  const newUser = await chat.users.create({
    email: 'john@example.com',
    name: 'John Doe',
    userData: { avatar: 'https://example.com/avatar.png' }
  });
  console.log('Participant created:', newUser.userId);
})();
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func createParticipant() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    user, err := chat.Users.Create(map[string]interface{}{
        "email": "john@example.com",
        "name":  "John Doe",
        "userData": map[string]interface{}{
            "avatar": "https://example.com/avatar.png",
        },
    })
    if err != nil {
        log.Fatalf("create participant failed: %v", err)
    }

    log.Printf("Participant created: %v", user["userId"])
}

Update a Participant

Update an existing participant's data.

(async () => {
  await chat.users.update('user-123', {
    email: 'newemail@example.com',
    userData: {
        name: 'Johnathan Doe',
        avatar: 'https://example.com/new-avatar.png',
        status: 'online'
    }
  });
  console.log('Participant updated successfully.');
})();
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func updateParticipant() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    _, err := chat.Users.Update("user-123", map[string]interface{}{
        "email": "newemail@example.com",
        "userData": map[string]interface{}{
            "name":   "Johnathan Doe",
            "avatar": "https://example.com/new-avatar.png",
            "status": "online",
        },
    })
    if err != nil {
        log.Fatalf("update participant failed: %v", err)
    }

    log.Println("Participant updated successfully")
}

Delete a Participant

Permanently delete a participant from your system. This action cannot be undone.

(async () => {
  await chat.users.delete('user-123');
  console.log('Participant deleted successfully.');
})();
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func deleteParticipant() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Users.Delete("user-123"); err != nil {
        log.Fatalf("delete participant failed: %v", err)
    }

    log.Println("Participant deleted successfully")
}

Create a Conversation

Create a new conversation for your participants.

(async () => {
  const groupChat = await chat.conversations.create({
    name: 'Project Phoenix',
    members: [
      { userId: 'user-123', role: 'admin' },
      { userId: 'user-456', role: 'member' }
    ],
    metadata: { department: 'engineering' }
  });
  console.log('Group chat created:', groupChat.id);
})();
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func createConversation() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    conversation, err := chat.Conversations.Create(map[string]interface{}{
        "name": "Project Phoenix",
        "members": []map[string]interface{}{
            {"userId": "123", "role": "admin"},
            {"userId": "456", "role": "member"},
        },
        "metadata": map[string]interface{}{"department": "engineering"},
    })
    if err != nil {
        log.Fatalf("create conversation failed: %v", err)
    }

    log.Printf("Group chat created: %v", conversation["id"])
}

Update a Conversation

Manage participants and their permissions within a conversation.

Add Participants

const conv = chat.conversation('group-abc');
await conv.addParticipant('user-789', 'member'); // Role is optional, defaults to 'member'
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func addParticipant() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Conversation("group-abc").AddParticipant("user-789", "member"); err != nil {
        log.Fatalf("add participant failed: %v", err)
    }

    log.Println("Participant added successfully")
}

Remove Participants

const conv = chat.conversation('group-abc');
await conv.removeParticipant('user-456');
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func removeParticipant() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Conversation("group-abc").RemoveParticipant("user-456"); err != nil {
        log.Fatalf("remove participant failed: %v", err)
    }

    log.Println("Participant removed successfully")
}

Delete a Conversation

Permanently delete a conversation and all its associated messages. This action cannot be undone.

await chat.conversations.delete('group-abc');
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func deleteConversation() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Conversations.Delete("group-abc"); err != nil {
        log.Fatalf("delete conversation failed: %v", err)
    }

    log.Println("Conversation deleted successfully")
}

Manage Blocks

As an admin, you can unilaterally block or unblock communication between any two participants.

Block User

// Block 'user-456' on behalf of 'user-123'
await chat.users('user-123').block('user-456');
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func blockUser() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Users.Block("user-123", "user-456"); err != nil {
        log.Fatalf("block failed: %v", err)
    }

    log.Println("Block applied successfully")
}

Unblock User

// Allow 'user-456' to contact 'user-123' again
await chat.users('user-123').unblock('user-456');
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func unblockUser() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Users.Unblock("user-123", "user-456"); err != nil {
        log.Fatalf("unblock failed: %v", err)
    }

    log.Println("Unblock applied successfully")
}

Listen for Admin Events

Listen for system-level events to build audit trails, monitoring, or automated workflows.

chat.users.onCreate((user) => {
  console.log('A new participant was created:', user);
});
chat.conversations.onCreate((conversation) => {
  console.log('A new conversation was created:', conversation);
});
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func main() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    if err := admin.Connect(); err != nil {
        log.Fatalf("connect failed: %v", err)
    }
    defer admin.Disconnect()

    chat := chatadmin.NewAdminChat(admin)

    chat.Users.OnCreate(func(data interface{}) {
        log.Printf("A new participant was created: %+v", data)
    })
    chat.Conversations.OnCreate(func(data interface{}) {
        log.Printf("A new conversation was created: %+v", data)
    })
    chat.Messages.OnCreate(func(data interface{}) {
        log.Printf("A new message was created: %+v", data)
    })
}

Subscribe to a Conversation

Subscribe to all messages sent to a specific conversation. Listen for real-time message events.

(async () => {
  const conversation = chat.conversation('group-abc');
  conversation.onMessage((message) => {
    console.log('New message:', message);
  });
})();
package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func main() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    if err := admin.Connect(); err != nil {
        log.Fatalf("connect failed: %v", err)
    }
    defer admin.Disconnect()

    chat := chatadmin.NewAdminChat(admin)
    conversation := chat.Conversation("group-abc")
    conversation.OnMessage(func(message interface{}) {
        log.Printf("New message: %+v", message)
    })
}

Send a Message

Send a message to a specific conversation from the admin.

(async () => {
  const conversation = chat.conversation('group-abc');
  await conversation.send('Hello, world!');
  console.log('Message sent successfully.');
})();

Note: The SDK currently only supports sending string content. If you want to send JSON, please stringify it first.

package main

import (
    "log"
    adminpkg "github.com/paanj-cloud/paanj-go/admin"
    chatadmin "github.com/paanj-cloud/paanj-go/chat/admin"
)

func main() {
    admin := adminpkg.NewAdmin("YOUR_SECRET_API_KEY", adminpkg.AdminOptions{
        ApiUrl: "https://api.paanj.com",
        WsUrl:  "wss://ws.paanj.com",
    })
    chat := chatadmin.NewAdminChat(admin)

    if _, err := chat.Conversation("group-abc").Send(
        "Hello, world!",
        map[string]interface{}{"source": "admin-docs"},
    ); err != nil {
        log.Fatalf("send failed: %v", err)
    }
}

Client SDK

For client-side applications. Requires a public API key.

Installation

Install the Paanj Client SDK to build your front-end application.

npm install @paanj/client @paanj/chat-client
go get github.com/paanj-cloud/paanj-go
flutter pub add paanj_client paanj_chat_client

Initialization

Initialize the client with your public API key.

import { PaanjClient } from '@paanj/client';
import { ChatClient } from '@paanj/chat-client';

const client = new PaanjClient({
  apiKey: 'YOUR_PUBLIC_API_KEY'
});
const chat = new ChatClient(client);
package main

import (
    "log"
    chatclient "github.com/paanj-cloud/paanj-go/chat/client"
    "github.com/paanj-cloud/paanj-go/client"
)

func main() {
    c := client.NewClient(client.ClientOptions{ApiKey: "YOUR_PUBLIC_API_KEY"})
    chat := chatclient.NewChatClient(c)
    _ = chat
    log.Println("Initialized Paanj Go client and chat client")
}
import 'package:paanj_client/paanj_client.dart';
import 'package:paanj_chat_client/paanj_chat_client.dart';

final client = PaanjClient(
  'YOUR_PUBLIC_API_KEY',
  options: ClientOptions(
    apiKey: 'YOUR_PUBLIC_API_KEY',
    apiUrl: 'https://api.paanj.com',
    wsUrl: 'wss://ws.paanj.com',
    persistSession: true,
  ),
);

final chat = ChatClient(client);

Authentication

Create an anonymous user to start interacting. This will return a session with an access token.

// Create an anonymous user with private data
// Private data is not stored but sent to webhooks
const session = await client.authenticateAnonymous({
    name: 'John Doe',
    metadata: { email: 'john@example.com' }
}, {
    internalId: 'u_789'
});

console.log('User ID:', session.userId);
console.log('Access Token:', session.accessToken);
// Authenticate anonymous user (example)
package main

import (
    "log"
    "github.com/paanj-cloud/paanj-go/client"
)

func main() {
    c := client.NewClient(client.ClientOptions{ApiKey: "YOUR_PUBLIC_API_KEY"})
    auth, err := c.AuthenticateAnonymous(map[string]interface{}{"name": "Go User"}, nil)
    if err != nil {
        log.Fatalf("auth failed: %v", err)
    }
    log.Printf("Authenticated user: %s", auth.UserId)
}
final session = await client.authenticateAnonymous(
  {
    'name': 'Flutter User',
    'metadata': {'email': 'john@example.com'},
  },
);

await client.connect();

print('User ID: ${session.userId}');
print('Access Token: ${session.accessToken}');

Create a Conversation

Create a new conversation. You can add other users by their ID.

// Create a conversation
const conversation = await chat.conversations.create({
  name: 'Team Project',
  participants: [
    { userId: 'user_456', role: 'member' } // Add another user
    // You (creator) are automatically added as admin
  ],
  metadata: { isPrivate: false }
});

// You are automatically subscribed to this conversation
console.log('Conversation created:', conversation.id);
package main

import (
    "log"
    chatclient "github.com/paanj-cloud/paanj-go/chat/client"
    "github.com/paanj-cloud/paanj-go/client"
)

func main() {
    c := client.NewClient(client.ClientOptions{ApiKey: "YOUR_PUBLIC_API_KEY"})
    chat := chatclient.NewChatClient(c)

    if _, err := c.AuthenticateAnonymous(map[string]interface{}{"name": "Go User"}, nil); err != nil {
        log.Fatalf("auth failed: %v", err)
    }

    conversation, err := chat.Conversations.Create(map[string]interface{}{
        "name": "Team Project",
        "participants": []map[string]interface{}{
            {"userId": "456", "role": "member"},
        },
        "metadata": map[string]interface{}{"isPrivate": false},
    })
    if err != nil {
        log.Fatalf("create conversation failed: %v", err)
    }

    log.Printf("Conversation created: %v", conversation["id"])
}
final conversation = await chat.createConversation(
  CreateConversationData(
    name: 'Team Project',
    participants: [
      ConversationMember(userId: 'user_456', role: 'member'),
    ],
    metadata: {'isPrivate': false},
  ),
);

print('Conversation created: ${conversation.id}');

List Conversations

Retrieve a list of conversations you are a member of.

// List conversations with fluent API
const conversations = await chat.conversations.list()
    .limit(10)
    .offset(0);
console.log('Conversations:', conversations);
// List conversations (Go)
result, err := chat.Conversations.List(map[string]interface{}{
    "limit":  10,
    "offset": 0,
})
if err != nil {
    log.Fatalf("list conversations failed: %v", err)
}

log.Printf("Conversations response: %+v", result)
if conversations, ok := result["conversations"]; ok {
    log.Printf("Conversations: %+v", conversations)
}
final conversations = await chat.listConversations(
  filters: ConversationFilters(limit: 10, page: 1),
);

print('Conversations: $conversations');

Real-time Messaging

Connect to the WebSocket server to send and receive messages in real-time.

// Connect to WebSocket
await client.connect();

// Listen for messages globally
chat.conversations.onMessage((msg) => {
    console.log('New message:', msg.content);
    console.log('From User:', msg.senderId);
});

// Send a message
const ctx = chat.conversations(conversation.id);
await ctx.send('Hello, world!');
// Connect, listen and send (Go)
package main

import (
    "log"
    chatclient "github.com/paanj-cloud/paanj-go/chat/client"
    "github.com/paanj-cloud/paanj-go/client"
)

func main() {
    c := client.NewClient(client.ClientOptions{ApiKey: "test-api-key"})
    chat := chatclient.NewChatClient(c)
    conversationID := "YOUR_CONVERSATION_ID"

    chat.Conversations.OnMessage(func(data interface{}) {
        log.Printf("New message: %v", data)
    })

    if _, err := c.AuthenticateAnonymous(map[string]interface{}{"name": "Go User"}, nil); err != nil {
        log.Fatalf("auth failed: %v", err)
    }
    if err := c.Connect(); err != nil {
        log.Fatalf("connect failed: %v", err)
    }

    conv := chat.Conversation(conversationID)
    conv.OnMessage(func(data interface{}) {
        log.Printf("Conversation message: %v", data)
    })
    if _, err := conv.Send("Hello from Go SDK!"); err != nil {
        log.Printf("send failed: %v", err)
    }
}
await client.connect();

chat.onMessage((dynamic msg) {
  print('New message: ${msg.content}');
  print('From User: ${msg.senderId}');
});

final ctx = chat.conversation(conversation.id);
final stopConversationMessages = ctx.onMessage((Message msg) {
  print('Conversation message: ${msg.content}');
});

await ctx.send('Hello, world!');
stopConversationMessages();

List Messages

Retrieve message history with a fluent API.

// List messages with fluent API
const messages = await chat.conversations(conversation.id)
    .messages()
    .list()
    .limit(20)
    .page(1);

console.log('History:', messages);
// List messages (Go)
conversationID := "YOUR_CONVERSATION_ID"
messages, err := chat.Conversation(conversationID).Messages().List(map[string]interface{}{
    "limit":  20,
    "offset": 0,
})
if err != nil {
    log.Fatalf("list messages failed: %v", err)
}

log.Printf("History: %+v", messages)
final messages = await chat
    .conversation(conversation.id)
    .messages()
    .list(filters: MessageFilters(limit: 20, page: 1));

print('History: $messages');

Manage Conversations

Manage conversation membership and settings.

const cnv = chat.conversations(conversation.id);

// Leave a conversation
await cnv.leave();

// List participants
const participants = await cnv.participants().list();
console.log('Participants:', participants);

// Add a participant (if you have permission)
await cnv.participants().add('user_789', 'member');

// Get conversation details
const details = await cnv.get();
console.log('Details:', details);

// Listen for updates
cnv.onUpdate((update) => {
    console.log('Conversation updated:', update);
});
// Manage conversations (Go)
conversationID := "YOUR_CONVERSATION_ID"
cnv := chat.Conversation(conversationID)

participants, err := cnv.Participants().List()
if err != nil {
    log.Fatalf("list participants failed: %v", err)
}
log.Printf("Participants: %+v", participants)

if _, err := cnv.Participants().Add("789", "member"); err != nil {
    log.Printf("add participant failed: %v", err)
}

details, err := cnv.Get()
if err != nil {
    log.Printf("get conversation failed: %v", err)
} else {
    log.Printf("Details: %+v", details)
}

cnv.OnUpdate(func(data interface{}) {
    log.Printf("Conversation updated: %+v", data)
})

if err := cnv.Leave(); err != nil {
    log.Printf("leave conversation failed: %v", err)
}
final cnv = chat.conversation(conversation.id);

final participants = await cnv.participants().list();
print('Participants: $participants');

await cnv.participants().add('user_789', role: 'member');

final details = await cnv.get();
print('Details: $details');

final stopUpdates = cnv.onUpdate((dynamic update) {
  print('Conversation updated: $update');
});

await cnv.leave();

stopUpdates();
cnv.dispose();

Block and Unblock Users

Users can block other users to prevent unwanted communication.

// Block a user
await chat.users('user_456').block();

// Get blocked users
const blockedUsers = await chat.users.getBlocked();
console.log('Blocked users:', blockedUsers);

// Unblock a user
await chat.users('user_456').unblock();
// Block and unblock users (Go)
if _, err := chat.User("456").Block(); err != nil {
    log.Fatalf("block failed: %v", err)
}

blocked, err := chat.Users.GetBlocked()
if err != nil {
    log.Fatalf("get blocked users failed: %v", err)
}
log.Printf("Blocked users: %+v", blocked["blockedUserIds"])

if _, err := chat.User("456").Unblock(); err != nil {
    log.Fatalf("unblock failed: %v", err)
}

chat.Users.OnTokenRefresh(func(data interface{}) {
    log.Printf("token updated: %+v", data)
})
await chat.user('user_456').block();

final blockedUsers = await chat.getBlockedUsers();
print('Blocked users: $blockedUsers');

await chat.user('user_456').unblock();

final stopGlobalTokenRefresh = chat.onTokenRefresh((dynamic data) {
  print('Token updated: $data');
});
final stopUserTokenRefresh = chat.user('user_456').onTokenRefresh((dynamic data) {
  print('User token updated: $data');
});

stopGlobalTokenRefresh();
stopUserTokenRefresh();