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
| Aufrufe | Braucht |
|---|---|
| Marktdaten: Märkte, Runden, Orderbücher, Trades, Ereignisse, Profile | Nichts |
| Dein Konto: Guthaben, Positionen, Orders, Aktivität | Ein Anmelde-Token in X-Auth-Token |
| Orders, Stornierungen, Aufteilungen, Zusammenlegungen | Das 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 selbst | Das 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.
POST /api/auth/noncemit{ "address": "<your wallet>" }liefert die Nachricht. Sie ist 5 Minuten gültig und funktioniert einmal.- 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.
POST /api/auth/verifymitaddress,messageundsignaturelieferttoken. Die erste Anmeldung legt das Konto an.
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// 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>oderAuthorization: Bearer <token>und beim Abonnieren des Kontos über den WebSocket alstoken. - 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/nonceund/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:
| Feld | Typ | Beschreibung |
|---|---|---|
key | öffentlicher Schlüssel | Ein neuer Ed25519-Schlüssel, den dein Bot erzeugt hat. Er signiert Orders, Aufteilungen und Zusammenlegungen. |
expiresAt | Unix-Sekunden | Wann der Schlüssel aufhört zu funktionieren: höchstens maxSessionTtl von GET /api/funds ab jetzt (24 Stunden). |
limit | USDC | Der Höchstbetrag, den der Schlüssel insgesamt für Käufe und Aufteilungen ausgeben darf. |
maxTrade | USDC | Der 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/logoutbeendet das Token, das du sendest;POST /api/auth/logout-allbeendet alle Tokens des Kontos.- Keins von beiden beendet den Sitzungsschlüssel: Schließe ihn mit
close_sessionoder lass ihn ablaufen.
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.
/api/auth/nonceDie zu signierende Nachricht abrufen
| Feld | Typ | Beschreibung |
|---|---|---|
address | string | Solana-Wallet-Adresse (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"
}- Die Nachricht ist 5 Minuten gültig und kann einmal verwendet werden. Chain ID nennt den Solana-Cluster des Servers.
| Status | Wann |
|---|---|
| 400 | Keine Solana-Adresse |
| 429 | Mehr als 30 Anfragen pro Minute von deiner IP-Adresse |
/api/auth/verifyDie signierte Nachricht gegen ein Token tauschen
| Feld | Typ | Beschreibung |
|---|---|---|
address | string | Dieselbe Wallet-Adresse |
message | string | Die Nachricht genau wie erhalten |
signature | string | Ed25519-Signatur der Nachrichtenbytes (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" } }- 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.
| Status | Wann |
|---|---|
| 401 | „Signature verification failed“ oder „Invalid or expired login message“ |
| 403 | Dieses Konto ist gesperrt |
| 429 | Mehr als 30 Anfragen pro Minute von deiner IP-Adresse |
/api/auth/meDas angemeldete Konto und sein Guthaben
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" } }/api/auth/logoutDieses Anmelde-Token beenden
curl -X POST "https://seeryx.com/api/auth/logout" \
-H "X-Auth-Token: $TOKEN"{ "success": true }- Andere Tokens des Kontos funktionieren weiter. Der Sitzungsschlüssel wird dadurch nicht beendet: Schließe ihn mit POST /api/relay close_session.
/api/auth/logout-allAlle Anmelde-Tokens des Kontos beenden
curl -X POST "https://seeryx.com/api/auth/logout-all" \
-H "X-Auth-Token: $TOKEN"{ "success": true }- Jedes bisher erstellte Token funktioniert nicht mehr, auch dieses; melde dich für ein neues erneut an.
/api/auth/usernameDen öffentlichen Benutzernamen festlegen oder ändern
| Feld | Typ | Beschreibung |
|---|---|---|
username | string | 2–20 Buchstaben, Ziffern oder _; eindeutig ohne Beachtung der Groß-/Kleinschreibung |
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" }- Der Name erscheint in der Rangliste und in deinem öffentlichen Profil; ohne Namen zeigen sie deine gekürzte Wallet-Adresse.