On the wire · 05:27:35 UTC Live 623 · Prematch 14,346 · Markets 57,229 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Tutorial · Swift · WebSocket

Pinnacle odds WebSocket in Swift

Updated · PinnFeed · 1 min read

Answer: create a URLRequest for wss://pinnfeed.io/v1/stream, set the x-api-key header, open it with URLSession.shared.webSocketTask(with:), send a JSON subscribe, and run a receive loop that replies {"type":"pong"} to each ping (every 20 s). Use it on macOS or a server; do not put a key inside an iOS app. Builder or Pro key required.

main.swift (macOS command-line tool)#

import Foundation

let key = ProcessInfo.processInfo.environment["PINNFEED_KEY"]!   // ps_live_...
var request = URLRequest(url: URL(string: "wss://pinnfeed.io/v1/stream")!)
request.setValue(key, forHTTPHeaderField: "x-api-key")
let task = URLSession.shared.webSocketTask(with: request)
task.maximumMessageSize = 32 * 1024 * 1024        // snapshot parts can be large
task.resume()

let sub = #"{"type":"subscribe","sports":["hockey"],"markets":["moneyline","total"],"main":true}"#
task.send(.string(sub)) { if let e = $0 { print("send error", e) } }

func receive() {
    task.receive { result in
        switch result {
        case .success(.string(let text)):
            if text.hasPrefix(#"{"type":"ping""#) {
                task.send(.string(#"{"type":"pong"}"#)) { _ in }
            } else {
                print(text.prefix(160))
            }
        case .success(.data(let data)):
            print("binary frame", data.count)
        case .failure(let error):
            print("closed:", task.closeCode.rawValue, error.localizedDescription)
            return
        @unknown default:
            break
        }
        receive()
    }
}
receive()
RunLoop.main.run()

Parse frames with JSONDecoder in real code; types follow the schema (snapshot, delta with changes[] of market/event upserts and removes).

Close codes#

4002 no_subscription (no subscribe in 30 s), 4008 slow_consumer (buffer over 16 MB), 4001 key_revoked. Reconnect with backoff and expect a fresh snapshot: reconnect.

Plans#

Builder (€99/mo, 3 connections) or Pro. 3-day trial; a card is required and it is charged after day 3 unless you cancel.

Educational content for adults (18+).

Questions people ask#

Why not call PinnFeed from the iPhone app?#

Anyone can extract a key from an app bundle. Run the stream on a server and expose your own API to the app: browser and app keys.

Why raise maximumMessageSize?#

The default limit is 1 MB and the first snapshot parts can be larger on broad subscriptions.

Vapor or SwiftNIO?#

Both have WebSocket clients that accept custom headers; the frames are identical.

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.