inicio

Primeros pasos

Autenticación

Sign-In With Solana para la API de Seeryx: el mensaje, el token en X-Auth-Token o Bearer y la clave de la sesión de trading que firma tus órdenes.

Descripción general

LlamadasRequisitos
Datos de mercado: mercados, rondas, libros, operaciones, eventos, perfilesNada
Tu cuenta: efectivo, posiciones, órdenes, actividadUn token de inicio de sesión en X-Auth-Token
Órdenes, cancelaciones, divisiones, combinacionesEl token y una Idempotency-Key; en seeryx.com cada orden, división y combinación lleva además signed, creado por tu clave de sesión de trading
Depósitos, retiros, la propia sesiónEl token y la firma de tu billetera en la transacción que prepara el servidor

Iniciar sesión con una billetera

Seeryx usa Sign-In With Solana: tu billetera firma un breve mensaje de texto, lo que no cuesta nada ni envía nada a la cadena de bloques.

  1. POST /api/auth/nonce con { "address": "<your wallet>" } devuelve el mensaje. Es válido durante 5 minutos y solo funciona una vez.
  2. Comprueba que la línea 1 nombra este sitio y la línea 2 tu dirección; después, firma los bytes UTF-8 exactos del mensaje con la clave Ed25519 de la billetera y codifica la firma de 64 bytes en base58.
  3. POST /api/auth/verify con address, message y signature devuelve token. El primer inicio de sesión crea la cuenta.
El mensaje
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 el clúster de Solana del servidor.
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
}

Tokens de inicio de sesión

Cabecera
Envía el token como X-Auth-Token: <token> o Authorization: Bearer <token> en cada solicitud con sesión iniciada, y como token en la suscripción de cuenta del WebSocket.
Vigencia
7 días. Vuelve a iniciar sesión antes de que venza, o cuando una llamada responda 403 (seeryx.com) o 401 con "Invalid or expired token".
Cookies
El propio sitio web inicia sesión con una cookie HttpOnly y un token CSRF, que solo pueden usar las páginas del sitio. Los clientes de la API usan la cabecera del token y no necesitan ninguno de los dos.
Límites
30 solicitudes por minuto y por dirección IP para cada uno de /auth/nonce y /auth/verify.

La clave de la sesión de trading

En seeryx.com cada operación se liquida en Solana a través del programa de Seeryx, y el programa solo acepta órdenes firmadas para tu cuenta. En lugar de pedir a la billetera que firme cada orden, la billetera aprueba una vez una clave de sesión:

CampoTipoDescripción
keyobligatorioclave públicaUna clave Ed25519 nueva creada por tu bot. Firma órdenes, divisiones y combinaciones.
expiresAtobligatoriosegundos UnixCuándo deja de funcionar la clave: como máximo maxSessionTtl de GET /api/funds a partir de ahora (24 horas).
limitobligatorioUSDCLo máximo que la clave puede gastar en compras y divisiones en total.
maxTradeobligatorioUSDCLo máximo que puede gastar una orden; como máximo, limit.
  • Puede operar, nunca retirar. La clave solo puede firmar órdenes, divisiones y combinaciones para tu cuenta dentro de sus límites. Los retiros siempre necesitan la propia billetera.
  • Una sola a la vez. Una sesión nueva reemplaza la clave anterior; las órdenes en el libro firmadas por la clave anterior se cancelan en cuanto se empieza a usar la nueva.
  • Las órdenes límite no deben sobrevivir a la sesión. Se rechaza una orden que quedaría en el libro más allá del final de la sesión: abre una sesión nueva antes de cotizar una ronda que cierra más tarde (las rondas de 1 día, por ejemplo).
  • Gratis. Seeryx paga la comisión de red y la renta de la cuenta de la transacción de sesión. Antes, tu primer depósito debe haber abierto tu cuenta (hasta entonces: 409 "Deposit first").
  • Ciérrala antes de tiempo con POST /api/relay { "action": "close_session" }: tus órdenes en el libro se cancelan y la clave deja de funcionar al instante.

