Panoramica
L’API Vito consente alla tua applicazione di lavorare con il saldo Vito di un utente da dentro Discord — leggerlo, addebitarlo o riaccreditarlo. L’utente conferma ogni addebito con il proprio PIN su vetox.io prima che venga mosso qualsiasi Vito, e la tua app viene notificata dell’esito. Vito è la valuta virtuale interna all’ecosistema Vetox; usa l’API per creare esperienze basate su Vito — sbloccare contenuti, funzionalità, vantaggi o premi. Non avviene alcun acquisto o vendita con denaro reale.
È un’API REST autenticata con una chiave segreta. Tutti gli endpoint restituiscono JSON e sono versionati sotto /v1.
https://api.vetox.io/public/vito/v1Saldi e liquidazione
La tua chiave API è legata al tuo account Vetox. Ogni addebito viene liquidato a tuo favore: quando la tua app deduce Vito da un utente, quei Vito vengono accreditati sul tuo saldo (al netto della commissione della piattaforma), mai distrutti. Quando la tua app aggiunge Vito a un utente, sono finanziati dal tuo saldo.
I Vito si muovono sempre tra saldi — mai da o verso denaro reale. All'utente viene addebitato l'intero importo richiesto; tu ricevi l'importo al netto della commissione della piattaforma; accrediti e premi sono finanziati dal tuo saldo tramite /add.
Requisiti
L’accesso all’API Vito è concesso per progetto. Prima di poterla chiamare ti serve:
- Un abbonamento utente attivo (livello Silver o superiore). L’API si congela automaticamente se l’abbonamento del proprietario scade e si ripristina quando si riabbona.
- Una domanda da sviluppatore approvata. Inviane una da questa pagina; il team Vetox la esamina manualmente.
- Termini per sviluppatori API accettati — confermati quando invii la tua domanda da sviluppatore.
- Gli ambiti di cui il tuo progetto ha bisogno. Sono concessi dal team Vetox in base alla tua domanda.
Ambiti disponibili
balance:readdeduct:createcredit:createtransfer:createtransactions:readAutenticazione
Autentica ogni richiesta con la tua chiave API segreta nell’header Authorization come token Bearer. Le chiavi hanno il prefisso vito_live_.
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxxDue livelli opzionali proteggono ulteriormente il tuo progetto:
- Lista IP consentiti — limita le richieste a IP di server specifici (configurala nella scheda Impostazioni).
- Limiti di frequenza — tetti di richieste per progetto che crescono con il tuo livello di abbonamento.
Chiavi API — archiviazione, rotazione e sicurezza
La tua chiave viene generata all’approvazione della domanda. Viene mostrata una sola volta — rivelala dalla scheda Chiavi API e conservala immediatamente.
Vetox non memorizza mai la tua chiave in forma leggibile (solo un hash con sale). Conservala come segreto lato server — una variabile d’ambiente o un gestore di segreti — mai nel codice client, in un repository git o in un browser.
Ruotala dalla scheda Chiavi API. La chiave precedente continua a funzionare per un periodo di tolleranza di 24 ore così da distribuire la nuova senza interruzioni, poi si disattiva.
Flusso di conferma dell’addebito
Ogni addebito passa da una conferma che l’utente approva con il proprio PIN — la tua chiave da sola non muove mai Vito:
- 1La tua app chiama POST /deduct con l’utente, l’importo, il guildId di origine e i dettagli dell’articolo.
- 2Vito crea una conferma in attesa (valida 10 minuti) e restituisce una confirmUrl. Se viene fornito un guildId, l’utente riceve anche un DM con i dettagli e un pulsante verso la pagina di conferma.
- 3L’utente apre la confirmUrl su vetox.io e approva l’addebito con il PIN del proprio portafoglio.
- 4Vito detrae i Vito, registra la transazione e — se hai un webhook configurato — invia un evento confirmation.completed firmato al tuo URL di callback.
- 5La tua app verifica la firma e completa la sua azione (ad esempio, sblocca il contenuto).
Parametri della richiesta (/deduct)
/v1/deductL’endpoint di detrazione accetta i seguenti campi del body:
discordIdamountguildIdreasonmerchantRefproductproduct.imageUrlmetadata* campo obbligatorio.
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
}Aggiungere Vito — accrediti (/add)
/v1/addPOST /add accredita Vito a un utente dal tuo saldo — per premi o accrediti. Accetta gli stessi campi di /deduct tranne guildId e product. A differenza di un addebito è immediato e non richiede il PIN dell'utente — la tua chiave API è la tua autorità — quindi la risposta riflette già il trasferimento completato. L'utente riceve l'intero importo; non si applica alcuna commissione di piattaforma.
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
}Webhook e verifica della firma
Aggiungi uno o più URL di callback https nella scheda Impostazioni. Vito consegna un POST firmato a ogni URL configurato ogni volta che una conferma raggiunge uno stato finale, riprovando fino a 5 volte con backoff esponenziale.
Verificare la firma
Ogni consegna porta un header X-Vito-Signature nella forma ts=<unix>;h1=<hex>. Ricalcola l’HMAC su "<ts>:<rawBody>" con il tuo segreto di firma e confronta a tempo costante. Verifica sempre sul body grezzo della richiesta, prima del parsing 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
});Eventi webhook e payload
Vito invia uno di quattro tipi di evento. Condividono tutti la stessa forma di payload; data.status riflette l’esito.
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
}
}Codici di errore
Gli errori restituiscono uno stato non 2xx con un body JSON che porta un error.code di primo livello. Casi comuni:
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
}Esempi di integrazione
Creare una richiesta di addebito:
/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" }
}'Controllare il saldo di un utente:
/v1/balance/:discordIdcurl https://api.vetox.io/public/vito/v1/balance/123456789012345678 \
-H "Authorization: Bearer $VITO_API_KEY"Test con l’integrazione dimostrativa
Viene fornita un’integrazione dimostrativa autonoma per esercitare l’intero flusso end-to-end senza scrivere codice. Percorre richiesta → conferma → PIN → webhook → completamento.
- 1Apri la cartella dell’integrazione dimostrativa e aggiungi la tua chiave API Vito, un token bot Discord e l’ID del tuo server (guild) di test in config.json.
- 2Esegui npm install && npm start, poi apri http://localhost:4000.
- 3Cerca un utente per ID Discord, scegli un articolo e avvia un addebito — la demo chiama /deduct e mostra la confirmUrl.
- 4Approva il PIN su vetox.io; la demo rileva il completamento (tramite webhook se configurato, altrimenti con polling) e completa l’azione di esempio.
Best practice, limiti e sicurezza
Sicurezza
- Mantieni la chiave API e il segreto di firma solo lato server; ruota subito l’uno o l’altro in caso di fuga.
- Verifica sempre la firma del webhook sul body grezzo e rifiuta le consegne più vecchie di ~5 minuti (protezione dai replay).
- Completa la tua azione solo su confirmation.completed — mai sulla risposta di /deduct (a quel punto l’addebito non è definitivo).
- Usa la lista IP consentiti e richiedi solo gli ambiti che ti servono davvero.
Limiti
- Le conferme scadono dopo 10 minuti; tratta le richieste non confermate come abbandonate.
- I limiti di frequenza sono per progetto e crescono con il livello di abbonamento del proprietario.
- amount deve essere un intero positivo; metadata è limitato a 10 chiavi.