Overzicht
Met de Vito-API kan je applicatie werken met het Vito-saldo van een gebruiker vanuit Discord — het lezen, afschrijven of weer bijschrijven. De gebruiker bevestigt elke afschrijving met zijn pincode op vetox.io voordat er Vito wordt verplaatst, en je app krijgt de uitkomst doorgegeven. Vito is de virtuele valuta binnen het Vetox-ecosysteem; gebruik de API om Vito-gebaseerde ervaringen te bouwen — het ontgrendelen van content, functies, voordelen of beloningen. Er vindt geen koop of verkoop met echt geld plaats.
Het is een REST-API die wordt geauthenticeerd met een geheime sleutel. Alle endpoints geven JSON terug en zijn geversioneerd onder /v1.
https://api.vetox.io/public/vito/v1Saldi & afwikkeling
Je API-sleutel is gekoppeld aan je Vetox-account. Elke afschrijving wordt in jouw voordeel afgewikkeld: wanneer je app Vito van een gebruiker aftrekt, wordt die Vito op je eigen saldo bijgeschreven (minus de platformkosten), nooit vernietigd. Wanneer je app Vito aan een gebruiker toevoegt, wordt dit vanuit je saldo gefinancierd.
Vito verplaatst altijd tussen saldi — nooit van of naar echt geld. De gebruiker wordt het volledige bedrag dat je vraagt in rekening gebracht; jij ontvangt het bedrag na de platformkosten; bijschrijvingen en beloningen worden vanuit je saldo via /add gefinancierd.
Vereisten
Toegang tot de Vito-API wordt per project verleend. Voordat je hem kunt aanroepen, heb je nodig:
- Een actief gebruikerslidmaatschap (niveau Silver of hoger). De API bevriest automatisch als het lidmaatschap van de eigenaar verloopt, en wordt hersteld wanneer hij opnieuw abonneert.
- Een goedgekeurde ontwikkelaarsaanvraag. Dien er een in via deze pagina; het Vetox-team beoordeelt deze handmatig.
- Geaccepteerde API-ontwikkelaarsvoorwaarden — bevestigd wanneer je je ontwikkelaarsaanvraag indient.
- De scopes die je project nodig heeft. Ze worden door het Vetox-team verleend op basis van je aanvraag.
Beschikbare scopes
balance:readdeduct:createcredit:createtransfer:createtransactions:readAuthenticatie
Authenticeer elk verzoek met je geheime API-sleutel in de Authorization-header als Bearer-token. Sleutels hebben het prefix vito_live_.
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxxTwee optionele lagen beschermen je project verder:
- IP-toelatingslijst — beperk verzoeken tot specifieke server-IP’s (configureer dit op het tabblad Instellingen).
- Snelheidslimieten — verzoekplafonds per project die meeschalen met je lidmaatschapsniveau.
API-sleutels — opslag, rotatie en beveiliging
Je sleutel wordt gegenereerd wanneer je aanvraag wordt goedgekeurd. Hij wordt maar één keer getoond — onthul hem op het tabblad API-sleutels en sla hem direct op.
Vetox slaat je sleutel nooit in leesbare vorm op (alleen een gesalte hash). Bewaar hem als een server-side geheim — een omgevingsvariabele of een secrets-manager — nooit in clientcode, een git-repository of een browser.
Roteer hem op het tabblad API-sleutels. De vorige sleutel blijft nog 24 uur als overgangsperiode werken zodat je de nieuwe zonder downtime kunt uitrollen, daarna stopt hij.
Bevestigingsflow van de afschrijving
Elke afschrijving verloopt via een bevestiging die de gebruiker met zijn pincode goedkeurt — je sleutel alleen verplaatst nooit Vito:
- 1Je app roept POST /deduct aan met de gebruiker, het bedrag, de oorspronkelijke guildId en de itemgegevens.
- 2Vito maakt een openstaande bevestiging (10 minuten geldig) en retourneert een confirmUrl. Als een guildId wordt opgegeven, ontvangt de gebruiker ook een DM met de gegevens en een knop naar de bevestigingspagina.
- 3De gebruiker opent de confirmUrl op vetox.io en keurt de afschrijving goed met de pincode van zijn wallet.
- 4Vito schrijft de Vito af, registreert de transactie en stuurt — als je een webhook hebt geconfigureerd — een ondertekende confirmation.completed-gebeurtenis naar je callback-URL.
- 5Je app verifieert de handtekening en voert zijn actie uit (bijvoorbeeld ontgrendelt de content).
Verzoekparameters (/deduct)
/v1/deductHet afschrijvings-endpoint accepteert de volgende body-velden:
discordIdamountguildIdreasonmerchantRefproductproduct.imageUrlmetadata* verplicht veld.
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 toevoegen — bijschrijvingen (/add)
/v1/addPOST /add schrijft Vito bij een gebruiker bij vanuit je eigen saldo — voor beloningen of bijschrijvingen. Het neemt dezelfde velden als /deduct, behalve guildId en product. Anders dan een afschrijving is het direct en heeft het geen gebruikers-PIN nodig — je API-sleutel is je bevoegdheid — dus het antwoord weerspiegelt al de voltooide overdracht. De gebruiker ontvangt het volledige bedrag; er zijn geen platformkosten van toepassing.
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 en handtekeningverificatie
Voeg een of meer https-callback-URL’s toe op het tabblad Instellingen. Vito levert een ondertekende POST aan elke geconfigureerde URL wanneer een bevestiging een eindstatus bereikt, met tot 5 nieuwe pogingen met exponentiële backoff.
De handtekening verifiëren
Elke levering bevat een X-Vito-Signature-header van de vorm ts=<unix>;h1=<hex>. Herbereken de HMAC over "<ts>:<rawBody>" met je ondertekeningsgeheim en vergelijk in constante tijd. Verifieer altijd tegen de ruwe verzoekbody, vóór het JSON-parsen.
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-gebeurtenissen en payloads
Vito stuurt een van vier gebeurtenistypes. Ze delen allemaal dezelfde payload-vorm; data.status weerspiegelt de uitkomst.
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
}
}Foutcodes
Fouten geven een niet-2xx-status terug met een JSON-body die een top-level error.code bevat. Veelvoorkomende gevallen:
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
}Integratievoorbeelden
Een afschrijvingsverzoek maken:
/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" }
}'Het saldo van een gebruiker controleren:
/v1/balance/:discordIdcurl https://api.vetox.io/public/vito/v1/balance/123456789012345678 \
-H "Authorization: Bearer $VITO_API_KEY"Testen met de demo-integratie
Een zelfstandige demo-integratie wordt geleverd om de volledige flow van begin tot eind te doorlopen zonder code te schrijven. Hij doorloopt verzoek → bevestiging → pincode → webhook → voltooiing.
- 1Open de map van de demo-integratie en voeg je Vito-API-sleutel, een Discord-bottoken en je test-server-(guild-)ID toe aan config.json.
- 2Voer npm install && npm start uit en open vervolgens http://localhost:4000.
- 3Zoek een gebruiker op Discord-ID, kies een item en start een afschrijving — de demo roept /deduct aan en toont de confirmUrl.
- 4Keur de pincode goed op vetox.io; de demo detecteert de voltooiing (via webhook indien geconfigureerd, anders via polling) en voert de voorbeeldactie uit.
Best practices, limieten en beveiliging
Beveiliging
- Houd je API-sleutel en ondertekeningsgeheim alleen server-side; roteer een van beide onmiddellijk bij een lek.
- Verifieer de webhook-handtekening altijd tegen de ruwe body en weiger leveringen ouder dan ~5 minuten (replaybescherming).
- Voer je actie alleen uit bij confirmation.completed — nooit bij de reactie van /deduct (op dat moment is de afschrijving niet definitief).
- Gebruik de IP-toelatingslijst en vraag alleen de scopes aan die je echt nodig hebt.
Limieten
- Bevestigingen verlopen na 10 minuten; behandel niet-bevestigde verzoeken als verlaten.
- Snelheidslimieten gelden per project en schalen mee met het lidmaatschapsniveau van de eigenaar.
- amount moet een positief geheel getal zijn; metadata is beperkt tot 10 sleutels.