Документація Vito API

Останнє оновлення: 26 червня 2026 р.
01

Огляд

Vito API дозволяє вашому застосунку працювати з балансом Vito користувача прямо в Discord — читати його, списувати з нього або зараховувати назад. Користувач підтверджує кожне списання своїм PIN-кодом на vetox.io, перш ніж будь-які Vito перемістяться, а ваш застосунок отримує сповіщення про результат. Vito — це віртуальна валюта в межах екосистеми Vetox; використовуйте API, щоб створювати досвід на основі Vito — розблокування контенту, функцій, переваг або винагород. Жодної купівлі чи продажу за реальні гроші не відбувається.

Це REST API з автентифікацією за секретним ключем. Усі кінцеві точки повертають JSON і версіонуються під /v1.

Базовий URLhttps://api.vetox.io/public/vito/v1
02

Баланси та розрахунки

Ваш API-ключ прив’язаний до вашого облікового запису Vetox. Кожне списання зараховується на вашу користь: коли ваш застосунок списує Vito в користувача, ці Vito зараховуються на ваш власний баланс (за вирахуванням комісії платформи) і ніколи не згоряють. Коли ваш застосунок нараховує Vito користувачу, це фінансується з вашого балансу.

Vito завжди переміщується між балансами — ніколи з реальних грошей або в них. З користувача стягується повна запитана вами сума; ви отримуєте суму за вирахуванням комісії платформи; зарахування та винагороди фінансуються з вашого балансу через /add.

Комісія платформи — та сама шкала, що й для внутрішніх переказів Vito, залежно від вашого рівня членства: 7% (Silver / Gold), 6% (Platinum), 5% (Diamond). Списання на 5 Vito або менше — без комісії. Зарахування через /add ніколи не оподатковуються комісією.
03

Вимоги

Доступ до Vito API надається для кожного проєкту. Перш ніж викликати його, вам потрібно:

  • Активне членство користувача (рівень Silver або вище). API автоматично заморожується, якщо членство власника закінчується, і відновлюється при повторній підписці.
  • Схвалену заявку розробника. Подайте її з цієї сторінки; команда Vetox перевіряє її вручну.
  • Прийнято умови для розробників API — підтверджуються під час подання заявки розробника.
  • Області доступу, потрібні вашому проєкту. Їх надає команда Vetox на основі вашої заявки.

Доступні області

balance:read
Читання балансу Vito користувача.
deduct:create
Створення списання — стягнення з балансу Vito користувача.
credit:create
Нарахувати Vito користувачу — фінансувати винагороди або зарахування зі свого балансу.
transfer:create
Створення переказу між двома користувачами.
transactions:read
Перегляд і читання транзакцій вашого проєкту.
04

Автентифікація

Автентифікуйте кожен запит секретним ключем API в заголовку Authorization як токен Bearer. Ключі мають префікс vito_live_.

http
Authorization: Bearer vito_live_xxxxxxxxxxxxxxxx

Два необов’язкові рівні додатково захищають ваш проєкт:

  • Список дозволених IP — обмежте запити конкретними IP сервера (налаштуйте на вкладці Налаштування).
  • Ліміти запитів — стелі запитів на проєкт, що масштабуються з вашим рівнем членства.
05

Ключі API — зберігання, ротація та безпека

Ваш ключ створюється при схваленні заявки. Він показується лише один раз — розкрийте його на вкладці Ключі API та одразу збережіть.

Vetox ніколи не зберігає ваш ключ у читабельному вигляді (лише солений хеш). Зберігайте його як секрет на стороні сервера — змінну середовища або менеджер секретів — ніколи в клієнтському коді, git-репозиторії чи браузері.

Ротуйте його на вкладці Ключі API. Попередній ключ працює ще 24-годинний пільговий період, щоб ви розгорнули новий без простою, а потім перестає.

Ставтеся до ключа як до пароля — будь-хто, у кого він є, може стягувати кошти з ваших користувачів. У разі витоку негайно ротуйте та перегляньте останні транзакції.
06

