Skip to Content
API ReferenceCompetition

Competition

Competition overview, your queue standing, and (for winners) prize payout nomination. Round lifecycle is admin-operated; these routes are for integrators and the product UI.

For the product rules (League of Loaf), see Trading competition. For the ranked board, see Leaderboard.

Endpoints

MethodPathDescription
GET/api/competitionPublic competition overview
GET/api/competition/queue-positionYour queue / final placement
GET/api/competition/queue-position/cardQueue-position share card (JPEG)
GET/api/competition/payout-detailsWinner payout status
POST/api/competition/payout-detailsNominate prize destination (one-shot)

Competition overview

GET /api/competition

Public, unauthenticated. Returns every round summary, a featured round (ACTIVE → PREPARED → latest), base maker/taker fees, and the current queue size. When no rounds exist, rounds is empty and featuredRound is null.

Cached briefly for edge clients (Cache-Control: public, max-age=0, s-maxage=5).

Request

import axios from 'axios'; const response = await axios.get('https://api.loafmarkets.com/api/competition'); console.log(response.data);

Response

Type: CompetitionInfoResponse

interface CompetitionInfoResponse { rounds: CompetitionRoundSummary[]; featuredRound: CompetitionFeaturedRound | null; makerFeeBps: number; takerFeeBps: number; queueCount: number; } interface CompetitionRoundSummary { roundNumber: number; name: string; startsAt: number | null; // Unix seconds endsAt: number | null; status: CompetitionRoundStatus; totalPrizePool: number; // whole USDC participantBatchSize: number; } type CompetitionRoundStatus = | 'DRAFT' | 'PENDING' | 'PREPARED' | 'ACTIVE' | 'ENDING' | 'ENDED'; interface CompetitionFeaturedRound { roundNumber: number; name: string; rules: string; startsAt: number | null; endsAt: number | null; startingBalanceUsdl: number; status: CompetitionRoundStatus; newAssetProperty: TradePropertyItem | null; prizePool: PrizePoolEntry[]; volumeMultiplierTiers: VolumeMultiplierTier[]; bottomCullPercent: number; } interface PrizePoolEntry { place: number; // 1 = first amount: number; // whole USDC (display) } interface VolumeMultiplierTier { minVolume: number; multiplier: number; }

Errors

StatusCodeDescription
500internal_errorUnexpected server error.

Queue position

GET /api/competition/queue-position

Authenticated. Returns your standing in the admission queue or (during the break after a round) your final placement from the last ended round. The two are mutually exclusive: show finalPlacement when set, otherwise position.

The queue exists independently of a live round. When no round config is available, priorityBoostPlaces and maxBoostsPerUser fall back to server defaults.

Request

import axios from 'axios'; const response = await axios.get( 'https://api.loafmarkets.com/api/competition/queue-position', { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` } }, ); console.log(response.data);

Response

Type: QueuePositionResponse

interface QueuePositionResponse { position: number | null; queueCount: number; finalPlacement: number | null; referralCount: number; priorityBoostPlaces: number; // N in the triangular boost formula maxBoostsPerUser: number; // Z — cap on referrals that count toward boost }

Example response (queued):

{ "position": 128, "queueCount": 2400, "finalPlacement": null, "referralCount": 2, "priorityBoostPlaces": 100, "maxBoostsPerUser": 5 }

Errors

StatusCodeDescription
401unauthorizedMissing or invalid authentication.
500internal_errorUnexpected server error.

Requires API key authentication. Sensitive endpoints are also rate limited per account.


Queue-position card

GET /api/competition/queue-position/card

Authenticated. Returns a JPEG share image for your current queue position.

Response headers include Content-Type: image/jpeg and Cache-Control: private, no-store (including on auth failure).

Errors

StatusCodeDescription
401unauthorizedMissing or invalid authentication.
404not_foundYou are not currently in the competition queue.
500internal_errorUnexpected server error.

Payout details

Get payout status

GET /api/competition/payout-details

Authenticated. Read-only “have I claimed yet?” for the latest ended round. Non-winners and “no ended round” return 200 with eligible: false (not an error).

Nominate payout destination

POST /api/competition/payout-details

Authenticated. Prize winners nominate exactly one of walletAddress or email. Accepted once per round. A second submission returns 409.

Request body (POST)

Type: CompetitionPayoutDetailsRequestBody

interface CompetitionPayoutDetailsRequestBody { walletAddress?: string; email?: string; }

Provide exactly one of the two fields.

Request (GET)

import axios from 'axios'; const response = await axios.get( 'https://api.loafmarkets.com/api/competition/payout-details', { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` } }, ); console.log(response.data);

Request (POST)

import axios from 'axios'; import type { CompetitionPayoutDetailsRequestBody } from '@loafmarkets/shared-types'; const body: CompetitionPayoutDetailsRequestBody = { walletAddress: '0xabc…', }; const response = await axios.post( 'https://api.loafmarkets.com/api/competition/payout-details', body, { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` } }, ); console.log(response.data);

Response

Type: CompetitionPayoutDetailsResponse

interface CompetitionPayoutDetailsResponse { eligible: boolean; roundNumber: number | null; place: number | null; submission: CompetitionPayoutSubmission | null; } interface CompetitionPayoutSubmission { payoutType: 'WALLET' | 'EMAIL'; walletAddress: string | null; email: string | null; submittedAt: number; // Unix seconds }

submission non-null means already claimed (further POST returns 409). null means still claimable when eligible is true.

Errors

StatusCodeDescription
400validation_errorBody failed schema validation (e.g. both or neither destination).
401unauthorizedMissing or invalid authentication.
403Caller is not a prize winner for the latest ended round (POST).
409No ended round yet, or payout already submitted (POST).
503Round ended but frozen final board is missing — retry later.
500internal_errorUnexpected server error.
Last updated on