Dokumentacja Vito API

Ostatnia aktualizacja: 26 czerwca 2026
01

Przegląd

Vito API pozwala Twojej aplikacji pracować z saldem Vito użytkownika z poziomu Discorda — odczytywać je, obciążać lub uznawać z powrotem. Użytkownik potwierdza każde obciążenie swoim PIN-em na vetox.io, zanim jakiekolwiek Vito zostanie przeniesione, a Twoja aplikacja jest powiadamiana o wyniku. Vito to wewnętrzna wirtualna waluta ekosystemu Vetox; używaj API, aby budować doświadczenia oparte na Vito — odblokowywanie treści, funkcji, korzyści lub nagród. Nie odbywa się żadna sprzedaż ani zakup za prawdziwe pieniądze.

To API REST uwierzytelniane tajnym kluczem. Wszystkie punkty końcowe zwracają JSON i są wersjonowane pod /v1.

Bazowy URLhttps://api.vetox.io/public/vito/v1
02

Salda i rozliczenie

Twój klucz API jest powiązany z Twoim kontem Vetox. Każde obciążenie jest rozliczane na Twoją korzyść: gdy Twoja aplikacja odejmuje Vito użytkownikowi, te Vito są księgowane na Twoim własnym saldzie (po potrąceniu opłaty platformy) i nigdy nie są niszczone. Gdy Twoja aplikacja dodaje Vito użytkownikowi, jest to finansowane z Twojego salda.

Vito zawsze przepływa między saldami — nigdy do ani z prawdziwych pieniędzy. Użytkownik jest obciążany pełną kwotą, o którą prosisz; Ty otrzymujesz kwotę po opłacie platformy; uznania i nagrody są finansowane z Twojego salda przez /add.

Opłata platformy — ta sama skala co przelewy Vito w aplikacji, zależnie od Twojego poziomu członkostwa: 7% (Silver / Gold), 6% (Platinum), 5% (Diamond). Obciążenia do 5 Vito są bez opłat. Uznania przez /add nigdy nie są obciążane opłatą.
03

Wymagania

Dostęp do Vito API jest przyznawany dla każdego projektu. Zanim będziesz mógł je wywołać, potrzebujesz:

  • Aktywnego członkostwa użytkownika (poziom Silver lub wyższy). API zamraża się automatycznie, gdy członkostwo właściciela wygaśnie, i przywraca się po ponownej subskrypcji.
  • Zatwierdzonego wniosku deweloperskiego. Złóż go na tej stronie; zespół Vetox sprawdza go ręcznie.
  • Zaakceptowane warunki dla deweloperów API — potwierdzane przy wysyłaniu wniosku deweloperskiego.
  • Zakresów, których potrzebuje Twój projekt. Są przyznawane przez zespół Vetox na podstawie wniosku.

Dostępne zakresy

balance:read
Odczyt salda Vito użytkownika.
deduct:create
Utworzenie potrącenia — obciążenie salda Vito użytkownika.
credit:create
Dodaj Vito użytkownikowi — finansuj nagrody lub uznania ze swojego salda.
transfer:create
Utworzenie przelewu między dwoma użytkownikami.
transactions:read
Wyświetlanie i odczyt transakcji Twojego projektu.
04

Uwierzytelnianie

Uwierzytelniaj każde żądanie swoim tajnym kluczem API w nagłówku Authorization jako token Bearer. Klucze mają prefiks vito_live_.

http
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxx

Dwie opcjonalne warstwy dodatkowo chronią Twój projekt:

  • Lista dozwolonych IP — ogranicz żądania do konkretnych adresów IP serwera (skonfiguruj w zakładce Ustawienia).
  • Limity szybkości — pułapy żądań na projekt, które skalują się z Twoim poziomem członkostwa.
05

Klucze API — przechowywanie, rotacja i bezpieczeństwo

Twój klucz jest generowany po zatwierdzeniu wniosku. Jest pokazywany tylko raz — ujawnij go w zakładce Klucze API i natychmiast zapisz.

Vetox nigdy nie przechowuje klucza w czytelnej formie (tylko solony hash). Trzymaj go jako sekret po stronie serwera — zmienną środowiskową lub menedżera sekretów — nigdy w kodzie klienta, repozytorium git ani przeglądarce.

Rotuj go w zakładce Klucze API. Poprzedni klucz działa jeszcze przez 24-godzinny okres przejściowy, abyś mógł wdrożyć nowy bez przestoju, a potem przestaje.

Traktuj klucz jak hasło — każdy, kto go ma, może obciążać Twoich użytkowników. W razie wycieku natychmiast go rotuj i sprawdź ostatnie transakcje.
06

Przepływ potwierdzania obciążenia

