Übersicht
Mit der Vito-API kann deine Anwendung von innerhalb von Discord mit dem Vito-Guthaben eines Nutzers arbeiten – es lesen, belasten oder gutschreiben. Jede Belastung wird vom Nutzer mit seiner PIN auf vetox.io bestätigt, bevor Vito bewegt wird, und deine App wird über das Ergebnis benachrichtigt. Vito ist die ökosystem-interne virtuelle Währung von Vetox; nutze die API, um Vito-basierte Erlebnisse zu schaffen – das Freischalten von Inhalten, Funktionen, Vorteilen oder Belohnungen. Es findet kein Kauf oder Verkauf mit echtem Geld statt.
Es ist eine REST-API, die mit einem geheimen Schlüssel authentifiziert wird. Alle Endpunkte geben JSON zurück und sind unter /v1 versioniert.
https://api.vetox.io/public/vito/v1Guthaben & Abrechnung
Dein API-Schlüssel ist mit deinem Vetox-Konto verknüpft. Jede Abbuchung wird zu deinen Gunsten abgerechnet: Wenn deine App einem Nutzer Vito abzieht, wird dieses Vito deinem eigenen Guthaben gutgeschrieben (abzüglich der Plattformgebühr) und niemals vernichtet. Wenn deine App einem Nutzer Vito hinzufügt, wird es aus deinem Guthaben finanziert.
Vito bewegt sich immer zwischen Guthaben – niemals von oder zu echtem Geld. Dem Nutzer wird der volle von dir angeforderte Betrag berechnet; du erhältst den Betrag nach Abzug der Plattformgebühr; Gutschriften und Belohnungen werden über /add aus deinem Guthaben finanziert.
Voraussetzungen
Der Zugriff auf die Vito-API wird pro Projekt gewährt. Bevor du sie aufrufen kannst, benötigst du:
- Eine aktive Nutzer-Mitgliedschaft (Stufe Silver oder höher). Die API wird automatisch eingefroren, wenn die Mitgliedschaft des Inhabers ausläuft, und stellt sich beim erneuten Abonnieren wieder her.
- Eine genehmigte Entwicklerbewerbung. Reiche eine über diese Seite ein; das Vetox-Team prüft sie manuell.
- Akzeptierte API-Entwicklerbedingungen – bestätigt, wenn du deinen Entwicklerantrag einreichst.
- Die Berechtigungen, die dein Projekt benötigt. Sie werden vom Vetox-Team anhand deiner Bewerbung gewährt.
Verfügbare Berechtigungen
balance:readdeduct:createcredit:createtransfer:createtransactions:readAuthentifizierung
Authentifiziere jede Anfrage mit deinem geheimen API-Schlüssel im Authorization-Header als Bearer-Token. Schlüssel tragen das Präfix vito_live_.
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxxZwei optionale Ebenen schützen dein Projekt zusätzlich:
- IP-Zulassungsliste – beschränke Anfragen auf bestimmte Server-IPs (konfiguriere sie im Tab Einstellungen).
- Ratenlimits – Anfragenobergrenzen pro Projekt, die mit deiner Mitgliedschaftsstufe steigen.
API-Schlüssel – Speicherung, Rotation & Sicherheit
Dein Schlüssel wird bei der Genehmigung deiner Bewerbung erzeugt. Er wird nur einmal angezeigt – zeige ihn im Tab API-Schlüssel an und speichere ihn sofort.
Vetox speichert deinen Schlüssel nie in lesbarer Form (nur einen gesalzenen Hash). Bewahre ihn als serverseitiges Secret auf – eine Umgebungsvariable oder einen Secrets-Manager – niemals im Client-Code, einem Git-Repository oder einem Browser.
Rotiere ihn im Tab API-Schlüssel. Der vorherige Schlüssel funktioniert noch eine 24-stündige Übergangsfrist, damit du den neuen ohne Ausfallzeit ausrollen kannst, danach wird er deaktiviert.
Bestätigungsablauf der Belastung
Jede Belastung läuft über eine Bestätigung, die der Nutzer mit seiner PIN genehmigt – dein Schlüssel allein bewegt nie Vito:
- 1Deine App ruft POST /deduct mit dem Nutzer, dem Betrag, der Ursprungs-guildId und den Artikeldetails auf.
- 2Vito erstellt eine ausstehende Bestätigung (10 Minuten gültig) und gibt eine confirmUrl zurück. Wird eine guildId angegeben, erhält der Nutzer zusätzlich eine DM mit den Details und einem Button zur Bestätigungsseite.
- 3Der Nutzer öffnet die confirmUrl auf vetox.io und genehmigt die Belastung mit seiner Wallet-PIN.
- 4Vito zieht die Vito ab, erfasst die Transaktion und sendet – falls ein Webhook konfiguriert ist – ein signiertes confirmation.completed-Ereignis an deine Callback-URL.
- 5Deine App prüft die Signatur und führt ihre Aktion aus (z. B. schaltet den Inhalt frei).
Anfrageparameter (/deduct)
/v1/deductDer Abzugs-Endpunkt akzeptiert die folgenden Body-Felder:
discordIdamountguildIdreasonmerchantRefproductproduct.imageUrlmetadata* Pflichtfeld.
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
}Vito hinzufügen — Gutschriften (/add)
/v1/addPOST /add schreibt einem Nutzer Vito aus deinem eigenen Guthaben gut — für Belohnungen oder Gutschriften. Es nimmt dieselben Felder wie /deduct, außer guildId und product. Anders als eine Abbuchung ist es sofortig und benötigt keine Nutzer-PIN — dein API-Schlüssel ist deine Befugnis — daher spiegelt die Antwort bereits die abgeschlossene Übertragung wider. Der Nutzer erhält den vollen Betrag; es fällt keine Plattformgebühr an.
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 & Signaturprüfung
Füge im Tab Einstellungen eine oder mehrere https-Callback-URLs hinzu. Vito stellt einen signierten POST an jede konfigurierte URL zu, sobald eine Bestätigung einen Endzustand erreicht, mit bis zu 5 Wiederholungen und exponentiellem Backoff.
Signatur prüfen
Jede Zustellung trägt einen X-Vito-Signature-Header der Form ts=<unix>;h1=<hex>. Berechne den HMAC über "<ts>:<rawBody>" mit deinem Signatur-Secret neu und vergleiche in konstanter Zeit. Prüfe immer gegen den rohen Anfrage-Body, vor dem JSON-Parsing.
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
});Webhook-Ereignisse & Payloads
Vito sendet einen von vier Ereignistypen. Sie teilen dieselbe Payload-Form; data.status spiegelt das Ergebnis wider.
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
}
}Fehlercodes
Fehler geben einen Nicht-2xx-Status mit einem JSON-Body zurück, der einen error.code auf oberster Ebene trägt. Häufige Fälle:
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
}Integrationsbeispiele
Eine Belastungsanfrage erstellen:
/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" }
}'Das Guthaben eines Nutzers prüfen:
/v1/balance/:discordIdcurl https://api.vetox.io/public/vito/v1/balance/123456789012345678 \
-H "Authorization: Bearer $VITO_API_KEY"Testen mit der Demo-Integration
Eine eigenständige Demo-Integration wird bereitgestellt, um den gesamten Ablauf ohne Code von Anfang bis Ende durchzuspielen. Sie durchläuft Anfrage → Bestätigung → PIN → Webhook → Abschluss.
- 1Öffne den Ordner der Demo-Integration und trage deinen Vito-API-Schlüssel, einen Discord-Bot-Token und deine Test-Server-(Guild-)ID in config.json ein.
- 2Führe npm install && npm start aus und öffne dann http://localhost:4000.
- 3Suche einen Nutzer per Discord-ID, wähle einen Artikel und starte eine Belastung – die Demo ruft /deduct auf und zeigt die confirmUrl an.
- 4Bestätige die PIN auf vetox.io; die Demo erkennt den Abschluss (per Webhook, falls konfiguriert, sonst per Polling) und führt die Beispielaktion aus.
Best Practices, Limits & Sicherheit
Sicherheit
- Halte deinen API-Schlüssel und das Signatur-Secret nur serverseitig; rotiere bei einem Leck sofort beides.
- Prüfe die Webhook-Signatur immer gegen den rohen Body und lehne Zustellungen ab, die älter als ~5 Minuten sind (Replay-Schutz).
- Führe deine Aktion nur bei confirmation.completed aus – niemals bei der Antwort von /deduct (zu diesem Zeitpunkt ist die Belastung noch nicht endgültig).
- Verwende die IP-Zulassungsliste und fordere nur die Berechtigungen an, die du wirklich brauchst.
Limits
- Bestätigungen laufen nach 10 Minuten ab; behandle unbestätigte Anfragen als abgebrochen.
- Ratenlimits gelten pro Projekt und steigen mit der Mitgliedschaftsstufe des Inhabers.
- amount muss eine positive Ganzzahl sein; metadata ist auf 10 Schlüssel begrenzt.