Cómo abrir la sesión y firmar con ella, byte a byte: Firma de órdenes.

Cerrar sesión

  • POST /api/auth/logout invalida el token que envías; POST /api/auth/logout-all invalida todos los tokens de la cuenta.
  • Ninguno de los dos cierra la clave de la sesión de trading: ciérrala con close_session o deja que venza.
curl
curl -s -X POST https://seeryx.com/api/auth/logout-all -H "X-Auth-Token: $TOKEN"
# {"success":true}

Endpoints de inicio de sesión

Inicia sesión con una billetera de Solana: pide un mensaje, firma sus bytes exactos con la clave de la billetera e intercambia la firma por un token. No se envía nada a la cadena de bloques ni se paga ninguna comisión.

POST/api/auth/nonce

Obtener el mensaje que hay que firmar

Público
CampoTipoDescripción
addresscuerpoobligatoriostringDirección de billetera de Solana (base58)
Solicitud
curl -X POST "https://seeryx.com/api/auth/nonce" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm"}'
Respuesta
{
  "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"
}
  • El mensaje es válido durante 5 minutos y solo puede usarse una vez. Chain ID indica el clúster de Solana del servidor.
EstadoCuándo
400No es una dirección de Solana
429Más de 30 solicitudes por minuto desde tu dirección IP
POST/api/auth/verify

Intercambiar el mensaje firmado por un token

Público
CampoTipoDescripción
addresscuerpoobligatoriostringLa misma dirección de billetera
messagecuerpoobligatoriostringEl mensaje exactamente como se recibió
signaturecuerpoobligatoriostringFirma Ed25519 de los bytes del mensaje (UTF-8), en base58
Solicitud
curl -X POST "https://seeryx.com/api/auth/verify" \
  -H "Content-Type: application/json" \
  -d '{"address":"4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm","message":"...","signature":"5Kq3..."}'
Respuesta
{ "token": "eyJ0eXAiOiJKV1Qi...", "user": { "id": 3, "address": "4hfqTJ6sVSszXZGCYjXEr4YuAXz9nyLut8725NP9mVvm", "createdAt": "2026-10-13 18:29:28" } }
  • El token es válido durante 7 días. Envíalo como X-Auth-Token (o Authorization: Bearer) en cada solicitud con sesión iniciada. El primer inicio de sesión crea la cuenta.
EstadoCuándo
401"Signature verification failed" o "Invalid or expired login message"
403Esta cuenta está bloqueada
429Más de 30 solicitudes por minuto desde tu dirección IP
GET/api/auth/me

La cuenta con sesión iniciada y su efectivo

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

Invalidar este token de inicio de sesión

Con sesión iniciada
Solicitud
curl -X POST "https://seeryx.com/api/auth/logout" \
  -H "X-Auth-Token: $TOKEN"
Respuesta
{ "success": true }
  • Los demás tokens de la cuenta siguen funcionando. No cierra la clave de la sesión de trading: ciérrala con POST /api/relay close_session.
POST/api/auth/logout-all

Invalidar todos los tokens de inicio de sesión de la cuenta

Con sesión iniciada
Solicitud
curl -X POST "https://seeryx.com/api/auth/logout-all" \
  -H "X-Auth-Token: $TOKEN"
Respuesta
{ "success": true }
  • Todos los tokens creados hasta ahora dejan de funcionar, también este; vuelve a iniciar sesión para obtener uno nuevo.
POST/api/auth/username

Fijar o cambiar el nombre de usuario público

Con sesión iniciada
CampoTipoDescripción
usernamecuerpoobligatoriostringDe 2 a 20 letras, dígitos o _; único sin distinguir mayúsculas y minúsculas
Solicitud
curl -X POST "https://seeryx.com/api/auth/username" \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"satoshi_bot"}'
Respuesta
{ "success": true, "username": "satoshi_bot" }
  • El nombre aparece en la clasificación y en tu perfil público; sin él, se muestra tu billetera abreviada.