Startseite

Erste Schritte

Authentifizierung

Sign-In With Solana für die Seeryx-API: die Nachricht, das Token in X-Auth-Token oder Bearer und der Sitzungsschlüssel, der deine Orders signiert.

Überblick

AufrufeBraucht
Marktdaten: Märkte, Runden, Orderbücher, Trades, Ereignisse, ProfileNichts
Dein Konto: Guthaben, Positionen, Orders, AktivitätEin Anmelde-Token in X-Auth-Token
Orders, Stornierungen, Aufteilungen, ZusammenlegungenDas Token und einen Idempotency-Key; auf seeryx.com trägt jede Order, Aufteilung und Zusammenlegung außerdem signed, erstellt von deinem Sitzungsschlüssel
Einzahlungen, Abhebungen, die Sitzung selbstDas Token und die Signatur deiner Wallet für die Transaktion, die der Server vorbereitet

Mit einer Wallet anmelden

Seeryx verwendet Sign-In With Solana: Deine Wallet signiert eine kurze Textnachricht; das kostet nichts und sendet nichts auf die Blockchain.

  1. POST /api/auth/nonce mit { "address": "<your wallet>" } liefert die Nachricht. Sie ist 5 Minuten gültig und funktioniert einmal.
  2. Prüfe, dass Zeile 1 diese Website und Zeile 2 deine Adresse nennt, signiere dann die exakten UTF-8-Bytes der Nachricht mit dem Ed25519-Schlüssel der Wallet und kodiere die 64-Byte-Signatur in Base58.
  3. POST /api/auth/verify mit address, message und signature liefert token. Die erste Anmeldung legt das Konto an.
Die Nachricht
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 nennt den Solana-Cluster des Servers.
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
}

Anmelde-Tokens

Header
Sende das Token bei jeder angemeldeten Anfrage als X-Auth-Token: <token> oder Authorization: Bearer <token> und beim Abonnieren des Kontos über den WebSocket als token.
Gültigkeit
7 Tage. Melde dich vorher erneut an oder wenn ein Aufruf mit 403 (seeryx.com) oder 401 mit „Invalid or expired token“ antwortet.
Cookies
Die Website selbst meldet sich mit einem HttpOnly-Cookie und einem CSRF-Token an, die nur Seiten der Website verwenden können. API-Clients verwenden den Token-Header und brauchen keins von beiden.
Limits
30 Anfragen pro Minute und IP-Adresse jeweils für /auth/nonce und /auth/verify.

Der Sitzungsschlüssel

Auf seeryx.com wird jeder Trade über das Seeryx-Programm auf Solana abgewickelt, und das Programm akzeptiert nur Orders, die für dein Konto signiert sind. Statt die Wallet bei jeder Order zu fragen, bestätigt die Wallet einmal einen Sitzungsschlüssel:

FeldTypBeschreibung
keyerforderlichöffentlicher SchlüsselEin neuer Ed25519-Schlüssel, den dein Bot erzeugt hat. Er signiert Orders, Aufteilungen und Zusammenlegungen.
expiresAterforderlichUnix-SekundenWann der Schlüssel aufhört zu funktionieren: höchstens maxSessionTtl von GET /api/funds ab jetzt (24 Stunden).
limiterforderlichUSDCDer Höchstbetrag, den der Schlüssel insgesamt für Käufe und Aufteilungen ausgeben darf.
maxTradeerforderlichUSDCDer Höchstbetrag, den eine einzelne Order ausgeben darf; höchstens limit.
  • Er kann handeln, nie abheben. Der Schlüssel kann nur Orders, Aufteilungen und Zusammenlegungen für dein Konto innerhalb seiner Limits signieren. Abhebungen brauchen immer die Wallet selbst.
  • Immer nur einer. Eine neue Sitzung ersetzt den alten Schlüssel; Orders im Orderbuch, die der alte Schlüssel signiert hat, werden storniert, sobald der neue verwendet wird.
  • Limit-Orders dürfen sie nicht überdauern. Eine Order wird abgelehnt, wenn sie über das Ende der Sitzung hinaus im Orderbuch liegen würde: Öffne eine neue Sitzung, bevor du eine Runde quotierst, die später endet (zum Beispiel die 1-Tages-Runden).
  • Kostenlos. Seeryx zahlt die Netzwerkgebühr und die Kontomiete (Rent) der Sitzungstransaktion. Deine erste Einzahlung muss vorher dein Konto eröffnet haben (bis dahin: 409 „Deposit first“).
  • Vorzeitig schließen mit POST /api/relay { "action": "close_session" }: Deine Orders im Orderbuch werden storniert, und der Schlüssel funktioniert sofort nicht mehr.