Każde obciążenie przechodzi przez potwierdzenie, które użytkownik zatwierdza PIN-em — sam klucz nigdy nie przenosi Vito:

  1. 1Twoja aplikacja wywołuje POST /deduct z użytkownikiem, kwotą, źródłowym guildId i szczegółami przedmiotu.
  2. 2Vito tworzy oczekujące potwierdzenie (ważne 10 minut) i zwraca confirmUrl. Jeśli podano guildId, użytkownik otrzymuje też DM ze szczegółami i przyciskiem do strony potwierdzenia.
  3. 3Użytkownik otwiera confirmUrl na vetox.io i zatwierdza obciążenie PIN-em swojego portfela.
  4. 4Vito potrąca Vito, zapisuje transakcję i — jeśli masz skonfigurowany webhook — wysyła podpisane zdarzenie confirmation.completed na Twój URL wywołania zwrotnego.
  5. 5Twoja aplikacja weryfikuje podpis i wykonuje swoją akcję (np. odblokowuje treść).
PIN-y wprowadza się wyłącznie na vetox.io — nigdy w Twojej aplikacji ani w Discordzie. Jeśli użytkownik nie potwierdzi, żądanie wygasa po 10 minutach i otrzymujesz zdarzenie confirmation.expired.
07

Parametry żądania (/deduct)

POST/v1/deduct

Punkt końcowy potrącenia przyjmuje następujące pola treści:

discordId
Identyfikator użytkownika Discord użytkownika — snowflake o długości 17–20 cyfr. Wymagane.
amount
Ilość Vito do obciążenia — dodatnia liczba całkowita. Wymagane.
guildId
Serwer Discord, z którego pochodzi obciążenie (snowflake). Wymagane — każde obciążenie musi pochodzić z konkretnego serwera, co także włącza DM do użytkownika.
reason
Krótki czytelny opis (≤ 256 znaków), pokazywany użytkownikowi i powtarzany w webhooku.
merchantRef
Twój własny ciąg referencyjny (≤ 128 znaków). Użyj go, aby powiązać webhook ze swoimi zapisami.
product
Deskryptor przedmiotu — { type, name, description?, imageUrl? }. Pokazywany użytkownikowi na stronie potwierdzenia i w DM oraz powtarzany w każdym webhooku.
product.imageUrl
Opcjonalny obraz produktu — musi być adresem URL https://.
metadata
Do 10 par klucz/wartość typu string, przekazywanych dosłownie w webhooku.

* pole wymagane.

Przykładowe żądanie
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" }
}
Przykładowa odpowiedź
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

Dodawanie Vito — uznania (/add)

POST/v1/add

POST /add zasila użytkownika w Vito z Twojego własnego salda — na nagrody lub uznania. Przyjmuje te same pola co /deduct z wyjątkiem guildId i product. W przeciwieństwie do obciążenia jest natychmiastowe i nie wymaga PIN-u użytkownika — Twój klucz API jest Twoim upoważnieniem — więc odpowiedź już odzwierciedla ukończony transfer. Użytkownik otrzymuje pełną kwotę; nie obowiązuje żadna opłata platformy.

Wymaga zakresu credit:create i wystarczającej ilości Vito na Twoim saldzie — w przeciwnym razie wywołanie zwraca 402 INSUFFICIENT_OWNER_FUNDS.
Przykładowe żądanie
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" }
}
Przykładowa odpowiedź
json
{
  "success": true,
  "data": {
    "transactionId": "txn_91b2",
    "toDiscordId": "123456789012345678",
    "amount": 250,
    "ownerBalance": 48250,
    "recipientBalance": 1250,
    "status": "completed"
  },
  "requestId": "req_def456",
  "timestamp": 1735689300000
}
09

Webhooki i weryfikacja podpisu

Dodaj jeden lub więcej adresów URL wywołań zwrotnych https w zakładce Ustawienia. Vito dostarcza podpisany POST na każdy skonfigurowany URL, gdy potwierdzenie osiągnie stan końcowy, ponawiając próbę do 5 razy z wykładniczym wycofaniem.

Webhooki uruchamiają się tylko wtedy, gdy Twój projekt ma JEDNOCZEŚNIE skonfigurowany URL wywołania zwrotnego ORAZ sekret podpisu. Ujawnij sekret podpisu (whsec_…) raz w zakładce Klucze API.

Weryfikacja podpisu

Każde dostarczenie zawiera nagłówek X-Vito-Signature w formie ts=<unix>;h1=<hex>. Przelicz ponownie HMAC na "<ts>:<rawBody>" swoim sekretem podpisu i porównaj w czasie stałym. Zawsze weryfikuj na surowej treści żądania, przed parsowaniem JSON.

