# Kosmi API Reverse Engineering Findings ## Key Discovery: HTTP POST Works! After browser-based investigation, we discovered that Kosmi's GraphQL API works via **HTTP POST**, not just WebSocket! ### Working Endpoint ``` POST https://engine.kosmi.io/ Content-Type: application/json { "query": "{ __schema { types { name } } }" } ``` **Response**: ✅ 200 OK with proper GraphQL response ### WebSocket Issue The WebSocket endpoint `wss://engine.kosmi.io/gql-ws` returns **403 Forbidden** when connecting directly because: 1. **Missing Cookies**: The browser has session cookies that aren't accessible via `document.cookie` (HTTP-only) 2. **Missing Headers**: Likely needs `Origin: https://app.kosmi.io` header 3. **Session Required**: May need to establish a session first via HTTP ## Implementation Options ### Option 1: HTTP POST with Polling (Recommended for Now) **Pros**: - ✅ Works without authentication - ✅ Simple implementation - ✅ No WebSocket complexity **Cons**: - ❌ Not real-time (need to poll) - ❌ Higher latency - ❌ More bandwidth usage **Implementation**: ```go // Poll for new messages every 1-2 seconds func (c *GraphQLClient) PollMessages() { ticker := time.NewTicker(2 * time.Second) for range ticker.C { // Query for messages since last timestamp messages := c.QueryMessages(lastTimestamp) // Process new messages } } ``` ### Option 2: WebSocket with Session Cookies **Pros**: - ✅ Real-time updates - ✅ Efficient (push-based) - ✅ Lower latency **Cons**: - ❌ Requires session establishment - ❌ Need to handle cookies - ❌ More complex **Implementation**: ```go // 1. First, establish session via HTTP session := establishSession() // 2. Then connect WebSocket with cookies dialer := websocket.Dialer{ Jar: session.CookieJar, } conn, _, err := dialer.Dial(wsURL, http.Header{ "Origin": []string{"https://app.kosmi.io"}, "Cookie": []string{session.Cookies}, }) ``` ### Option 3: Hybrid Approach **Best of both worlds**: 1. Use HTTP POST for sending messages (mutations) 2. Use HTTP POST polling for receiving messages (queries) 3. Later upgrade to WebSocket when we figure out auth ## Next Steps ### Immediate (HTTP-based) 1. ✅ Update `graphql.go` to use HTTP POST instead of WebSocket 2. ✅ Implement message polling 3. ✅ Test with actual Kosmi room 4. ✅ Verify message sending works ### Future (WebSocket-based) 1. ⏳ Figure out session establishment 2. ⏳ Extract cookies from browser or create session 3. ⏳ Update WebSocket connection to include cookies 4. ⏳ Switch from polling to real-time subscriptions ## GraphQL Schema Discovery From the introspection query, we found these types: - `RootQueryType` - For queries - `RootMutationType` - For mutations - `Session` - Session management - `Success` - Success responses We need to explore the schema more to find: - Message query fields - Message mutation fields - Room/channel structures ## Testing Commands ### Test HTTP Endpoint ```bash curl -X POST https://engine.kosmi.io/ \ -H "Content-Type: application/json" \ -d '{"query": "{ __schema { types { name } } }"}' ``` ### Test with Go ```go resp, err := http.Post( "https://engine.kosmi.io/", "application/json", strings.NewReader(`{"query": "{ __schema { types { name } } }"}`), ) ``` ## Browser Findings ### Cookies Present ``` g_state={...} ``` Plus HTTP-only cookies we can't access. ### User Agent ``` Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 ``` ### Origin ``` https://app.kosmi.io ``` ## Recommendations **For MVP**: Use HTTP POST with polling - Simpler to implement - Works without authentication - Good enough for initial testing - Can upgrade to WebSocket later **For Production**: Figure out WebSocket auth - Better performance - Real-time updates - Lower bandwidth - Better user experience ## Updated Architecture ``` IRC Message ↓ Matterbridge ↓ Kosmi Bridge (HTTP POST) ↓ POST https://engine.kosmi.io/ ↓ Kosmi Room Kosmi Room ↓ Poll https://engine.kosmi.io/ (every 2s) ↓ Kosmi Bridge ↓ Matterbridge ↓ IRC Message ``` ## Action Items 1. **Update `graphql.go`**: - Replace WebSocket with HTTP client - Implement POST request method - Add polling loop for messages 2. **Test queries**: - Find the correct query for fetching messages - Find the correct mutation for sending messages - Test with actual room ID 3. **Implement polling**: - Poll every 1-2 seconds - Track last message timestamp - Only fetch new messages 4. **Document limitations**: - Note the polling delay - Explain why WebSocket doesn't work yet - Provide upgrade path --- **Status**: HTTP POST endpoint discovered and verified ✅ **Next**: Implement HTTP-based client to replace WebSocket