головна сторінка

Початок роботи

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

Sign-In With Solana для API Seeryx: повідомлення, токен у X-Auth-Token або Bearer і ключ торгової сесії, що підписує ваші ордери.

Огляд

ВикликиПотрібно
Ринкові дані: ринки, раунди, книги ордерів, угоди, події, профіліНічого
Ваш акаунт: кошти, позиції, ордери, активністьТокен входу в X-Auth-Token
Ордери, скасування, розділення, об’єднанняТокен і Idempotency-Key; на seeryx.com кожен ордер, розділення й об’єднання також містить signed, створений ключем вашої торгової сесії
Поповнення, виведення, сама сесіяТокен і підпис вашого гаманця під транзакцією, яку готує сервер

Вхід через гаманець

Seeryx використовує вхід через гаманець Solana (Sign-In With Solana): ваш гаманець підписує коротке текстове повідомлення — це безкоштовно й нічого не надсилає в блокчейн.

  1. POST /api/auth/nonce з { "address": "<your wallet>" } повертає повідомлення. Воно дійсне 5 хвилин і спрацьовує лише один раз.
  2. Перевірте, що в рядку 1 указано цей сайт, а в рядку 2 — вашу адресу, потім підпишіть точні байти повідомлення в UTF-8 ключем Ed25519 гаманця й закодуйте 64-байтовий підпис у base58.
  3. POST /api/auth/verify з address, message і signature повертає token. Перший вхід створює акаунт.
Повідомлення
seeryx.com wants you to sign in with your Solana account:
4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm

Sign in to Seeryx. This does not send a transaction or cost a fee.

URI: https://seeryx.com
Version: 1
Chain ID: mainnet
Nonce: a4b5fb6f571c43b4b1c5057abaa8cea2
Issued At: 2026-10-13T18:29:28.000Z
Expiration Time: 2026-10-13T18:34:28.000Z
Chain ID вказує кластер Solana, у якому працює сервер.
seeryx.ts
// seeryx.ts: a small client for the Seeryx API. Node 22+, npm i @solana/kit
import { readFileSync } from 'node:fs';
import { createKeyPairFromBytes, getAddressFromPublicKey, getBase58Decoder, signBytes } from '@solana/kit';
import type { Address } from '@solana/kit';
import { apiUrl } from './api-url.mjs';

export const BASE = process.env.SEERYX_URL ?? 'https://seeryx.com';
export const ACCESS = process.env.SEERYX_ACCESS ?? ''; // only on a site with access codes
let token = '';

export interface Round {
  slug: string; start: number; end: number; open: number | null; close: number | null;
  outcome: 'up' | 'down' | null; status: 'upcoming' | 'live' | 'settled';
}
export interface Book { bids: [price: number, shares: number][]; asks: [price: number, shares: number][] }
export interface Account {
  positions: { slug: string; side: 'up' | 'down'; shares: number; cost: number }[];
  orders: {
    id: number; slug: string; side: 'up' | 'down'; action: 'buy' | 'sell'; shares: number; limit: number;
  }[];
  balance: { available: number; total: number };
}

export class ApiError extends Error {
  constructor(
    message: string, readonly status: number, readonly code?: string, readonly retryAfter?: number,
  ) {
    super(message);
  }
}

// One request. Writes get a fresh Idempotency-Key unless you pass the key of the attempt you are retrying.
export async function api<T>(path: string, init: { method?: string; body?: unknown; key?: string } = {}) {
  const method = init.method ?? 'GET';
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
  if (token) headers['X-Auth-Token'] = token;
  if (ACCESS) headers['X-Access-Token'] = ACCESS;
  if (method !== 'GET') headers['Idempotency-Key'] = init.key ?? crypto.randomUUID();
  const body = init.body === undefined ? undefined : JSON.stringify(init.body);
  const res = await fetch(apiUrl(BASE, path), { method, headers, body, redirect: 'error' });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) {
    const wait = Number(res.headers.get('Retry-After')) || undefined;
    throw new ApiError(data.error ?? `HTTP ${res.status}`, res.status, data.code, wait);
  }
  return data as T;
}

