Vito API-Dokumentation

Zuletzt aktualisiert: 26. Juni 2026
01

Ü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.

Basis-URLhttps://api.vetox.io/public/vito/v1
02

Guthaben & 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.

Plattformgebühr — dieselbe Staffel wie bei In-App-Vito-Überweisungen, abhängig von deiner Mitgliedsstufe: 7 % (Silver / Gold), 6 % (Platinum), 5 % (Diamond). Abbuchungen von 5 Vito oder weniger sind gebührenfrei. Gutschriften über /add werden nie mit einer Gebühr belegt.
03

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:read
Das Vito-Guthaben eines Nutzers lesen.
deduct:create
Einen Abzug erstellen – das Vito-Guthaben eines Nutzers belasten.
credit:create
Einem Nutzer Vito hinzufügen — Belohnungen oder Gutschriften aus deinem Guthaben finanzieren.
transfer:create
Eine Überweisung zwischen zwei Nutzern erstellen.
transactions:read
Die Transaktionen deines Projekts auflisten und lesen.
04

Authentifizierung

Authentifiziere jede Anfrage mit deinem geheimen API-Schlüssel im Authorization-Header als Bearer-Token. Schlüssel tragen das Präfix vito_live_.

http
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxx

Zwei 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.
05

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.

Behandle den Schlüssel wie ein Passwort – wer ihn besitzt, kann deinen Nutzern Beträge berechnen. Bei einem Leck sofort rotieren und deine letzten Transaktionen prüfen.
06

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:

  1. 1Deine App ruft POST /deduct mit dem Nutzer, dem Betrag, der Ursprungs-guildId und den Artikeldetails auf.
  2. 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.
  3. 3Der Nutzer öffnet die confirmUrl auf vetox.io und genehmigt die Belastung mit seiner Wallet-PIN.
  4. 4Vito zieht die Vito ab, erfasst die Transaktion und sendet – falls ein Webhook konfiguriert ist – ein signiertes confirmation.completed-Ereignis an deine Callback-URL.
  5. 5Deine App prüft die Signatur und führt ihre Aktion aus (z. B. schaltet den Inhalt frei).
PINs werden nur auf vetox.io eingegeben – niemals in deiner App oder in Discord. Bestätigt der Nutzer nie, läuft die Anfrage nach 10 Minuten ab und du erhältst ein confirmation.expired-Ereignis.
07

Anfrageparameter (/deduct)

POST/v1/deduct

Der Abzugs-Endpunkt akzeptiert die folgenden Body-Felder:

discordId
Die Discord-Benutzer-ID des Nutzers – ein 17- bis 20-stelliger Snowflake. Erforderlich.
amount
Zu berechnender Vito-Betrag – eine positive Ganzzahl. Erforderlich.
guildId
Der Discord-Server, von dem die Belastung ausgeht (Snowflake). Erforderlich – jede Belastung muss von einem bestimmten Server kommen, was auch die DM an den Nutzer aktiviert.
reason
Eine kurze, lesbare Beschreibung (≤ 256 Zeichen), die dem Nutzer angezeigt und im Webhook wiederholt wird.
merchantRef
Deine eigene Referenzzeichenfolge (≤ 128 Zeichen). Verwende sie, um den Webhook deinen Aufzeichnungen zuzuordnen.
product
Artikelbeschreibung – { type, name, description?, imageUrl? }. Wird dem Nutzer auf der Bestätigungsseite und in der DM angezeigt und in jedem Webhook wiederholt.
product.imageUrl
Optionales Produktbild – muss eine https://-URL sein.
metadata
Bis zu 10 String-Schlüssel/Wert-Paare, die unverändert im Webhook weitergegeben werden.

* Pflichtfeld.

Beispielanfrage
http
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" }
}
Beispielantwort
json
{
  "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
}
08

Vito hinzufügen — Gutschriften (/add)

POST/v1/add

POST /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.

