Create leaderboard
Create one leaderboard in the community that owns your API key, with its ranking metric, schedule, audience and prizes.
- Method
- POST
- Path
https://api.returning.ai / v1/ leaderboards - Permission
- leaderboard
- Retries
- No Idempotency-Key; list by slug before retrying
When to use this
- Launch a monthly trading competition ranked by a user field your integration writes, such as trading volume.
- Run a time-boxed campaign that pays coins or XP to the top traders when it ends.
- Set up a leaderboard that only traders with a given role can see or be ranked on.
Authentication#
- Header
Authorization: Bearer <API_KEY>- Permission
- leaderboardShown in the dashboard as “Leaderboard”
Send a Community API key with the leaderboard permission. The key decides the community, so never send a community ID.
Behaviour#
The leaderboard is saved at once, after the last of your leaderboards unless you send displayOrder. With isEnabled: true it is live straight away for the traders on its view lists. Before the start date it shows as not started, and after the end date its ranks are frozen.
Scores: XP and Coins add up what each trader earns in the period, Referrals counts referrals completed in the period, and a user-field key adds up the numbers written to that field in the period, starting again from the last overwrite. Traders with a score of 0 are not ranked. Ranks are first calculated from the start date when the leaderboard has a reset or an end date, otherwise when someone first opens it, and then refresh about every hour.
Resets and prizes: with enableLeaderboardReset, scores restart every day, week, month or year at startTime in the leaderboard's time zone, and the finished period is kept as history. With enablePrizePool, each prize row's coins and xp are credited to the winners automatically when a period ends or the leaderboard reaches its end date. A leaderboard with no end date and no reset never pays prizes.
Request#
Headers#
Body#
Required: name, slug, rankingField, displayedColumns, startDate, isEnabled, at least one entry in a rank list (allowedRolesToRank, allowedUsersToRank, allowedTagsToRank) and at least one entry in a view list (allowedRolesToView, allowedUsersToView, allowedTagsToView). Several fields have an older alias, such as rankBy for rankingField; send one of each pair. Fields the endpoint does not recognise are ignored, so check spelling. Metrics whose names contain spaces, such as messages sent, can't be set through the API.
Rule1-100 chars
Eg"Monthly Trading Volume"
Rule1-100 chars; lowercase letters, numbers and single hyphens
Eg"monthly-trading-volume"
RuleMax 2000 chars
Eg"Top traders by trading volume each month."
Rulehttp or https URL
Eg"https://cdn.example.com/leaderboards/monthly-volume.png"
XP or Coins earned in the period, Referrals completed in the period, or the key of a Numerical user field, whose values written in the period are added up from the last overwrite. Other values, such as currencies, are read as a user-field key.RuleXP, Coins, Referrals or a user-field key; send this or rankBy
Eg"tradingvolume"
user is always added as the first column. Common columns: tier, level, xp, coins, badges.RuleUp to 50; send this or displayedFields with displayFieldsOrder
Eg["user", "tier", "level"]
Rule1-100 chars
Eg"tier"
RuleMin 0
Eg0
false keeps the column out of the table.Egtrue
startTime on this date, in timeZone.RuleISO 8601 or DD-MM-YYYY; send this or duration.start
Eg"2026-10-01T00:00:00.000Z"
endTime on this date. Omit it for an open-ended leaderboard.RuleISO 8601, DD-MM-YYYY or null
Egnull
true when the leaderboard has no end date. Defaults to false.Egtrue
0 (UTC).RuleMinutes, e.g. 480 for UTC+8
Eg0
hours (1-12), minutes (0-59) and ampm. Defaults to 12:00 AM.endDate, in the same format. Defaults to 11:59 PM.all-time, daily, weekly, monthly, yearly. Defaults to none.Eg["monthly", "all-time"]
@all covers every trader in your community.RuleAt least one rank list must have an entry
Eg["@all"]
RuleAt least one rank list must have an entry
Eg["3247779"]
RuleAt least one rank list must have an entry
Eg[]
@all covers every trader. Traders on a rank list can always see it.RuleAt least one view list must have an entry
Eg["@all"]
RuleAt least one view list must have an entry
Eg[]
RuleAt least one view list must have an entry
Eg[]
true makes the leaderboard live at once for the traders who can see it.RuleSend this or enabled
Egtrue
0 to add it last; a positive value inserts it there and moves the others down, and a value past the end adds it last.RuleWhole number, 0 or more
Eg0
true restarts scores every period and keeps each finished period as history.Egtrue
enableLeaderboardReset is true.Ruledaily, weekly, monthly, yearly
Eg"monthly"
true pays the prizes rows to the winners when a period ends.Egfalse
enablePrizePool is true.Eg[]
true for a range of ranks (positionFrom to positionTo), false for one rank (position).isRange is false.isRange is true.isRange is true.true shows the coin or XP amount as the prize name.0 for none.0 for none.[] for none. A required field holds back the coins and XP until the trader claims.true blurs rows below the top topRankLimit ranks. Each trader still sees their own row.Egfalse
topRankOnly is true.RuleWhole number, 1 or more when topRankOnly is true
Eg10
true shows only traders with a score above 0.Egtrue
Egfalse
true lets guests see the leaderboard, if your community allows guest preview. Defaults to false.Egfalse
name and description lists of languageCode and translation.full or partial.image. image wins if you send both.RuleUp to 2,000 chars
Eg"https://cdn.example.com/leaderboards/monthly-volume.png"
rankingField. rankingField wins if you send both.Rule1-100 chars; ^[a-zA-Z0-9_-]+$
Eg"tradingvolume"
displayedColumns; send it with displayFieldsOrder.RuleMax 50 items
Eg["user", "tier", "level"]
displayedColumns; send it with displayedFields.RuleMax 50 items
Eg["user", "tier", "level"]
allowedTimeFilters. allowedTimeFilters wins if you send both.Eg["monthly", "all-time"]
startDate, endDate, hasNoEndDate, timeZone, startTime and endTime, which win if you send them.Eg"2026-10-01T00:00:00.000Z"
null.RuleNullable
Egnull
true when there is no end date.Egtrue
Eg0
Rule1-12
Eg12
Rule0-59
Eg0
AM or PM.RuleAM, PM
Eg"AM"
Rule1-12
Eg11
Rule0-59
Eg59
AM or PM.RuleAM, PM
Eg"PM"
allowed...ToRank fields, which win if you send them.Eg[]
Eg["@all"]
Eg[]
allowed...ToView fields, which win if you send them.Eg[]
Eg["@all"]
Eg[]
topRankOnly, topRankLimit, onlyPositiveRanks and includeDummyUsers, which win if you send them.topRankOnly (enabled) and topRankLimit (value).topRankOnly.Egfalse
topRankLimit. 1 or more when enabled is true.Rule1 or more when enabled is true
Eg0
onlyPositiveRanks.onlyPositiveRanks.Egtrue
includeDummyUsers.includeDummyUsers.Egfalse
isEnabled. isEnabled wins if you send both.Egtrue
isPreviewEnabled. isPreviewEnabled wins if you send both.Egfalse
displayOrder. order wins if you send both.RuleMin 0
Eg0
curl --request POST \
--url https://api.returning.ai/v1/leaderboards \
--header 'Authorization: Bearer <API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"name": "Monthly Trading Volume",
"slug": "monthly-trading-volume",
"description": "Top traders by trading volume each month.",
"rankingField": "tradingvolume",
"displayedColumns": ["user", "tier", "level"],
"startDate": "2026-10-01T00:00:00.000Z",
"hasNoEndDate": true,
"timeZone": 0,
"allowedTimeFilters": ["monthly", "all-time"],
"allowedRolesToRank": ["@all"],
"allowedRolesToView": ["@all"],
"enableLeaderboardReset": true,
"leaderboardResetFrequency": "monthly",
"isEnabled": true
}'
Response#
A 201 returns the stored leaderboard in data, with defaults filled in and user, role and tag references expanded. Save data._id. Branch on the HTTP status.
meta.code on success.Eg{"status": "success", "statusCode": 201}
Rulesuccess
Eg201
Eg"Create leaderboard success."
Eg{ ... }
Eg"66f000000000000000000301"
Eg"66f000000000000000000010"
custom for a leaderboard you create.Eg"Monthly Trading Volume"
Eg"monthly-trading-volume"
Eg"Top traders by trading volume each month."
Eg"tradingvolume"
user comes first.Eg["user", "tier", "level"]
Eg["user", "tier", "level"]
Eg["monthly", "all-time"]
Eg{ ... }
timeZone is minutes from UTC.Eg{ ... }
id (numeric platform user ID), _id, username and email; roles and tags as _id and name.Eg{ ... }
Eg{ ... }
Eg{}
true when scores restart every period.Egtrue
Eg"monthly"
true when prizes are paid.Egfalse
Eg[]
Eg[]
true when the leaderboard is live.Egtrue
true when guests can see it.Egfalse
false. A new leaderboard is not your community's active leaderboard.Egfalse
Eg2
displayOrder.Eg2
RuleDate-time
Eg"2026-09-26T08:30:00.000Z"
RuleDate-time
Eg"2026-09-26T08:30:00.000Z"
{
"meta": {
"status": "success",
"statusCode": 201
},
"message": "Create leaderboard success.",
"data": {
"_id": "66f000000000000000000301",
"communityID": "66f000000000000000000010",
"kind": "custom",
"name": "Monthly Trading Volume",
"slug": "monthly-trading-volume",
"description": "Top traders by trading volume each month.",
"rankBy": "tradingvolume",
"displayedFields": ["user", "tier", "level"],
"displayFieldsOrder": ["user", "tier", "level"],
"timeFilters": ["monthly", "all-time"],
"performanceDisplay": {
"showTop": {
"enabled": false,
"value": 0
},
"showPositive": {
"enabled": false
},
"showDummy": {
"enabled": false
}
},
"duration": {
"start": "2026-10-01T00:00:00.000Z",
"end": null,
"noEndDate": true,
"timeZone": 0,
"startTime": {
"hours": 12,
"minutes": 0,
"ampm": "AM"
},
"endTime": {
"hours": 11,
"minutes": 59,
"ampm": "PM"
}
},
"rankedUserRoles": {
"users": [],
"roles": [
{
"_id": "66f000000000000000000502",
"name": "@all"
}
],
"tags": []
},
"viewPermissionUserRoles": {
"users": [],
"roles": [
{
"_id": "66f000000000000000000502",
"name": "@all"
}
],
"tags": []
},
"banner": {},
"enableLeaderboardReset": true,
"leaderboardResetFrequency": "monthly",
"enablePrizePool": false,
"prizes": [],
"userInformationDisplay": [],
"enabled": true,
"previewEnabled": false,
"selected": false,
"displayOrder": 2,
"order": 2,
"updatedAt": "2026-09-26T08:30:00.000Z",
"createdAt": "2026-09-26T08:30:00.000Z"
}
}
Errors#
401, 403 and 400 VALIDATION_FAILED errors carry a code in meta.code. Other errors from this endpoint have no code; branch on the HTTP status and read detail.
Fix the request05
rankingField names no field. There is no meta.code; detail says which, such as startDate is required., rankedUserRoles.roles[0] could not be resolved for this community. or Invalid rankBy value: .... Nothing was created.VALIDATION_FAILEDFix the requestrankingField with spaces, or topRankOnly without a topRankLimit of 1 or more. detail names the field. Nothing was created.AUTH_API_KEY_REQUIREDFix the requestAuthorization: Bearer <API_KEY>.AUTH_API_KEY_INVALIDFix the requestAUTH_PERMISSION_REQUIREDFix the requestleaderboard. Add the permission in Settings > Integration > API Keys.Fix the data01
detail says which (Custom leaderboard name is already exists! or Leaderboard slug already exists: <slug>). Choose another, or use the existing leaderboard.Retry with backoff03
search=slug:<slug> and create again only if it isn't there.search=slug:<slug> and create again only if it isn't there.AUTH_API_KEY_VALIDATION_FAILEDRetry with backoff{
"meta": {
"status": "error",
"statusCode": 400,
"code": "VALIDATION_FAILED"
},
"message": "Validation failed",
"detail": {
"slug": "slug must contain only lowercase letters, numbers, and hyphens"
},
"solution": "Please check the request and try again"
}