export interface Wallet { pair: CryptoKeyPair; address: Address }

// A wallet file as solana-keygen writes it: a JSON array of 64 numbers.
export async function loadWallet(path = process.env.SEERYX_WALLET ?? 'wallet.json'): Promise<Wallet> {
  const pair = await createKeyPairFromBytes(new Uint8Array(JSON.parse(readFileSync(path, 'utf8'))));
  return { pair, address: await getAddressFromPublicKey(pair.publicKey) };
}

// Sign-In With Solana: ask for the message, check it, sign its exact bytes, trade the signature for a token.
export async function signIn(wallet: Wallet) {
  const { address } = wallet;
  const { message } = await api<{ message: string }>('/auth/nonce', { method: 'POST', body: { address } });
  const [first, second] = message.split('\n');
  const site = `${new URL(BASE).hostname} wants you to sign in with your Solana account:`;
  if (first !== site || second !== address) {
    throw new Error('Unexpected sign-in message: not this site or not this wallet');
  }
  const bytes = await signBytes(wallet.pair.privateKey, new TextEncoder().encode(message));
  const signature = getBase58Decoder().decode(bytes);
  const body = { address, message, signature };
  ({ token } = await api<{ token: string }>('/auth/verify', { method: 'POST', body }));
  return token; // valid for 7 days
}

Токени входу

Заголовок
Надсилайте токен як X-Auth-Token: <token> або Authorization: Bearer <token> у кожному запиті, що потребує входу, і як token у підписці WebSocket на акаунт.
Строк дії
7 днів. Увійдіть знову до завершення цього строку або коли виклик відповідає 403 (seeryx.com) чи 401 з "Invalid or expired token".
Файли cookie
Сам сайт входить за допомогою файлу cookie з HttpOnly і токена CSRF, якими можуть користуватися лише сторінки сайту. API-клієнти використовують заголовок із токеном, і ні те, ні інше їм не потрібне.
Ліміти
30 запитів на хвилину з однієї IP-адреси для кожного з /auth/nonce і /auth/verify.

Ключ торгової сесії

На seeryx.com кожна угода проходить розрахунок у мережі Solana через програму Seeryx, а програма приймає лише ордери, підписані для вашого акаунта. Щоб не просити гаманець підписувати кожен ордер, гаманець один раз підтверджує ключ сесії:

ПолеТипОпис
keyобов’язковепублічний ключНовий ключ Ed25519, створений вашим ботом. Він підписує ордери, розділення й об’єднання.
expiresAtобов’язковесекунди UnixКоли ключ перестає діяти: щонайбільше через maxSessionTtl з GET /api/funds від цього моменту (24 години).
limitобов’язковеUSDCНайбільша сума, яку ключ може витратити на купівлі й розділення загалом.
maxTradeобов’язковеUSDCНайбільша сума, яку може витратити один ордер; не більше за limit.
  • Він може торгувати, але ніколи не виводить кошти. Ключ може лише підписувати ордери, розділення й об’єднання для вашого акаунта в межах своїх лімітів. Для виведення завжди потрібен сам гаманець.
  • Лише один водночас. Нова сесія замінює старий ключ; ордери в книзі, підписані старим ключем, скасовуються, щойно починає діяти новий.
  • Лімітні ордери не можуть пережити сесію. Ордер відхиляється, якщо він стояв би в книзі після завершення сесії: відкрийте нову сесію, перш ніж виставляти котирування для раунду, що закривається пізніше (наприклад, для 1-денних раундів).
  • Безкоштовно. Комісію мережі й ренту за акаунт для транзакції сесії сплачує Seeryx. Ваш рахунок спершу має відкрити перше поповнення (до того: 409 "Deposit first").
  • Закрийте її достроково через POST /api/relay { "action": "close_session" }: ваші ордери в книзі скасовуються, і ключ одразу перестає діяти.

Як відкрити сесію й підписувати нею, байт за байтом: «Підписання ордерів».

Вихід

  • POST /api/auth/logout завершує дію токена, який ви надсилаєте; POST /api/auth/logout-all завершує дію всіх токенів акаунта.
  • Жоден із них не закриває ключ торгової сесії: закрийте його через close_session або дочекайтеся, поки закінчиться строк його дії.
