Dokumentasi Vito API

Terakhir diperbarui: 26 Juni 2026
01

Ringkasan

Vito API memungkinkan aplikasi Anda bekerja dengan saldo Vito pengguna dari dalam Discord — membacanya, menagihnya, atau mengkreditkannya kembali. Pengguna mengonfirmasi setiap tagihan dengan PIN di vetox.io sebelum ada Vito yang berpindah, dan aplikasi Anda diberi tahu hasilnya. Vito adalah mata uang virtual internal ekosistem Vetox; gunakan API untuk membangun pengalaman berbasis Vito — membuka konten, fitur, keuntungan, atau hadiah. Tidak ada pembelian atau penjualan dengan uang sungguhan.

Ini adalah REST API yang diautentikasi dengan kunci rahasia. Semua endpoint mengembalikan JSON dan diberi versi di bawah /v1.

URL dasarhttps://api.vetox.io/public/vito/v1
02

Saldo & penyelesaian

Kunci API Anda terikat ke akun Vetox Anda. Setiap penagihan diselesaikan untuk Anda: saat aplikasi Anda memotong Vito dari pengguna, Vito itu dikreditkan ke saldo Anda sendiri (dikurangi biaya platform), tidak pernah dimusnahkan. Saat aplikasi Anda menambahkan Vito ke pengguna, itu didanai dari saldo Anda.

Vito selalu berpindah antar saldo — tidak pernah dari atau ke uang sungguhan. Pengguna ditagih jumlah penuh yang Anda minta; Anda menerima jumlah setelah biaya platform; kredit dan hadiah didanai dari saldo Anda melalui /add.

Biaya platform — skala yang sama dengan transfer Vito dalam aplikasi, berdasarkan tingkat keanggotaan Anda: 7% (Silver / Gold), 6% (Platinum), 5% (Diamond). Penagihan 5 Vito atau kurang bebas biaya. Kredit melalui /add tidak pernah dikenai biaya.
03

Persyaratan

Akses ke Vito API diberikan per proyek. Sebelum dapat memanggilnya, Anda memerlukan:

  • Keanggotaan pengguna aktif (tingkat Silver atau lebih tinggi). API membeku otomatis jika keanggotaan pemilik berakhir, dan pulih saat berlangganan lagi.
  • Pengajuan pengembang yang disetujui. Kirim satu dari halaman ini; tim Vetox meninjaunya secara manual.
  • Persyaratan Pengembang API yang disetujui — dikonfirmasi saat Anda mengirim aplikasi pengembang Anda.
  • Cakupan yang dibutuhkan proyek Anda. Diberikan oleh tim Vetox berdasarkan pengajuan Anda.

Cakupan yang tersedia

balance:read
Membaca saldo Vito pengguna.
deduct:create
Membuat pemotongan — menagih saldo Vito pengguna.
credit:create
Menambahkan Vito ke pengguna — mendanai hadiah atau kredit dari saldo Anda.
transfer:create
Membuat transfer antara dua pengguna.
transactions:read
Mendaftar dan membaca transaksi proyek Anda.
04

Autentikasi

Autentikasi setiap permintaan dengan kunci API rahasia Anda di header Authorization sebagai token Bearer. Kunci memiliki prefiks vito_live_.

http
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxx

Dua lapisan opsional melindungi proyek Anda lebih lanjut:

  • Daftar izin IP — batasi permintaan ke IP server tertentu (konfigurasikan di tab Pengaturan).
  • Batas laju — plafon permintaan per proyek yang naik sesuai tingkat keanggotaan Anda.
05

Kunci API — penyimpanan, rotasi, dan keamanan

Kunci Anda dibuat saat pengajuan disetujui. Hanya ditampilkan sekali — tampilkan dari tab Kunci API dan simpan segera.

Vetox tidak pernah menyimpan kunci Anda dalam bentuk yang dapat dibaca (hanya hash bergaram). Simpan sebagai rahasia sisi server — variabel lingkungan atau pengelola rahasia — jangan pernah dalam kode klien, repositori git, atau peramban.

Rotasi dari tab Kunci API. Kunci sebelumnya tetap berfungsi selama masa tenggang 24 jam agar Anda dapat menerapkan yang baru tanpa henti, lalu berhenti.

Perlakukan kunci seperti kata sandi — siapa pun yang memilikinya dapat menagih pengguna Anda. Jika bocor, rotasi segera dan tinjau transaksi terbaru Anda.
06