Erfordert den Scope credit:create und ausreichend Vito in deinem eigenen Guthaben — andernfalls gibt der Aufruf 402 INSUFFICIENT_OWNER_FUNDS zurück.
Beispielanfrage
http
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" }
}
Beispielantwort
json
{
  "success": true,
  "data": {
    "transactionId": "txn_91b2",
    "toDiscordId": "123456789012345678",
    "amount": 250,
    "ownerBalance": 48250,
    "recipientBalance": 1250,
    "status": "completed"
  },
  "requestId": "req_def456",
  "timestamp": 1735689300000
}
09

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.

Webhooks werden nur ausgelöst, wenn dein Projekt sowohl eine konfigurierte Callback-URL als auch ein Signatur-Secret hat. Zeige dein Signatur-Secret (whsec_…) einmal im Tab API-Schlüssel an.

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.

http
signature = HMAC_SHA256(signingSecret, "<ts>:<rawBody>")
header    = X-Vito-Signature: ts=<unix-seconds>;h1=<hex-signature>
Referenz-Prüfer (Node / Express):
javascript
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
});
10

Webhook-Ereignisse & Payloads

Vito sendet einen von vier Ereignistypen. Sie teilen dieselbe Payload-Form; data.status spiegelt das Ergebnis wider.

confirmation.completed
Der Nutzer hat bestätigt und die Vito wurden abgezogen. Führe deine Aktion aus. Trägt transactionId.
confirmation.failed
Die Belastung konnte nicht abgeschlossen werden (z. B. unzureichendes Guthaben oder ein interner Fehler). Trägt failureReason.
confirmation.expired
Der Nutzer hat nicht innerhalb von 10 Minuten bestätigt. Kein Vito bewegt.
confirmation.cancelled
Der Nutzer hat die Anfrage abgebrochen. Kein Vito bewegt.
credit.completed
Eine vom Inhaber finanzierte /add-Gutschrift wurde abgerechnet. Enthält den Empfänger und transactionId und wird sofort ausgelöst — es gibt keinen Bestätigungsschritt.
Beispiel-Payload (confirmation.completed)
http
POST 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
  }
}
11

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:

400VITO_VALIDATION_ERROR
Ein Anfragefeld fehlt oder ist fehlerhaft (z. B. eine ungültige guildId).
401invalid key
Fehlender, fehlerhafter oder unbekannter API-Schlüssel.
403OWNER_MEMBERSHIP_INACTIVE
Die Mitgliedschaft des Projektinhabers ist abgelaufen – die API ist eingefroren, bis er erneut abonniert.
403scope / IP
Dem Schlüssel fehlt die erforderliche Berechtigung, oder die Anfrage-IP ist nicht zugelassen.
404not found
Der Nutzer, die Transaktion oder die Ressource existiert nicht.
402insufficient balance
Der Nutzer hat nicht genug Vito für die Belastung.
402INSUFFICIENT_OWNER_FUNDS
Dein eigenes (Inhaber-)Guthaben ist zu niedrig, um eine /add-Gutschrift zu finanzieren.
429rate limited
Du hast das Ratenlimit deines Projekts überschritten – warte und versuche es erneut.
Form der Fehlerantwort
json
{
  "success": false,
  "error": { "type": "Bad Request", "message": "guildId must be a valid Discord server ID", "code": "VITO_VALIDATION_ERROR" },
  "requestId": "req_abc123",
  "timestamp": 1735689300000
}
12

Integrationsbeispiele

Eine Belastungsanfrage erstellen:

POST/v1/deduct
bash
curl -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:

GET/v1/balance/:discordId
bash
curl https://api.vetox.io/public/vito/v1/balance/123456789012345678 \
  -H "Authorization: Bearer $VITO_API_KEY"
13

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. 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.
  2. 2Führe npm install && npm start aus und öffne dann http://localhost:4000.
  3. 3Suche einen Nutzer per Discord-ID, wähle einen Artikel und starte eine Belastung – die Demo ruft /deduct auf und zeigt die confirmUrl an.
  4. 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.
Der Empfang des Webhooks erfordert einen öffentlichen https-Callback und ein Signatur-Secret; ohne sie greift die Demo auf das Polling deiner Transaktionen zurück und funktioniert so ohne Einrichtung.
14

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.
Idempotency-Key dedupliziert WiederholungenWebhooks wiederholen 5× mit BackoffSchnell 2xx bestätigen, asynchron erfüllen