curl
curl -s -X POST https://seeryx.com/api/auth/logout-all -H "X-Auth-Token: $TOKEN"
# {"success":true}

Ендпоінти входу

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

POST/api/auth/nonce

Отримати повідомлення для підпису

Публічний
ПолеТипОпис
addressтілообов’язковеstringАдреса гаманця Solana (base58)
Запит
curl -X POST "https://seeryx.com/api/auth/nonce" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm"}'
Відповідь
{
  "message": "seeryx.com wants you to sign in with your Solana account:\n4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm\n\nSign in to Seeryx. This does not send a transaction or cost a fee.\n\nURI: https://seeryx.com\nVersion: 1\nChain ID: mainnet\nNonce: a4b5fb6f571c43b4b1c5057abaa8cea2\nIssued At: 2026-10-13T18:29:28.000Z\nExpiration Time: 2026-10-13T18:34:28.000Z",
  "nonce": "a4b5fb6f571c43b4b1c5057abaa8cea2"
}
  • Повідомлення дійсне 5 хвилин, і його можна використати лише один раз. Chain ID вказує кластер Solana, у якому працює сервер.
СтатусКоли
400Це не адреса Solana
429Понад 30 запитів на хвилину з вашої IP-адреси
POST/api/auth/verify

Обміняти підписане повідомлення на токен

Публічний
ПолеТипОпис
addressтілообов’язковеstringТа сама адреса гаманця
messageтілообов’язковеstringПовідомлення точно в тому вигляді, у якому його отримано
signatureтілообов’язковеstringПідпис Ed25519 байтів повідомлення (UTF-8), base58
Запит
curl -X POST "https://seeryx.com/api/auth/verify" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm","message":"...","signature":"5Kq3..."}'
Відповідь
{ "token": "eyJ0eXAiOiJKV1Qi...", "user": { "id": 3, "address": "4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm", "createdAt": "2026-10-13 18:29:28" } }
  • Токен дійсний 7 днів. Надсилайте його як X-Auth-Token (або Authorization: Bearer) у кожному запиті, що потребує входу. Перший вхід створює акаунт.
СтатусКоли
401"Signature verification failed" або "Invalid or expired login message"
403Цей акаунт заблоковано
429Понад 30 запитів на хвилину з вашої IP-адреси
GET/api/auth/me

Акаунт, у який виконано вхід, і його кошти

Потрібен вхід
Запит
curl "https://seeryx.com/api/auth/me" \
  -H "X-Auth-Token: $TOKEN"
Відповідь
{ "user": { "id": 3, "address": "4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm", "username": null, "avatar": null },
  "balance": { "total": 474.097965, "available": 474.097965, "locked": 0, "currency": "USDC" } }
POST/api/auth/logout

Завершити дію цього токена входу

Потрібен вхід
Запит
curl -X POST "https://seeryx.com/api/auth/logout" \
  -H "X-Auth-Token: $TOKEN"
Відповідь
{ "success": true }
  • Інші токени акаунта продовжують діяти. Ключ торгової сесії не закривається: закрийте його через POST /api/relay close_session.
POST/api/auth/logout-all

Завершити дію всіх токенів входу акаунта

Потрібен вхід
Запит
curl -X POST "https://seeryx.com/api/auth/logout-all" \
  -H "X-Auth-Token: $TOKEN"
Відповідь
{ "success": true }
  • Усі видані досі токени перестають діяти, зокрема й цей; щоб отримати новий, увійдіть знову.
POST/api/auth/username

Установити або змінити публічне ім’я користувача

Потрібен вхід
ПолеТипОпис
usernameтілообов’язковеstring2–20 літер, цифр або _; унікальне без урахування регістру
Запит
curl -X POST "https://seeryx.com/api/auth/username" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"satoshi_bot"}'
Відповідь
{ "success": true, "username": "satoshi_bot" }
  • Ім’я відображається в рейтингу й у вашому публічному профілі; без нього там показано скорочену адресу вашого гаманця.