WebSocket API
L'API WebSocket fournit un flux en temps réel des données de marché, des transactions, des mises à jour du carnet d'ordres et des changements de position.
Endpoint: ws://{host}:8084/ws
Connexion
Authentifiez-vous à l'aide de votre clé API via l'en-tête X-Api-Key ou le paramètre de requête apiKey.
Via l'en-tête
const ws = new WebSocket('wss://polymarket.sandbox.playbatman.com/ws', {
headers: { 'X-Api-Key': 'your-api-key' }
});
Via le paramètre de requête
const ws = new WebSocket('wss://polymarket.sandbox.playbatman.com/ws?apiKey=your-api-key');
Réponse d'authentification
Lors d'une connexion réussie, vous recevez :
{
"type": "AUTHENTICATED",
"payload": {
"clientId": "ws-client-uuid",
"operatorId": "operator-uuid"
}
}
Si l'authentification échoue, la connexion est fermée avec le code 4001.
Abonnement aux marchés
Après la connexion, abonnez-vous aux marchés pour recevoir des mises à jour.
S'abonner
{
"type": "SUBSCRIBE",
"payload": {
"marketIds": ["market-uuid-1", "market-uuid-2"]
}
}
Vous pouvez également vous abonner à un seul marché :
{
"type": "SUBSCRIBE",
"payload": {
"marketIds": "market-uuid-1"
}
}
Réponse :
{
"type": "SUBSCRIBED",
"payload": {
"marketIds": ["market-uuid-1", "market-uuid-2"]
}
}
Se désabonner
{
"type": "UNSUBSCRIBE",
"payload": {
"marketIds": ["market-uuid-1"]
}
}
Réponse :
{
"type": "UNSUBSCRIBED",
"payload": {
"marketIds": ["market-uuid-1"]
}
}
Maintien de la connexion
Envoyez des pings périodiques pour maintenir la connexion active :
{ "type": "PING" }
Réponse :
{ "type": "PONG" }
Types d'événements
Une fois abonné à un marché, vous recevez les types d'événements suivants :
PRICE_UPDATE
Déclenché lorsque les prix du marché changent (après des transactions ou des modifications du carnet d'ordres).
{
"type": "PRICE_UPDATE",
"payload": {
"marketId": "market-uuid",
"prices": [
{
"marketId": "market-uuid",
"outcomeId": "outcome-uuid-1",
"outcomeName": "Yes",
"bestBid": 0.65,
"bestAsk": 0.68,
"lastPrice": 0.66,
"midPrice": 0.665,
"spread": 0.03,
"volume24h": 5000
},
{
"marketId": "market-uuid",
"outcomeId": "outcome-uuid-2",
"outcomeName": "No",
"bestBid": 0.32,
"bestAsk": 0.35,
"lastPrice": 0.34,
"midPrice": 0.335,
"spread": 0.03,
"volume24h": 4800
}
],
"timestamp": 1708293600000
}
}
ORDERBOOK_UPDATE
Déclenché lorsque le carnet d'ordres d'un résultat change.
{
"type": "ORDERBOOK_UPDATE",
"payload": {
"marketId": "market-uuid",
"outcomeId": "outcome-uuid",
"orderBook": {
"marketId": "market-uuid",
"outcomeId": "outcome-uuid",
"bids": [
{ "price": 0.65, "shares": 150, "orderCount": 3 }
],
"asks": [
{ "price": 0.68, "shares": 75, "orderCount": 2 }
],
"bestBid": 0.65,
"bestAsk": 0.68,
"spread": 0.03,
"timestamp": 1708293600000
},
"timestamp": 1708293600000
}
}
TRADE
Déclenché lorsqu'une transaction s'exécute dans un marché auquel vous êtes abonné.
{
"type": "TRADE",
"payload": {
"marketId": "market-uuid",
"outcomeId": "outcome-uuid",
"price": 0.66,
"shares": 50,
"side": "BUY",
"timestamp": 1708293600000
}
}
MARKET_STATUS
Déclenché lorsque le statut d'un marché change (ouvert, suspendu, fermé, résolu, etc.).
{
"type": "MARKET_STATUS",
"payload": {
"marketId": "market-uuid",
"status": "RESOLVED",
"timestamp": 1708293600000
}
}
POSITION_UPDATE
Déclenché lorsque la position de votre opérateur dans un marché change. Envoyé uniquement à l'opérateur propriétaire de la position.
{
"type": "POSITION_UPDATE",
"payload": {
"marketId": "market-uuid",
"operatorId": "operator-uuid",
"position": {
"id": "position-uuid",
"marketId": "market-uuid",
"outcomeId": "outcome-uuid",
"operatorId": "operator-uuid",
"shares": "150",
"avgPrice": "0.62",
"totalCost": "93",
"realizedPnl": "0"
},
"timestamp": 1708293600000
}
}
ORDER_UPDATE
Déclenché lorsqu'un des ordres de votre opérateur est mis à jour (exécuté, partiellement exécuté, annulé). Envoyé uniquement à l'opérateur propriétaire de l'ordre.
{
"type": "ORDER_UPDATE",
"payload": {
"marketId": "market-uuid",
"operatorId": "operator-uuid",
"order": {
"id": "order-uuid",
"marketId": "market-uuid",
"outcomeId": "outcome-uuid",
"operatorId": "operator-uuid",
"playerId": "player-123",
"side": "BUY",
"type": "LIMIT",
"shares": "50",
"price": "0.65",
"filledShares": "50",
"avgFillPrice": "0.63",
"remainingShares": "0",
"status": "FILLED",
"transactionId": "txn-001"
},
"timestamp": 1708293600000
}
}
ERROR
Envoyé lorsqu'une erreur survient lors du traitement d'un message.
{
"type": "ERROR",
"payload": {
"code": "INVALID_MESSAGE",
"message": "Unknown message type: INVALID"
}
}
Exemple complet
const WebSocket = require('ws');
const ws = new WebSocket('wss://polymarket.sandbox.playbatman.com/ws?apiKey=your-api-key');
ws.on('open', () => {
console.log('Connected');
});
ws.on('message', (data) => {
const message = JSON.parse(data);
switch (message.type) {
case 'AUTHENTICATED':
console.log('Authenticated as', message.payload.operatorId);
// Subscribe to a market
ws.send(JSON.stringify({
type: 'SUBSCRIBE',
payload: { marketIds: ['market-uuid'] }
}));
break;
case 'SUBSCRIBED':
console.log('Subscribed to', message.payload.marketIds);
break;
case 'PRICE_UPDATE':
console.log('Price update:', message.payload.prices);
break;
case 'TRADE':
console.log('Trade:', message.payload);
break;
case 'ORDER_UPDATE':
console.log('Order update:', message.payload.order);
break;
case 'POSITION_UPDATE':
console.log('Position update:', message.payload.position);
break;
case 'MARKET_STATUS':
console.log('Market status:', message.payload.status);
break;
case 'PONG':
break;
}
});
// Keep-alive ping every 30 seconds
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'PING' }));
}
}, 30000);
Visibilité des événements
| Événement | Visibilité |
|---|---|
PRICE_UPDATE | Tous les abonnés du marché |
ORDERBOOK_UPDATE | Tous les abonnés du marché |
TRADE | Tous les abonnés du marché |
MARKET_STATUS | Tous les abonnés du marché |
POSITION_UPDATE | Uniquement l'opérateur propriétaire de la position |
ORDER_UPDATE | Uniquement l'opérateur propriétaire de l'ordre |
Alternatives pour l'intégration backend
Le WebSocket est idéal pour les interfaces utilisateur en temps réel basées sur un navigateur. Pour les intégrations backend-à-backend, considérez ces alternatives :
- Webhooks — Recevez des notifications HTTP POST lorsque des événements surviennent. Plus fiable que le maintien d'une connexion WebSocket persistante depuis votre serveur. Inclut la signature HMAC-SHA256 et les tentatives automatiques.
- Rejeu d'événements — Récupérez les événements manqués via REST. Les événements sont conservés pendant 24 heures avec des numéros de séquence croissants de façon monotone pour une pagination fiable.
Un modèle recommandé pour l'intégration backend est d'utiliser les webhooks pour la livraison en temps réel et le rejeu d'événements comme filet de sécurité pour capturer tout événement manqué lors d'une interruption des webhooks.