pagina iniziale

Per iniziare

Autenticazione

Sign-In With Solana per l’API di Seeryx: il messaggio, il token in X-Auth-Token o Bearer e la chiave di sessione che firma i tuoi ordini.

Panoramica

ChiamateRequisiti
Dati di mercato: mercati, round, libri ordini, operazioni, eventi, profiliNiente
Il tuo conto: fondi disponibili, posizioni, ordini, attivitàUn token di accesso in X-Auth-Token
Ordini, annullamenti, divisioni, unioniIl token e una Idempotency-Key; su seeryx.com ogni ordine, divisione e unione include anche signed, creato dalla tua chiave di sessione di trading
Depositi, prelievi, la sessione stessaIl token e la firma del tuo wallet sulla transazione preparata dal server

Accedi con un wallet

Seeryx usa Sign-In With Solana: il tuo wallet firma un breve messaggio di testo, che non costa nulla e non invia nulla on-chain.

  1. POST /api/auth/nonce con { "address": "<your wallet>" } restituisce il messaggio. È valido per 5 minuti e funziona una sola volta.
  2. Verifica che la riga 1 indichi questo sito e la riga 2 il tuo indirizzo, poi firma i byte UTF-8 esatti del messaggio con la chiave Ed25519 del wallet e codifica la firma di 64 byte in base58.
  3. POST /api/auth/verify con address, message e signature restituisce token. Il primo accesso crea il conto.
Il messaggio
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 indica il cluster Solana del server.
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
}

Token di accesso

Intestazione
Invia il token come X-Auth-Token: <token> o Authorization: Bearer <token> in ogni richiesta autenticata, e come token nell’iscrizione al conto del WebSocket.
Durata
7 giorni. Accedi di nuovo prima della scadenza, o quando una chiamata risponde 403 (seeryx.com) o 401 con "Invalid or expired token".
Cookie
Il sito stesso accede con un cookie HttpOnly e un token CSRF, utilizzabili solo dalle pagine del sito. I client dell’API usano l’intestazione con il token e non hanno bisogno di nessuno dei due.
Limiti
30 richieste al minuto per indirizzo IP per ciascuno tra /auth/nonce e /auth/verify.

La chiave di sessione di trading

Su seeryx.com ogni operazione viene regolata su Solana tramite il programma Seeryx, e il programma accetta solo ordini firmati per il tuo conto. Invece di chiedere al wallet di firmare ogni ordine, il wallet approva una sola volta una chiave di sessione:

CampoTipoDescrizione
keyobbligatoriochiave pubblicaUna nuova chiave Ed25519 creata dal tuo bot. Firma ordini, divisioni e unioni.
expiresAtobbligatoriosecondi UnixQuando la chiave smette di funzionare: al massimo maxSessionTtl di GET /api/funds da adesso (24 ore).
limitobbligatorioUSDCLa spesa massima complessiva della chiave per acquisti e divisioni.
maxTradeobbligatorioUSDCLa spesa massima di un singolo ordine; al massimo pari a limit.
  • Può fare trading, mai prelevare. La chiave può firmare solo ordini, divisioni e unioni per il tuo conto, entro i suoi limiti. I prelievi richiedono sempre il wallet stesso.
  • Una alla volta. Una nuova sessione sostituisce la chiave precedente; gli ordini in attesa firmati dalla vecchia chiave vengono annullati non appena si inizia a usare quella nuova.
  • Gli ordini limite non devono sopravviverle. Un ordine in attesa viene rifiutato se resterebbe nel libro ordini oltre la fine della sessione: apri una nuova sessione prima di quotare un round che chiude più tardi (per esempio i round da 1 giorno).
  • Gratuita. Seeryx paga la commissione di rete e il rent dell’account della transazione di sessione. Il tuo primo deposito deve aver già aperto il tuo conto (fino ad allora: 409 "Deposit first").
  • Chiudila in anticipo con POST /api/relay { "action": "close_session" }: i tuoi ordini in attesa vengono annullati e la chiave smette subito di funzionare.