http
signature = HMAC_SHA256(signingSecret, "<ts>:<rawBody>")
header    = X-Vito-Signature: ts=<unix-seconds>;h1=<hex-signature>
Referencyjny weryfikator (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

Zdarzenia webhooków i ładunki

Vito wysyła jeden z czterech typów zdarzeń. Wszystkie mają ten sam kształt ładunku; data.status odzwierciedla wynik.

confirmation.completed
Użytkownik potwierdził i Vito zostało potrącone. Wykonaj swoją akcję. Zawiera transactionId.
confirmation.failed
Nie udało się ukończyć obciążenia (np. niewystarczające saldo lub błąd wewnętrzny). Zawiera failureReason.
confirmation.expired
Użytkownik nie potwierdził w ciągu 10 minut. Brak przepływu Vito.
confirmation.cancelled
Użytkownik anulował żądanie. Brak przepływu Vito.
credit.completed
Rozliczono uznanie /add finansowane przez właściciela. Zawiera odbiorcę i transactionId oraz uruchamia się natychmiast — nie ma kroku potwierdzenia.
Przykładowy ładunek (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

Kody błędów

Błędy zwracają status inny niż 2xx z treścią JSON zawierającą error.code na najwyższym poziomie. Częste przypadki:

400VITO_VALIDATION_ERROR
Brakuje pola żądania lub jest źle sformułowane (np. nieprawidłowy guildId).
401invalid key
Brakujący, źle sformułowany lub nieznany klucz API.
403OWNER_MEMBERSHIP_INACTIVE
Członkostwo właściciela projektu wygasło — API jest zamrożone do czasu ponownej subskrypcji.
403scope / IP
Klucz nie ma wymaganego zakresu lub IP żądania nie znajduje się na liście dozwolonych.
404not found
Użytkownik, transakcja lub zasób nie istnieje.
402insufficient balance
Użytkownik nie ma wystarczającej ilości Vito na obciążenie.
402INSUFFICIENT_OWNER_FUNDS
Twoje własne saldo (właściciela) jest zbyt niskie, aby sfinansować uznanie /add.
429rate limited
Przekroczono limit szybkości projektu — odczekaj i spróbuj ponownie.
Kształt odpowiedzi błędu
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

Przykłady integracji

Utwórz żądanie obciążenia:

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" }
  }'

Sprawdź saldo użytkownika:

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

Testowanie z integracją demonstracyjną

Udostępniono samodzielną integrację demonstracyjną do przećwiczenia pełnego przepływu od początku do końca bez pisania kodu. Przechodzi przez żądanie → potwierdzenie → PIN → webhook → ukończenie.

  1. 1Otwórz folder integracji demonstracyjnej i dodaj swój klucz Vito API, token bota Discord oraz identyfikator testowego serwera (guild) do config.json.
  2. 2Uruchom npm install && npm start, a następnie otwórz http://localhost:4000.
  3. 3Wyszukaj użytkownika po ID Discord, wybierz przedmiot i rozpocznij obciążenie — demo wywołuje /deduct i pokazuje confirmUrl.
  4. 4Zatwierdź PIN na vetox.io; demo wykrywa ukończenie (przez webhook, jeśli skonfigurowany, w przeciwnym razie przez odpytywanie) i wykonuje przykładową akcję.
Odbiór webhooka wymaga publicznego callbacku https i sekretu podpisu; bez nich demo wraca do odpytywania Twoich transakcji, więc działa bez konfiguracji.
14

Najlepsze praktyki, limity i bezpieczeństwo

Bezpieczeństwo

  • Trzymaj klucz API i sekret podpisu tylko po stronie serwera; w razie wycieku natychmiast rotuj którykolwiek z nich.
  • Zawsze weryfikuj podpis webhooka na surowej treści i odrzucaj dostarczenia starsze niż ~5 minut (ochrona przed powtórzeniem).
  • Wykonuj swoją akcję tylko przy confirmation.completed — nigdy przy odpowiedzi /deduct (w tym momencie obciążenie nie jest ostateczne).
  • Używaj listy dozwolonych IP i żądaj tylko tych zakresów, których naprawdę potrzebujesz.

Limity

  • Potwierdzenia wygasają po 10 minutach; traktuj niepotwierdzone żądania jako porzucone.
  • Limity szybkości są na projekt i skalują się z poziomem członkostwa właściciela.
  • amount musi być dodatnią liczbą całkowitą; metadata jest ograniczone do 10 kluczy.
Idempotency-Key usuwa duplikaty ponowieńWebhooki ponawiają 5× z wycofaniemPotwierdź szybko 2xx, realizuj asynchronicznie