Alur konfirmasi tagihan

Setiap tagihan melalui konfirmasi yang disetujui pengguna dengan PIN — kunci Anda saja tidak pernah memindahkan Vito:

  1. 1Aplikasi Anda memanggil POST /deduct dengan pengguna, jumlah, guildId asal, dan detail item.
  2. 2Vito membuat konfirmasi tertunda (berlaku 10 menit) dan mengembalikan confirmUrl. Jika guildId diberikan, pengguna juga menerima DM berisi detail dengan tombol ke halaman konfirmasi.
  3. 3Pengguna membuka confirmUrl di vetox.io dan menyetujui tagihan dengan PIN dompetnya.
  4. 4Vito memotong Vito, mencatat transaksi, dan — jika Anda mengonfigurasi webhook — mengirim peristiwa confirmation.completed yang ditandatangani ke URL callback Anda.
  5. 5Aplikasi Anda memverifikasi tanda tangan dan menyelesaikan tindakannya (misalnya, membuka konten).
PIN hanya dimasukkan di vetox.io — tidak pernah di aplikasi Anda atau di Discord. Jika pengguna tidak pernah mengonfirmasi, permintaan kedaluwarsa setelah 10 menit dan Anda menerima peristiwa confirmation.expired.
07

Parameter permintaan (/deduct)

POST/v1/deduct

Endpoint pemotongan menerima bidang body berikut:

discordId
ID pengguna Discord milik pengguna — snowflake 17–20 digit. Wajib.
amount
Jumlah Vito yang ditagih — bilangan bulat positif. Wajib.
guildId
Server Discord tempat tagihan berasal (snowflake). Wajib — setiap tagihan harus berasal dari server tertentu, yang juga mengaktifkan DM ke pengguna.
reason
Deskripsi singkat yang dapat dibaca (≤ 256 karakter), ditampilkan ke pengguna dan diulang di webhook.
merchantRef
String referensi Anda sendiri (≤ 128 karakter). Gunakan untuk mencocokkan webhook dengan catatan Anda.
product
Deskriptor item — { type, name, description?, imageUrl? }. Ditampilkan ke pengguna di halaman konfirmasi dan DM, dan diulang di setiap webhook.
product.imageUrl
Gambar produk opsional — harus berupa URL https://.
metadata
Hingga 10 pasangan kunci/nilai string, diteruskan apa adanya di webhook.

* bidang wajib.

Contoh permintaan
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" }
}
Contoh respons
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

Menambahkan Vito — kredit (/add)

POST/v1/add

POST /add mengkreditkan Vito ke pengguna dari saldo Anda sendiri — untuk hadiah atau kredit. Menerima field yang sama dengan /deduct kecuali guildId dan product. Tidak seperti penagihan, ini instan dan tidak memerlukan PIN pengguna — kunci API Anda adalah otoritas Anda — sehingga respons sudah mencerminkan transfer yang selesai. Pengguna menerima jumlah penuh; tidak ada biaya platform yang berlaku.

Memerlukan scope credit:create dan Vito yang cukup di saldo Anda sendiri — jika tidak, panggilan mengembalikan 402 INSUFFICIENT_OWNER_FUNDS.
Contoh permintaan
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" }
}
Contoh respons
json
{
  "success": true,
  "data": {
    "transactionId": "txn_91b2",
    "toDiscordId": "123456789012345678",
    "amount": 250,
    "ownerBalance": 48250,
    "recipientBalance": 1250,
    "status": "completed"
  },
  "requestId": "req_def456",
  "timestamp": 1735689300000
}
09

Webhook dan verifikasi tanda tangan

Tambahkan satu atau beberapa URL callback https di tab Pengaturan. Vito mengirim POST yang ditandatangani ke setiap URL yang dikonfigurasi setiap kali konfirmasi mencapai status akhir, mencoba ulang hingga 5 kali dengan backoff eksponensial.

Webhook hanya terpicu saat proyek Anda memiliki BAIK URL callback yang dikonfigurasi MAUPUN rahasia penandatanganan. Tampilkan rahasia penandatanganan Anda (whsec_…) sekali dari tab Kunci API.

Memverifikasi tanda tangan

Setiap pengiriman membawa header X-Vito-Signature berbentuk ts=<unix>;h1=<hex>. Hitung ulang HMAC atas "<ts>:<rawBody>" dengan rahasia penandatanganan Anda dan bandingkan dalam waktu konstan. Selalu verifikasi terhadap body permintaan mentah, sebelum mem-parsing JSON.

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