Come aprire la sessione e firmare con essa, byte per byte: Firma degli ordini.

Disconnessione

  • POST /api/auth/logout invalida il token che invii; POST /api/auth/logout-all invalida tutti i token del conto.
  • Nessuno dei due chiude la chiave di sessione di trading: chiudila con close_session o lasciala scadere.
curl
curl -s -X POST https://seeryx.com/api/auth/logout-all -H "X-Auth-Token: $TOKEN"
# {"success":true}

Endpoint di accesso

Accedi con un wallet Solana: chiedi un messaggio, firmane i byte esatti con la chiave del wallet, scambia la firma con un token. Non viene inviato nulla on-chain e non si paga alcuna commissione.

POST/api/auth/nonce

Ottieni il messaggio da firmare

Pubblico
CampoTipoDescrizione
addresscorpoobbligatoriostringIndirizzo del wallet Solana (base58)
Richiesta
curl -X POST "https://seeryx.com/api/auth/nonce" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm"}'
Risposta
{
  "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"
}
  • Il messaggio è valido per 5 minuti e può essere usato una sola volta. Chain ID indica il cluster Solana del server.
StatoQuando
400Non è un indirizzo Solana
429Più di 30 richieste al minuto dal tuo indirizzo IP
POST/api/auth/verify

Scambia il messaggio firmato con un token

Pubblico
CampoTipoDescrizione
addresscorpoobbligatoriostringLo stesso indirizzo del wallet
messagecorpoobbligatoriostringIl messaggio esattamente come ricevuto
signaturecorpoobbligatoriostringFirma Ed25519 dei byte del messaggio (UTF-8), in base58
Richiesta
curl -X POST "https://seeryx.com/api/auth/verify" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm","message":"...","signature":"5Kq3..."}'
Risposta
{ "token": "eyJ0eXAiOiJKV1Qi...", "user": { "id": 3, "address": "4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm", "createdAt": "2026-10-13 18:29:28" } }
  • Il token è valido per 7 giorni. Invialo come X-Auth-Token (o Authorization: Bearer) in ogni richiesta autenticata. Il primo accesso crea il conto.
StatoQuando
401"Signature verification failed" o "Invalid or expired login message"
403Questo conto è bloccato
429Più di 30 richieste al minuto dal tuo indirizzo IP
GET/api/auth/me

Il conto con cui hai effettuato l’accesso e i suoi fondi disponibili

Con accesso
Richiesta
curl "https://seeryx.com/api/auth/me" \
  -H "X-Auth-Token: $TOKEN"
Risposta
{ "user": { "id": 3, "address": "4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm", "username": null, "avatar": null },
  "balance": { "total": 474.097965, "available": 474.097965, "locked": 0, "currency": "USDC" } }
POST/api/auth/logout

Invalida questo token di accesso

Con accesso
Richiesta
curl -X POST "https://seeryx.com/api/auth/logout" \
  -H "X-Auth-Token: $TOKEN"
Risposta
{ "success": true }
  • Gli altri token del conto continuano a funzionare. Non chiude la chiave di sessione di trading: chiudila con POST /api/relay close_session.
POST/api/auth/logout-all

Invalida tutti i token di accesso del conto

Con accesso
Richiesta
curl -X POST "https://seeryx.com/api/auth/logout-all" \
  -H "X-Auth-Token: $TOKEN"
Risposta
{ "success": true }
  • Tutti i token creati finora smettono di funzionare, compreso questo; accedi di nuovo per ottenerne uno nuovo.
POST/api/auth/username

Imposta o modifica il nome utente pubblico

Con accesso
CampoTipoDescrizione
usernamecorpoobbligatoriostringDa 2 a 20 caratteri tra lettere, cifre o _; unico senza distinzione tra maiuscole e minuscole
Richiesta
curl -X POST "https://seeryx.com/api/auth/username" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"satoshi_bot"}'
Risposta
{ "success": true, "username": "satoshi_bot" }
  • Il nome compare nella classifica e nel tuo profilo pubblico; senza nome vi compare il tuo wallet abbreviato.