Wie du die Sitzung öffnest und damit signierst, Byte für Byte: Orders signieren.

Abmelden

  • POST /api/auth/logout beendet das Token, das du sendest; POST /api/auth/logout-all beendet alle Tokens des Kontos.
  • Keins von beiden beendet den Sitzungsschlüssel: Schließe ihn mit close_session oder lass ihn ablaufen.
curl
curl -s -X POST https://seeryx.com/api/auth/logout-all -H "X-Auth-Token: $TOKEN"
# {"success":true}

Anmelde-Endpunkte

Melde dich mit einer Solana-Wallet an: Fordere eine Nachricht an, signiere ihre exakten Bytes mit dem Wallet-Schlüssel und tausche die Signatur gegen ein Token. Nichts wird auf die Blockchain gesendet, und es fällt keine Gebühr an.

POST/api/auth/nonce

Die zu signierende Nachricht abrufen

Öffentlich
FeldTypBeschreibung
addressBodyerforderlichstringSolana-Wallet-Adresse (Base58)
Anfrage
curl -X POST "https://seeryx.com/api/auth/nonce" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm"}'
Antwort
{
  "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"
}
  • Die Nachricht ist 5 Minuten gültig und kann einmal verwendet werden. Chain ID nennt den Solana-Cluster des Servers.
StatusWann
400Keine Solana-Adresse
429Mehr als 30 Anfragen pro Minute von deiner IP-Adresse
POST/api/auth/verify

Die signierte Nachricht gegen ein Token tauschen

Öffentlich
FeldTypBeschreibung
addressBodyerforderlichstringDieselbe Wallet-Adresse
messageBodyerforderlichstringDie Nachricht genau wie erhalten
signatureBodyerforderlichstringEd25519-Signatur der Nachrichtenbytes (UTF-8), Base58
Anfrage
curl -X POST "https://seeryx.com/api/auth/verify" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm","message":"...","signature":"5Kq3..."}'
Antwort
{ "token": "eyJ0eXAiOiJKV1Qi...", "user": { "id": 3, "address": "4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm", "createdAt": "2026-10-13 18:29:28" } }
  • Das Token ist 7 Tage gültig. Sende es bei jeder angemeldeten Anfrage als X-Auth-Token (oder Authorization: Bearer). Die erste Anmeldung legt das Konto an.
StatusWann
401„Signature verification failed“ oder „Invalid or expired login message“
403Dieses Konto ist gesperrt
429Mehr als 30 Anfragen pro Minute von deiner IP-Adresse
GET/api/auth/me

Das angemeldete Konto und sein Guthaben

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

Dieses Anmelde-Token beenden

Angemeldet
Anfrage
curl -X POST "https://seeryx.com/api/auth/logout" \
  -H "X-Auth-Token: $TOKEN"
Antwort
{ "success": true }
  • Andere Tokens des Kontos funktionieren weiter. Der Sitzungsschlüssel wird dadurch nicht beendet: Schließe ihn mit POST /api/relay close_session.
POST/api/auth/logout-all

Alle Anmelde-Tokens des Kontos beenden

Angemeldet
Anfrage
curl -X POST "https://seeryx.com/api/auth/logout-all" \
  -H "X-Auth-Token: $TOKEN"
Antwort
{ "success": true }
  • Jedes bisher erstellte Token funktioniert nicht mehr, auch dieses; melde dich für ein neues erneut an.
POST/api/auth/username

Den öffentlichen Benutzernamen festlegen oder ändern

Angemeldet
FeldTypBeschreibung
usernameBodyerforderlichstring2–20 Buchstaben, Ziffern oder _; eindeutig ohne Beachtung der Groß-/Kleinschreibung
Anfrage
curl -X POST "https://seeryx.com/api/auth/username" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"satoshi_bot"}'
Antwort
{ "success": true, "username": "satoshi_bot" }
  • Der Name erscheint in der Rangliste und in deinem öffentlichen Profil; ohne Namen zeigen sie deine gekürzte Wallet-Adresse.