On the wire · 05:17:37 UTC Live 600 · Prematch 14,341 · Markets 57,274 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Answer · Java · WebSocket

Pinnacle odds WebSocket in Java

Updated · PinnFeed · 2 min read

Answer: with Java 11 or newer you need no library: HttpClient.newWebSocketBuilder() can set the x-api-key header, connect to wss://pinnfeed.io/v1/stream, send a JSON subscribe, and answer the server's ping (every 20 seconds) with {"type":"pong"}. Frames arrive as welcome, subscribed, snapshot parts and then delta frames. Builder (€99/mo) is required.

Minimal client#

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;

public class PinnFeedStream {
  public static void main(String[] args) throws Exception {
    String key = System.getenv("PINNFEED_KEY"); // ps_live_...
    CountDownLatch closed = new CountDownLatch(1);
    WebSocket.Listener listener = new WebSocket.Listener() {
      final StringBuilder buf = new StringBuilder();
      public void onOpen(WebSocket ws) {
        ws.sendText("{\"type\":\"subscribe\",\"sports\":[\"soccer\"],\"markets\":[\"moneyline\"],\"main\":true}", true);
        ws.request(1);
      }
      public CompletionStage<?> onText(WebSocket ws, CharSequence part, boolean last) {
        buf.append(part);
        if (last) {
          String msg = buf.toString();
          buf.setLength(0);
          if (msg.startsWith("{\"type\":\"ping\"")) ws.sendText("{\"type\":\"pong\"}", true);
          else System.out.println(msg.length() > 160 ? msg.substring(0, 160) + "..." : msg);
        }
        ws.request(1);
        return null;
      }
      public CompletionStage<?> onClose(WebSocket ws, int code, String reason) {
        System.out.println("closed " + code + " " + reason);
        closed.countDown();
        return null;
      }
      public void onError(WebSocket ws, Throwable e) {
        e.printStackTrace();
        closed.countDown();
      }
    };
    HttpClient.newHttpClient().newWebSocketBuilder()
        .header("x-api-key", key)
        .buildAsync(URI.create("wss://pinnfeed.io/v1/stream"), listener)
        .join();
    closed.await();
  }
}

Run with java PinnFeedStream.java (Java 11+ single-file launch). Large snapshots arrive in several text parts, which is why the listener buffers until last is true. Parse with Jackson or Gson in real code.

Close codes to handle#

CodeMeaningFix
4002 no_subscriptionNo subscribe within 30 sSend it in onOpen
4008 slow_consumerYour client fell behind (server buffer over 16 MB)Process frames off the listener thread; subscribe to fewer markets
HTTP 403 plan_lacks_wsFree or Hobby keyUse a Builder or Pro key

The server drops the connection if it hears no pong for 60 seconds. Reconnect with backoff and expect a fresh snapshot: reconnect pattern, ping/pong, snapshot/delta. Other languages: Go, C#, Rust, TypeScript.

Plans#

The WebSocket is on Builder (€99/mo, 3 connections) and Pro. 3-day trial; a card is required and it is charged after day 3 unless you cancel. Prototype on Free REST first: signup.

Educational content for adults (18+).

See also: Swift client.

Questions people ask#

Is there an official Java SDK?#

No. The JDK client plus a JSON library is enough.

Kotlin or Spring?#

The same frames work with OkHttp's WebSocket or Spring's WebSocketClient; set the x-api-key header the same way. Full example: Kotlin + OkHttp.

Can I pass the key in the URL?#

Yes, wss://pinnfeed.io/v1/stream?key=ps_live_... works; the header keeps it out of logs.

The WebSocket plan: Builder, €99/mo.

Real-time Pinnacle odds pushed over one WebSocket, all 13 sports, every market, no-vig fair odds and closing lines. 3 days free, cancel in one click.

Form K-1 · Free API key

Get your free API key.

One field. No password, no card: enter your email, click the link we send, and your key is on screen.

By continuing you agree to the Terms and Privacy Policy.

One free key per email. Link valid for 20 minutes.