Sign in with a wallet signature
const url = 'https://foxleague.ai/api/auth/verify';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"address":"example","provider":"example","signature":"example","timestamp":1}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://foxleague.ai/api/auth/verify \ --header 'Content-Type: application/json' \ --data '{ "address": "example", "provider": "example", "signature": "example", "timestamp": 1 }'Checks a wallet signature and answers a new session token. Sign the text foxleague:chain=1:auth-<timestamp> on mainnet with the wallet’s MultiversX message signer, where <timestamp> is the current Unix time in seconds. Send the same timestamp, the address and the 128 hexadecimal character signature.
The timestamp must be within 300 seconds of the server’s clock, in either direction. A signature works once: sign a new message for every login. The first successful login of a wallet creates its account; a team comes later with POST /api/register. A session lasts 24 hours by default and cannot be renewed: sign in again when a call answers 401.
Who: anyone.
Refusals:
Invalid wallet address: it is not a valid erd1 address.:addressis not a valid MultiversX wallet address.Auth token expired:timestampis more than 300 seconds away from the server’s clock.Signature verification failed: the signature does not match the message and the address.signature_replayed: this signature was already used for a login.Failed to create session: the session could not be stored. Try again.Too many failed sign-in attempts. Try again in <minutes> <unit>.(HTTP 429, with aRetry-Afterheader): too many sign-ins that did not get in. Failed signatures and replayed copies of a used one both count, per client (an IPv6 client counts as its /64) and per wallet: 10 within 60 seconds lock that client or that wallet for 5 minutes by default. The lock is a fixed wait and further attempts do not extend it. A new signature of a fresh message still signs in during a lock.
Request Body required
Section titled “Request Body required ”A signed login message.
object
Your wallet address (erd1...).
Optional wallet type the app reports, such as extension or walletConnect. It does not change the answer.
The signature of the message, 128 hexadecimal characters.
The Unix time in seconds that the signed message carries.
Example generated
{ "address": "example", "provider": "example", "signature": "example", "timestamp": 1}Responses
Section titled “ Responses ”Success or a refusal: read success (the refusals are in the description).
object
A machine-readable reason next to error, set only where the caller must act differently. tx_pending: the payment was not refused but could not be verified yet; keep the transaction hash and confirm again with the same hash, never pay twice.
The answer. Present when success is true.
object
The session token. Send it as Authorization: Bearer <token>.
Why the request was refused, in plain words. Present when success is false.
true when the request did what it asked. false is a refusal: read error.
Example
{ "data": { "token": "7eb86c57-a811-4a01-9ea3-30a1a66d58b5" }, "success": true}Too many failed or replayed sign-ins from this client or for this wallet (10 within 60 seconds by default). The answer carries Retry-After and the usual JSON refusal Too many failed sign-in attempts. Try again in <minutes> <unit>.. A new signature of a fresh message still signs in.
object
A machine-readable reason next to error, set only where the caller must act differently. tx_pending: the payment was not refused but could not be verified yet; keep the transaction hash and confirm again with the same hash, never pay twice.
The answer. Present when success is true.
object
The session token. Send it as Authorization: Bearer <token>.
Why the request was refused, in plain words. Present when success is false.
true when the request did what it asked. false is a refusal: read error.
Example generated
{ "code": "example", "data": { "token": "example" }, "error": "example", "success": true}