Autorisez les applications approuvées à prélever vos Vito avec confirmation par PIN, et gérez les demandes de paiement depuis votre page Achats.
Nécessite un abonnement Silver ou supérieur — à la fois pour postuler et pour chaque appel authentifié. Si l’abonnement du détenteur de la clé expire, le projet est gelé jusqu’à son renouvellement.
Une API REST qui permet à votre application de manipuler le solde Vito d’un utilisateur depuis Discord : le lire, le débiter, le créditer ou le déplacer entre utilisateurs. Tous les endpoints renvoient du JSON et sont versionnés sous /v1.
Les Vito ne se convertissent jamais en argent réel, ni l’inverse. Ils circulent uniquement entre les soldes Vetox.
Votre clé et votre secret de signature ne sont affichés qu’une seule fois. Après l’approbation, vous disposez d’une fenêtre de 7 jours pour les révéler depuis l’onglet des clés API. Vetox n’en conserve qu’un hachage et ne peut pas les réafficher — si vous manquez la fenêtre, il faut effectuer une rotation.
Gardez-la uniquement côté serveur — quiconque la détient peut débiter vos utilisateurs
Effectuez la rotation depuis l’onglet des clés API. La clé précédente reste valable pendant un délai de grâce de 24 heures, ce qui permet de déployer sans interruption
Le secret de signature des webhooks se renouvelle séparément, avec son propre chevauchement de 24 heures
En cas de fuite, effectuez immédiatement une rotation
Votre clé seule ne peut pas déplacer les Vito d’un utilisateur. Chaque débit exige que l’utilisateur l’approuve avec le code PIN de son portefeuille, sur vetox.io — jamais dans votre application ni dans Discord.
1
Votre application appelle POST /v1/deduct
Avec l’utilisateur, le montant, le guildId d’origine et les détails de l’article.
2
Vito renvoie une confirmUrl
Une confirmation en attente, valable 10 minutes. L’utilisateur reçoit également un MP.
3
L'utilisateur approuve avec son code PIN
Sur vetox.io.
4
Vito règle et notifie
Le solde est débité, la transaction enregistrée, et un webhook signé est envoyé si vous en avez configuré un.
5
Votre application vérifie et finalise
Vérifiez la signature, puis débloquez le contenu ou livrez l’article.
Ne finalisez votre action que sur confirmation.completed — jamais sur la réponse de /deduct. À ce stade, le débit n’est pas définitif.
POST /v1/add crédite des Vito à un utilisateur depuis votre propre solde — pour des récompenses ou des remboursements. Mêmes champs que /deduct, sauf guildId et product.
Contrairement à un débit, un crédit n’a pas d’étape de confirmation : il est réglé immédiatement. Nécessite le scope credit:create et un solde suffisant, sinon l’appel renvoie 402 VITO_INSUFFICIENT_OWNER_FUNDS.
Chaque débit vous est reversé après déduction des frais de la plateforme — selon le même barème que les transferts Vito dans l’application, en fonction de votre niveau d’abonnement :
Votre abonnement
Frais
Normal, Silver, Gold
7 %
Platinum
6 %
Diamond
5 %
Les montants de 5 Vito ou moins sont sans frais, et les crédits via /v1/add le sont toujours.
Ajoutez une ou plusieurs URL de rappel https dans l’onglet des paramètres. Vito envoie un POST signé dès qu’une confirmation atteint un état final.
Les webhooks ne partent que si votre projet possède à la fois une URL de rappel et un secret de signature. Révélez le secret (whsec_…) une seule fois depuis l’onglet des clés API.
Chaque livraison porte un en-tête X-Vito-Signature :
X-Vito-Signature: ts=<unix>;h1=<hex>
Deux autres en-têtes accompagnent chaque livraison — utilisez X-Vito-Event-Id comme clé de déduplication, car une nouvelle tentative renvoie le même identifiant :
En-tête
Contient
X-Vito-Event-Id
Identifiant stable de cet événement — identique d’une tentative à l’autre
X-Vito-Event-Type
Par exemple confirmation.completed
Pendant une rotation du secret de signature, l’en-tête porte plusieurs signatures, la plus récente en premier :
Acceptez la livraison si l’un quelconque des h1 correspond. Un vérificateur qui ne lit que le premier rejettera tous les webhooks tant qu’il n’aura pas déployé le nouveau secret — ce qui annule tout l’intérêt du chevauchement de 24 heures.
Recalculez le HMAC sur <ts>:<rawBody> avec votre secret de signature et comparez en temps constant.
const crypto = require('crypto');function verify(rawBody, header, secret) { const parts = header.split(';'); const ts = parts.find(p => p.startsWith('ts='))?.slice(3); const sigs = parts.filter(p => p.startsWith('h1=')).map(p => p.slice(3)); if (!ts || sigs.length === 0) return false; // Reject anything older than ~5 minutes — replay protection. if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; const expected = Buffer.from( crypto.createHmac('sha256', secret).update(`${ts}:${rawBody}`).digest('hex'), ); // Any matching signature is valid — a rotation emits several. return sigs.some(sig => { const actual = Buffer.from(sig); // timingSafeEqual throws when the lengths differ, so check first. return ( actual.length === expected.length && crypto.timingSafeEqual(actual, expected) ); });}
Vérifiez sur le corps brut, avant tout parsing JSON ou middleware susceptible de le réécrire.
Il existe aussi une limite par IP égale à la moitié de votre quota par minute, avec un plancher de 30.
En charge, les endpoints d’écriture échouent en mode fermé — un débit est rejeté plutôt que de risquer une double dépense. Les lectures échouent en mode ouvert. Traitez une écriture rejetée comme « n’a pas eu lieu » et réessayez.
Envoyez un en-tête Idempotency-Key pour dédupliquer les nouvelles tentatives en toute sécurité.
La clé API et le secret de signature n’ont jamais leur place dans du code client. En cas de fuite de l’un ou l’autre, effectuez immédiatement une rotation.
Vérifiez chaque webhook
Contrôlez la signature sur le corps brut et rejetez les livraisons datant de plus de ~5 minutes.
Ne réglez que sur completed
Ne livrez jamais sur la seule réponse de /deduct — le débit n’est définitif qu’avec confirmation.completed.
Moindre privilège
Ne demandez que les scopes réellement utilisés et activez la liste d’IP autorisées.