Aller au contenu principal

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énementVisibilité
PRICE_UPDATETous les abonnés du marché
ORDERBOOK_UPDATETous les abonnés du marché
TRADETous les abonnés du marché
MARKET_STATUSTous les abonnés du marché
POSITION_UPDATEUniquement l'opérateur propriétaire de la position
ORDER_UPDATEUniquement 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.