Les webhooks vous permettent de recevoir des notifications HTTP en temps réel lorsque des événements se produisent sur votre infrastructure M2S. Plus besoin de poller l’API : M2S vous notifie automatiquement.
| Événement | Description | Payload |
|---|---|---|
instance.created | Une instance a été créée | instance, user |
instance.deleted | Une instance a été supprimée | instance, user |
instance.started | Une instance a démarré | instance |
instance.stopped | Une instance s’est arrêtée | instance |
backup.completed | Un backup s’est terminé | backup, instance |
backup.failed | Un backup a échoué | backup, instance, error |
alert.triggered | Une alerte s’est déclenchée | alert, instance, metric |
invoice.created | Une facture a été générée | invoice, amount |
curl -X POST "https://api.m2s.cloud/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://votre-app.com/webhooks/m2s",
"events": ["instance.created", "instance.deleted", "backup.failed"],
"secret": "votre-secret-key",
"active": true
}'
# Réponse
{
"data": {
"id": "wh_abc123",
"url": "https://votre-app.com/webhooks/m2s",
"events": ["instance.created", "instance.deleted", "backup.failed"],
"secret": "whsec_xxxxxxxxxxxxx",
"active": true,
"created_at": "2024-01-20T10:00:00Z"
}
}
{
"id": "evt_xyz789",
"type": "instance.created",
"created_at": "2024-01-20T10:30:00Z",
"data": {
"instance": {
"id": "i-abc123",
"name": "web-prod-01",
"status": "running",
"plan": "business",
"region": "fr-par-1",
"ip_address": "51.15.0.100"
},
"user": {
"id": "usr_456",
"email": "admin@example.com"
}
}
}
Chaque webhook est signé avec un secret pour garantir son authenticité. Vérifiez toujours la signature avant de traiter le payload.
from flask import Flask, request, abort
import hmac
import hashlib
import json
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_xxxxxxxxxxxxx"
def verify_signature(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
@app.route('/webhooks/m2s', methods=['POST'])
def handle_webhook():
payload = request.get_data(as_text=True)
signature = request.headers.get('X-M2S-Signature')
if not verify_signature(payload, signature, WEBHOOK_SECRET):
abort(401)
event = json.loads(payload)
print(f"Événement reçu: {event['type']}")
# Traiter l'événement
if event['type'] == 'instance.created':
instance = event['data']['instance']
print(f"Nouvelle instance: {instance['name']}")
return {'status': 'ok'}, 200
const crypto = require('crypto');
const express = require('express');
const app = express();
const WEBHOOK_SECRET = 'whsec_xxxxxxxxxxxxx';
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
app.post('/webhooks/m2s', (req, res) => {
const payload = JSON.stringify(req.body);
const signature = req.headers['x-m2s-signature'];
if (!verifySignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
console.log(`Événement reçu: ${event.type}`);
res.json({ status: 'ok' });
});
Chaque requête webhook inclut les headers suivants :
| Header | Description |
|---|---|
X-M2S-Signature | Signature HMAC-SHA256 du payload |
X-M2S-Event-ID | ID unique de l’événement |
X-M2S-Event-Type | Type d’événement (ex: instance.created) |
X-M2S-Timestamp | Timestamp UNIX de l’événement |
Content-Type | application/json |
En cas d’échec de livraison, M2S réessaie automatiquement selon une politique exponentielle :
Après 5 échecs, le webhook est désactivé et une notification email est envoyée.
| Recommandé | À éviter |
|---|---|
| Vérifiez toujours la signature | Traiter sync dans le handler |
| Répondez rapidement (200 OK) | Ignorer la signature |
| Traitez async (queue/background) | Timeout trop long (> 30s) |
| Loguez les événements reçus | Endpoint HTTP non sécurisé |
| Gérez l’idempotence (X-M2S-Event-ID) | Pas de logs de débogage |