WebSocket de cuotas Pinnacle en Kotlin (OkHttp)
Respuesta: con OkHttp, construya un Request a wss://pinnfeed.io/v1/stream con cabecera x-api-key, llame newWebSocket, envíe un JSON subscribe en onOpen, y responda {"type":"pong"} a cada ping del servidor (cada 20 s). Frames: welcome, subscribed, partes snapshot, luego delta. Builder (99 €/mes) o Pro.
Gradle#
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("org.json:json:20240303")
}
Client#
import okhttp3.*
import org.json.JSONObject
import java.util.concurrent.TimeUnit
fun main() {
val key = System.getenv("PINNFEED_KEY") ?: error("set PINNFEED_KEY") // ps_live_...
val client = OkHttpClient.Builder().readTimeout(0, TimeUnit.MILLISECONDS).build()
fun connect(delayMs: Long = 0) {
Thread.sleep(delayMs)
val req = Request.Builder().url("wss://pinnfeed.io/v1/stream").header("x-api-key", key).build()
client.newWebSocket(req, object : WebSocketListener() {
override fun onOpen(ws: WebSocket, response: Response) {
ws.send("""{"type":"subscribe","sports":["soccer"],"markets":["moneyline"],"main":true}""")
}
override fun onMessage(ws: WebSocket, text: String) {
val msg = JSONObject(text)
when (msg.getString("type")) {
"ping" -> ws.send("""{"type":"pong"}""")
"delta" -> {
val changes = msg.getJSONArray("changes")
for (i in 0 until changes.length()) {
val ch = changes.getJSONObject(i)
if (ch.getString("kind") == "market" && ch.getString("op") == "upsert") {
val m = ch.getJSONObject("market")
if (m.optDouble("maxStake", 0.0) >= 100) println("${m.getLong("eventId")} ${m.getJSONArray("outcomes")}")
}
}
}
"error" -> println("error ${msg.optString("code")}: ${msg.optString("message")}")
}
}
override fun onClosed(ws: WebSocket, code: Int, reason: String) {
println("closed $code $reason")
if (code != 4001) connect(2000) // 4001 = key revoked
}
override fun onFailure(ws: WebSocket, t: Throwable, response: Response?) {
println("failure ${response?.code} ${t.message}")
connect(5000)
}
})
}
connect()
}
CTA#
Builder (€99/mes). Prueba de 3 días; tarjeta requerida. REST gratis: signup.
Preguntas frecuentes#
¿Por qué Builder?#
/v1/stream exige Builder o Pro. Free/Hobby reciben 403 plan_lacks_ws.
¿Hace falta un SDK oficial?#
No — OkHttp + JSON bastan.
¿Contenido educativo para adultos?#
Sí (18+).
Contenido educativo para mayores de 18 años. Sin pronósticos ni ganancias garantizadas. En España, apuesta solo con operadores con licencia de la DGOJ.