Процес підтвердження списання

Кожне списання проходить через підтвердження, яке користувач схвалює PIN-кодом — сам лише ваш ключ ніколи не переміщує Vito:

  1. 1Ваш застосунок викликає POST /deduct з користувачем, сумою, вихідним guildId і деталями елемента.
  2. 2Vito створює очікуване підтвердження (дійсне 10 хвилин) і повертає confirmUrl. Якщо вказано guildId, користувачу також надсилається ПП з деталями та кнопкою на сторінку підтвердження.
  3. 3Користувач відкриває confirmUrl на vetox.io і схвалює списання PIN-кодом свого гаманця.
  4. 4Vito списує Vito, записує транзакцію і — якщо у вас налаштований вебхук — надсилає підписану подію confirmation.completed на ваш URL зворотного виклику.
  5. 5Ваш застосунок перевіряє підпис і виконує свою дію (наприклад, розблоковує контент).
PIN-коди вводяться лише на vetox.io — ніколи у вашому застосунку чи в Discord. Якщо користувач не підтвердить, запит закінчується через 10 хвилин, і ви отримуєте подію confirmation.expired.
07

Параметри запиту (/deduct)

POST/v1/deduct

Кінцева точка списання приймає такі поля тіла:

discordId
Discord-ідентифікатор користувача — snowflake з 17–20 цифр. Обов’язково.
amount
Кількість Vito для списання — додатне ціле число. Обов’язково.
guildId
Discord-сервер, з якого походить списання (snowflake). Обов’язково — кожне списання має походити з конкретного сервера, що також вмикає ПП користувачу.
reason
Короткий читабельний опис (≤ 256 символів), показаний користувачу та повторений у вебхуку.
merchantRef
Ваш власний рядок посилання (≤ 128 символів). Використовуйте його, щоб зіставити вебхук із вашими записами.
product
Дескриптор елемента — { type, name, description?, imageUrl? }. Показується користувачу на сторінці підтвердження та в ПП і повторюється в кожному вебхуку.
product.imageUrl
Необов’язкове зображення продукту — має бути URL https://.
metadata
До 10 рядкових пар ключ/значення, що передаються без змін у вебхуку.

* обов’язкове поле.

Приклад запиту
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" }
}
Приклад відповіді
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 — зарахування (/add)

POST/v1/add

POST /add зараховує Vito користувачу з вашого власного балансу — для винагород або зарахувань. Приймає ті самі поля, що й /deduct, окрім guildId та product. На відміну від списання, воно миттєве й не потребує PIN користувача — ваш API-ключ є вашим повноваженням — тож відповідь уже відображає завершений переказ. Користувач отримує повну суму; комісія платформи не застосовується.

Потребує область credit:create і достатньо Vito на вашому балансі — інакше виклик повертає 402 INSUFFICIENT_OWNER_FUNDS.
Приклад запиту
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" }
}
Приклад відповіді
json
{
  "success": true,
  "data": {
    "transactionId": "txn_91b2",
    "toDiscordId": "123456789012345678",
    "amount": 250,
    "ownerBalance": 48250,
    "recipientBalance": 1250,
    "status": "completed"
  },
  "requestId": "req_def456",
  "timestamp": 1735689300000
}
09

Вебхуки та перевірка підпису

Додайте один або кілька https-URL зворотного виклику на вкладці Налаштування. Vito доставляє підписаний POST на кожен налаштований URL, коли підтвердження досягає кінцевого стану, повторюючи до 5 разів з експоненційною затримкою.

Вебхуки спрацьовують лише коли ваш проєкт має ОДНОЧАСНО налаштований URL зворотного виклику ТА секрет підпису. Розкрийте секрет підпису (whsec_…) один раз на вкладці Ключі API.

Перевірка підпису

Кожна доставка містить заголовок X-Vito-Signature вигляду ts=<unix>;h1=<hex>. Перерахуйте HMAC за "<ts>:<rawBody>" вашим секретом підпису та порівняйте за сталий час. Завжди перевіряйте за необробленим тілом запиту, до розбору JSON.