Peristiwa webhook dan payload

Vito mengirim salah satu dari empat jenis peristiwa. Semuanya berbagi bentuk payload yang sama; data.status mencerminkan hasilnya.

confirmation.completed
Pengguna mengonfirmasi dan Vito dipotong. Selesaikan tindakan Anda. Membawa transactionId.
confirmation.failed
Tagihan tidak dapat diselesaikan (misalnya, saldo tidak cukup atau kesalahan internal). Membawa failureReason.
confirmation.expired
Pengguna tidak mengonfirmasi dalam 10 menit. Tidak ada Vito berpindah.
confirmation.cancelled
Pengguna membatalkan permintaan. Tidak ada Vito berpindah.
credit.completed
Kredit /add yang didanai pemilik telah diselesaikan. Membawa penerima dan transactionId, dan terpicu seketika — tidak ada langkah konfirmasi.
Contoh 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

Kode kesalahan

Kesalahan mengembalikan status non-2xx dengan body JSON yang membawa error.code tingkat atas. Kasus umum:

400VITO_VALIDATION_ERROR
Bidang permintaan hilang atau salah bentuk (misalnya, guildId tidak valid).
401invalid key
Kunci API hilang, salah bentuk, atau tidak dikenal.
403OWNER_MEMBERSHIP_INACTIVE
Keanggotaan pemilik proyek telah berakhir — API dibekukan hingga ia berlangganan lagi.
403scope / IP
Kunci tidak memiliki cakupan yang diperlukan, atau IP permintaan tidak ada di daftar izin.
404not found
Pengguna, transaksi, atau sumber daya tidak ada.
402insufficient balance
Pengguna tidak memiliki cukup Vito untuk tagihan.
402INSUFFICIENT_OWNER_FUNDS
Saldo Anda sendiri (pemilik) terlalu rendah untuk mendanai kredit /add.
429rate limited
Anda melampaui batas laju proyek — mundur dan coba lagi.
Bentuk respons kesalahan
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

Contoh integrasi

Buat permintaan tagihan:

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

Periksa saldo pengguna:

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

Menguji dengan integrasi demo

Integrasi demo mandiri disediakan untuk menjalankan seluruh alur dari ujung ke ujung tanpa menulis kode. Ia menelusuri permintaan → konfirmasi → PIN → webhook → penyelesaian.

  1. 1Buka folder integrasi demo dan tambahkan kunci Vito API, token bot Discord, dan ID server (guild) uji Anda ke config.json.
  2. 2Jalankan npm install && npm start, lalu buka http://localhost:4000.
  3. 3Cari pengguna berdasarkan ID Discord, pilih item, dan mulai tagihan — demo memanggil /deduct dan menampilkan confirmUrl.
  4. 4Setujui PIN di vetox.io; demo mendeteksi penyelesaian (melalui webhook jika dikonfigurasi, jika tidak melalui polling) dan menyelesaikan tindakan contoh.
Menerima webhook memerlukan callback https publik dan rahasia penandatanganan; tanpa itu, demo kembali ke polling transaksi Anda, sehingga berfungsi tanpa konfigurasi.
14

Praktik terbaik, batas, dan keamanan

Keamanan

  • Simpan kunci API dan rahasia penandatanganan Anda hanya di sisi server; rotasi salah satunya segera jika bocor.
  • Selalu verifikasi tanda tangan webhook terhadap body mentah dan tolak pengiriman yang lebih tua dari ~5 menit (perlindungan replay).
  • Selesaikan tindakan Anda hanya pada confirmation.completed — jangan pernah pada respons /deduct (pada titik itu tagihan belum final).
  • Gunakan daftar izin IP dan minta hanya cakupan yang benar-benar Anda butuhkan.

Batas

  • Konfirmasi kedaluwarsa setelah 10 menit; perlakukan permintaan yang tidak dikonfirmasi sebagai ditinggalkan.
  • Batas laju bersifat per proyek dan naik sesuai tingkat keanggotaan pemilik.
  • amount harus bilangan bulat positif; metadata dibatasi 10 kunci.
Idempotency-Key menghilangkan duplikat percobaan ulangWebhook mencoba ulang 5× dengan backoffBalas 2xx cepat, penuhi secara asinkron