Aperçu
L’API Vito permet à votre application de travailler avec le solde Vito d’un utilisateur depuis Discord — le lire, le débiter ou le recréditer. L’utilisateur confirme chaque débit avec son code PIN sur vetox.io avant que le moindre Vito ne bouge, et votre app est notifiée du résultat. Vito est la monnaie virtuelle interne de l’écosystème Vetox ; utilisez l’API pour créer des expériences basées sur Vito — débloquer du contenu, des fonctionnalités, des avantages ou des récompenses. Aucun achat ni vente avec de l’argent réel n’a lieu.
C’est une API REST authentifiée par une clé secrète. Tous les endpoints renvoient du JSON et sont versionnés sous /v1.
https://api.vetox.io/public/vito/v1Soldes et règlement
Votre clé API est liée à votre compte Vetox. Chaque débit est réglé à votre profit : lorsque votre application déduit des Vito à un utilisateur, ces Vito sont crédités sur votre propre solde (déduction faite des frais de plateforme), jamais détruits. Lorsque votre application ajoute des Vito à un utilisateur, ils sont financés depuis votre solde.
Les Vito circulent toujours entre les soldes — jamais depuis ou vers de l’argent réel. L’utilisateur est débité du montant total que vous demandez ; vous recevez le montant après les frais de plateforme ; les crédits et récompenses sont financés depuis votre solde via /add.
Prérequis
L’accès à l’API Vito est accordé par projet. Avant de pouvoir l’appeler, il vous faut :
- Un abonnement utilisateur actif (niveau Silver ou supérieur). L’API se gèle automatiquement si l’abonnement du propriétaire expire, et se rétablit lorsqu’il se réabonne.
- Une demande de développeur approuvée. Soumettez-en une depuis cette page ; l’équipe Vetox l’examine manuellement.
- Conditions développeur de l'API acceptées — validées lors de l'envoi de votre demande de développeur.
- Les portées dont votre projet a besoin. Elles sont accordées par l’équipe Vetox selon votre demande.
Portées disponibles
balance:readdeduct:createcredit:createtransfer:createtransactions:readAuthentification
Authentifiez chaque requête avec votre clé API secrète dans l’en-tête Authorization sous forme de jeton Bearer. Les clés portent le préfixe vito_live_.
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxxDeux couches facultatives protègent davantage votre projet :
- Liste d’IP autorisées — restreignez les requêtes à des IP de serveur précises (configurez-la dans l’onglet Paramètres).
- Limites de débit — plafonds de requêtes par projet qui évoluent selon votre niveau d’abonnement.
Clés API — stockage, rotation et sécurité
Votre clé est générée à l’approbation de votre demande. Elle n’est affichée qu’une seule fois — révélez-la depuis l’onglet Clés API et stockez-la immédiatement.
Vetox ne stocke jamais votre clé sous forme lisible (seulement un hachage salé). Conservez-la comme un secret côté serveur — une variable d’environnement ou un gestionnaire de secrets — jamais dans le code client, un dépôt git ou un navigateur.
Faites-la tourner depuis l’onglet Clés API. L’ancienne clé continue de fonctionner pendant une période de grâce de 24 heures pour déployer la nouvelle sans interruption, puis elle s’arrête.
Parcours de confirmation du débit
Chaque débit passe par une confirmation que l’utilisateur approuve avec son code PIN — votre clé seule ne déplace jamais de Vito :
- 1Votre app appelle POST /deduct avec l’utilisateur, le montant, le guildId d’origine et les détails de l’élément.
- 2Vito crée une confirmation en attente (valable 10 minutes) et renvoie une confirmUrl. Si un guildId est fourni, l’utilisateur reçoit aussi un DM avec les détails et un bouton vers la page de confirmation.
- 3L’utilisateur ouvre la confirmUrl sur vetox.io et approuve le débit avec le PIN de son portefeuille.
- 4Vito déduit les Vito, enregistre la transaction et — si un webhook est configuré — envoie un événement confirmation.completed signé à votre URL de callback.
- 5Votre app vérifie la signature et effectue son action (par exemple, débloque le contenu).
Paramètres de la requête (/deduct)
/v1/deductL’endpoint de déduction accepte les champs de corps suivants :
discordIdamountguildIdreasonmerchantRefproductproduct.imageUrlmetadata* champ obligatoire.
POST https://api.vetox.io/public/vito/v1/deduct
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
Idempotency-Key: req_9a1f2b # optional, dedupes retries for 24h
{
"discordId": "123456789012345678",
"amount": 500,
"guildId": "1470389021162209280",
"reason": "Unlock premium theme",
"merchantRef": "ref_1042",
"product": {
"type": "feature",
"name": "Premium theme",
"description": "Unlocks the premium theme pack",
"imageUrl": "https://cdn.example.com/theme.png"
},
"metadata": { "ref": "1042" }
}{
"success": true,
"data": {
"confirmationId": "f3c9...e1",
"confirmUrl": "https://vetox.io/confirm/vito/f3c9...e1",
"amount": 500,
"expiresAt": 1735689600000,
"status": "pending"
},
"requestId": "req_abc123",
"timestamp": 1735689300000
}Ajouter des Vito — crédits (/add)
/v1/addPOST /add crédite un utilisateur de Vito depuis votre propre solde — pour des récompenses ou des crédits. Il prend les mêmes champs que /deduct sauf guildId et product. Contrairement à un débit, il est immédiat et ne nécessite pas le PIN de l’utilisateur — votre clé API est votre autorité — la réponse reflète donc déjà le transfert effectué. L’utilisateur reçoit le montant total ; aucuns frais de plateforme ne s’appliquent.
POST https://api.vetox.io/public/vito/v1/add
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
Idempotency-Key: credit_7f3a # optional, dedupes retries for 24h
{
"discordId": "123456789012345678",
"amount": 250,
"reason": "Event reward",
"merchantRef": "reward_1042",
"metadata": { "ref": "1042" }
}{
"success": true,
"data": {
"transactionId": "txn_91b2",
"toDiscordId": "123456789012345678",
"amount": 250,
"ownerBalance": 48250,
"recipientBalance": 1250,
"status": "completed"
},
"requestId": "req_def456",
"timestamp": 1735689300000
}Webhooks et vérification de signature
Ajoutez une ou plusieurs URLs de callback https dans l’onglet Paramètres. Vito livre un POST signé à chaque URL configurée dès qu’une confirmation atteint un état final, avec jusqu’à 5 tentatives en repli exponentiel.
Vérifier la signature
Chaque livraison porte un en-tête X-Vito-Signature de la forme ts=<unix>;h1=<hex>. Recalculez le HMAC sur "<ts>:<rawBody>" avec votre secret de signature et comparez en temps constant. Vérifiez toujours le corps brut de la requête, avant l’analyse JSON.
signature = HMAC_SHA256(signingSecret, "<ts>:<rawBody>")
header = X-Vito-Signature: ts=<unix-seconds>;h1=<hex-signature>import crypto from 'crypto';
import express from 'express';
const app = express();
// IMPORTANT: verify against the RAW body, before JSON parsing.
app.post('/webhooks/vito', express.raw({ type: '*/*' }), (req, res) => {
const sig = req.header('X-Vito-Signature') || ''; // "ts=<unix>;h1=<hmac>[;h1=<hmac>]"
const pairs = sig.split(';').map(p => p.split('='));
const ts = pairs.find(([k]) => k === 'ts')?.[1];
const sigs = pairs.filter(([k]) => k === 'h1').map(([, v]) => v);
const rawBody = req.body.toString('utf8');
const expected = crypto
.createHmac('sha256', process.env.VITO_SIGNING_SECRET) // whsec_...
.update(`${ts}:${rawBody}`)
.digest('hex');
const expectedBuf = Buffer.from(expected, 'hex');
// During a 24h secret rotation the header carries TWO h1= values — accept ANY.
// Length-guard FIRST: crypto.timingSafeEqual throws on a length mismatch.
const ok = sigs.some(h => {
const got = Buffer.from(h, 'hex');
return (
got.length === expectedBuf.length &&
crypto.timingSafeEqual(got, expectedBuf)
);
});
// Reject anything older than ~5 minutes to stop replays.
const fresh = ts && Math.abs(Date.now() / 1000 - Number(ts)) < 300;
if (!ok || !fresh) return res.status(401).end();
const event = JSON.parse(rawBody);
if (event.eventType === 'confirmation.completed') {
grantPremiumTheme(event.data.merchantRef, event.data.fromDiscordId);
}
res.status(200).end(); // ack fast; run your action async if slow
});Événements de webhook et charges utiles
Vito envoie l’un des quatre types d’événement. Ils partagent tous la même forme de charge utile ; data.status reflète le résultat.
confirmation.completedconfirmation.failedconfirmation.expiredconfirmation.cancelledcredit.completedPOST https://your-app.com/webhooks/vito
X-Vito-Signature: ts=1735689600;h1=4f8b2c...e9
X-Vito-Event-Id: evt_3a2b1c
X-Vito-Event-Type: confirmation.completed
Content-Type: application/json
{
"eventId": "evt_3a2b1c",
"eventType": "confirmation.completed",
"timestamp": 1735689600000,
"data": {
"confirmationId": "f3c9...e1",
"type": "deduct",
"fromDiscordId": "123456789012345678",
"toDiscordId": null,
"amount": 500,
"reason": "Unlock premium theme",
"merchantRef": "ref_1042",
"product": { "type": "feature", "name": "Premium theme" },
"status": "completed",
"transactionId": "txn_77a2",
"metadata": { "ref": "1042" },
"failureReason": null
}
}Codes d’erreur
Les erreurs renvoient un statut non 2xx avec un corps JSON portant un error.code de premier niveau. Cas courants :
VITO_VALIDATION_ERRORinvalid keyOWNER_MEMBERSHIP_INACTIVEscope / IPnot foundinsufficient balanceINSUFFICIENT_OWNER_FUNDSrate limited{
"success": false,
"error": { "type": "Bad Request", "message": "guildId must be a valid Discord server ID", "code": "VITO_VALIDATION_ERROR" },
"requestId": "req_abc123",
"timestamp": 1735689300000
}Exemples d’intégration
Créer une demande de débit :
/v1/deductcurl -X POST https://api.vetox.io/public/vito/v1/deduct \
-H "Authorization: Bearer $VITO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"discordId": "123456789012345678",
"amount": 500,
"guildId": "1470389021162209280",
"merchantRef": "ref_1042",
"product": { "type": "feature", "name": "Premium theme" }
}'Vérifier le solde d’un utilisateur :
/v1/balance/:discordIdcurl https://api.vetox.io/public/vito/v1/balance/123456789012345678 \
-H "Authorization: Bearer $VITO_API_KEY"Tester avec l’intégration de démonstration
Une intégration de démonstration autonome est fournie pour exercer le parcours complet de bout en bout sans écrire de code. Elle parcourt demande → confirmation → PIN → webhook → finalisation.
- 1Ouvrez le dossier de l’intégration de démonstration et ajoutez votre clé d’API Vito, un token de bot Discord et l’ID de votre serveur (guild) de test dans config.json.
- 2Lancez npm install && npm start, puis ouvrez http://localhost:4000.
- 3Recherchez un utilisateur par son ID Discord, choisissez un élément et démarrez un débit — la démo appelle /deduct et affiche la confirmUrl.
- 4Approuvez le PIN sur vetox.io ; la démo détecte la finalisation (par webhook si configuré, sinon par sondage) et effectue l’action d’exemple.
Bonnes pratiques, limites et sécurité
Sécurité
- Gardez votre clé API et le secret de signature uniquement côté serveur ; faites tourner l’un ou l’autre immédiatement en cas de fuite.
- Vérifiez toujours la signature du webhook contre le corps brut et rejetez les livraisons de plus de ~5 minutes (protection contre le rejeu).
- N’effectuez votre action que sur confirmation.completed — jamais sur la réponse de /deduct (à ce stade, le débit n’est pas définitif).
- Utilisez la liste d’IP autorisées et ne demandez que les portées dont vous avez réellement besoin.
Limites
- Les confirmations expirent après 10 minutes ; traitez les demandes non confirmées comme abandonnées.
- Les limites de débit sont par projet et évoluent selon le niveau d’abonnement du propriétaire.
- amount doit être un entier positif ; metadata est plafonné à 10 clés.