http
signature = HMAC_SHA256(signingSecret, "<ts>:<rawBody>")
header    = X-Vito-Signature: ts=<unix-seconds>;h1=<hex-signature>
Еталонний перевіряч (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

Події вебхуків та корисні навантаження

Vito надсилає один із чотирьох типів подій. Усі вони мають однакову форму корисного навантаження; data.status відображає результат.

confirmation.completed
Користувач підтвердив, і Vito списано. Виконайте свою дію. Містить transactionId.
confirmation.failed
Списання не вдалося завершити (наприклад, недостатній баланс або внутрішня помилка). Містить failureReason.
confirmation.expired
Користувач не підтвердив протягом 10 хвилин. Vito не переміщено.
confirmation.cancelled
Користувач скасував запит. Vito не переміщено.
credit.completed
Нарахування /add, профінансоване власником, розраховано. Містить отримувача й transactionId і спрацьовує негайно — кроку підтвердження немає.
Приклад корисного навантаження (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

Коди помилок

Помилки повертають статус, відмінний від 2xx, з тілом JSON, що містить error.code верхнього рівня. Поширені випадки:

400VITO_VALIDATION_ERROR
Поле запиту відсутнє або неправильно сформоване (наприклад, недійсний guildId).
401invalid key
Відсутній, неправильно сформований або невідомий ключ API.
403OWNER_MEMBERSHIP_INACTIVE
Членство власника проєкту закінчилося — API заморожено до повторної підписки.
403scope / IP
Ключу бракує потрібної області доступу, або IP запиту не в списку дозволених.
404not found
Користувач, транзакція або ресурс не існує.
402insufficient balance
У користувача недостатньо Vito для списання.
402INSUFFICIENT_OWNER_FUNDS
Вашого власного балансу (власника) замало, щоб профінансувати нарахування /add.
429rate limited
Ви перевищили ліміт запитів проєкту — зачекайте та повторіть.
Форма відповіді про помилку
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

Приклади інтеграції

Створити запит на списання:

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

Перевірити баланс користувача:

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

Тестування з демонстраційною інтеграцією

Надається автономна демонстраційна інтеграція для відпрацювання повного процесу від початку до кінця без написання коду. Вона проходить запит → підтвердження → PIN → вебхук → завершення.

  1. 1Відкрийте папку демонстраційної інтеграції і додайте ваш ключ Vito API, токен бота Discord та ID тестового сервера (guild) до config.json.
  2. 2Виконайте npm install && npm start, потім відкрийте http://localhost:4000.
  3. 3Знайдіть користувача за Discord ID, виберіть елемент і почніть списання — демо викликає /deduct і показує confirmUrl.
  4. 4Підтвердьте PIN на vetox.io; демо виявляє завершення (через вебхук, якщо налаштовано, інакше опитуванням) і виконує демонстраційну дію.
Прийом вебхука потребує публічного https-callback та секрету підпису; без них демо повертається до опитування ваших транзакцій, тож працює без налаштування.
14

Найкращі практики, ліміти та безпека

Безпека

  • Тримайте ключ API та секрет підпису лише на стороні сервера; у разі витоку негайно ротуйте будь-який із них.
  • Завжди перевіряйте підпис вебхука за необробленим тілом і відхиляйте доставки, старші за ~5 хвилин (захист від повторів).
  • Виконуйте свою дію лише при confirmation.completed — ніколи за відповіддю /deduct (у цей момент списання ще не остаточне).
  • Використовуйте список дозволених IP і запитуйте лише ті області доступу, які справді потрібні.

Ліміти

  • Підтвердження закінчуються через 10 хвилин; вважайте непідтверджені запити покинутими.
  • Ліміти запитів діють на проєкт і масштабуються з рівнем членства власника.
  • amount має бути додатним цілим числом; metadata обмежено 10 ключами.
Idempotency-Key усуває дублі повторівВебхуки повторюють 5× із затримкоюШвидко відповідайте 2xx, виконуйте асинхронно