Returning.AIDevelopers
v1

API reference / Gamification / Leaderboards

.md

Create leaderboard

Create one leaderboard in the community that owns your API key, with its ranking metric, schedule, audience and prizes.

Last updated 26 Sep 2026API v1

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#

Authorization#stringREQUIRED
Community API key with leaderboard.

RuleBearer <API_KEY>

Content-Type#stringREQUIRED
Request body format.

Ruleapplication/json

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.

name#stringREQUIRED
Leaderboard name shown to traders. Must be unique in your community.

Rule1-100 chars

Eg"Monthly Trading Volume"

slug#stringREQUIRED
URL-friendly ID. Must be unique in your community.

Rule1-100 chars; lowercase letters, numbers and single hyphens

Eg"monthly-trading-volume"

description#stringOPTIONAL
Description shown to traders. Defaults to empty.

RuleMax 2000 chars

Eg"Top traders by trading volume each month."

image#stringOPTIONAL
Leaderboard image URL.

Rulehttp or https URL

Eg"https://cdn.example.com/leaderboards/monthly-volume.png"

rankingField#stringONE OF
What traders are ranked by: 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"

displayedColumns#arrayONE OF
Columns in the leaderboard table, in order. Send names, or objects to hide a column. 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"]

column#stringREQUIRED
Column name.

Rule1-100 chars

Eg"tier"

order#integerREQUIRED
Position, starting at 0.

RuleMin 0

Eg0

visible#booleanREQUIRED
false keeps the column out of the table.

Egtrue

startDate#stringONE OF
First day of the leaderboard. It starts at startTime on this date, in timeZone.

RuleISO 8601 or DD-MM-YYYY; send this or duration.start

Eg"2026-10-01T00:00:00.000Z"

endDate#stringOPTIONAL
Last day of the leaderboard. It ends at endTime on this date. Omit it for an open-ended leaderboard.

RuleISO 8601, DD-MM-YYYY or null

Egnull

hasNoEndDate#booleanOPTIONAL
true when the leaderboard has no end date. Defaults to false.

Egtrue

timeZone#numberOPTIONAL
Time zone for the start, end and resets, as minutes from UTC. Defaults to 0 (UTC).

RuleMinutes, e.g. 480 for UTC+8

Eg0

startTime#objectOPTIONAL
Time of day the leaderboard and each reset period start, as hours (1-12), minutes (0-59) and ampm. Defaults to 12:00 AM.
endTime#objectOPTIONAL
Time of day the leaderboard ends on endDate, in the same format. Defaults to 11:59 PM.
allowedTimeFilters#string[]OPTIONAL
Period tabs traders can switch between: all-time, daily, weekly, monthly, yearly. Defaults to none.

Eg["monthly", "all-time"]

allowedRolesToRank#string[]ONE OF
Roles whose traders get ranked, by name or ID. @all covers every trader in your community.

RuleAt least one rank list must have an entry

Eg["@all"]

allowedUsersToRank#string[]ONE OF
Traders to rank one by one, by platform user ID, username or email. Each must be a member of your community.

RuleAt least one rank list must have an entry

Eg["3247779"]

allowedTagsToRank#string[]ONE OF
Tags whose traders get ranked, by name or ID.

RuleAt least one rank list must have an entry

Eg[]

allowedRolesToView#string[]ONE OF
Roles whose traders can see the leaderboard, by name or ID. @all covers every trader. Traders on a rank list can always see it.

RuleAt least one view list must have an entry

Eg["@all"]

allowedUsersToView#string[]ONE OF
Traders who can see the leaderboard, by platform user ID, username or email.

RuleAt least one view list must have an entry

Eg[]

allowedTagsToView#string[]ONE OF
Tags whose traders can see the leaderboard, by name or ID.

RuleAt least one view list must have an entry

Eg[]

isEnabled#booleanONE OF
true makes the leaderboard live at once for the traders who can see it.

RuleSend this or enabled

Egtrue

displayOrder#integerOPTIONAL
Position among your leaderboards, starting at 1. Omit it or send 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

enableLeaderboardReset#booleanOPTIONAL
true restarts scores every period and keeps each finished period as history.

Egtrue

leaderboardResetFrequency#stringOPTIONAL
How often scores restart. Required when enableLeaderboardReset is true.

Ruledaily, weekly, monthly, yearly

Eg"monthly"

enablePrizePool#booleanOPTIONAL
true pays the prizes rows to the winners when a period ends.

Egfalse

prizes#object[]OPTIONAL
Prize rows by rank. Used only when enablePrizePool is true.

Eg[]

isRange#booleanREQUIRED
true for a range of ranks (positionFrom to positionTo), false for one rank (position).
position#numberOPTIONAL
The rank that wins, when isRange is false.
positionFrom#numberOPTIONAL
First rank in the range, when isRange is true.
positionTo#numberOPTIONAL
Last rank in the range, when isRange is true.
prizeName#stringREQUIRED
Prize name shown to traders.
useRewardAsPrizeName#booleanREQUIRED
true shows the coin or XP amount as the prize name.
coins#numberREQUIRED
Coins credited to each winning trader. Send 0 for none.
xp#numberREQUIRED
XP credited to each winning trader. Send 0 for none.
customFields#object[]REQUIRED
Details the winner fills in to claim the prize. Send [] for none. A required field holds back the coins and XP until the trader claims.
topRankOnly#booleanOPTIONAL
true blurs rows below the top topRankLimit ranks. Each trader still sees their own row.

Egfalse

topRankLimit#numberOPTIONAL
How many top ranks stay visible. Must be 1 or more when topRankOnly is true.

RuleWhole number, 1 or more when topRankOnly is true

Eg10

onlyPositiveRanks#booleanOPTIONAL
true shows only traders with a score above 0.

Egtrue

includeDummyUsers#booleanOPTIONAL
Older setting for filling the table with placeholder traders. Leave it out.

Egfalse

isPreviewEnabled#booleanOPTIONAL
true lets guests see the leaderboard, if your community allows guest preview. Defaults to false.

Egfalse

widget#objectOPTIONAL
Embeddable widget settings. Most integrations leave this out.
banner#objectOPTIONAL
Banner settings. Most integrations leave this out.
translations#objectOPTIONAL
Translated names and descriptions, as name and description lists of languageCode and translation.
userInformationDisplay#object[]OPTIONAL
How much of each trader's details the table shows, per field, as full or partial.
leaderboardPageConfig#objectOPTIONAL
Leaderboard page layout settings. Most integrations leave this out.
leaderImage#stringOPTIONAL
Alias for image. image wins if you send both.

RuleUp to 2,000 chars

Eg"https://cdn.example.com/leaderboards/monthly-volume.png"

rankBy#stringOPTIONAL
Alias for rankingField. rankingField wins if you send both.

Rule1-100 chars; ^[a-zA-Z0-9_-]+$

Eg"tradingvolume"

displayedFields#string[]OPTIONAL
Visible columns. Alias for displayedColumns; send it with displayFieldsOrder.

RuleMax 50 items

Eg["user", "tier", "level"]

displayFieldsOrder#string[]OPTIONAL
Column order. Alias for displayedColumns; send it with displayedFields.

RuleMax 50 items

Eg["user", "tier", "level"]

timeFilters#string[]OPTIONAL
Alias for allowedTimeFilters. allowedTimeFilters wins if you send both.

Eg["monthly", "all-time"]

duration#objectOPTIONAL
The schedule as one object. Alias for startDate, endDate, hasNoEndDate, timeZone, startTime and endTime, which win if you send them.
start#stringREQUIRED
First day of the leaderboard.

Eg"2026-10-01T00:00:00.000Z"

end#stringOPTIONAL
Last day, or null.

RuleNullable

Egnull

noEndDate#booleanREQUIRED
true when there is no end date.

Egtrue

timeZone#numberREQUIRED
Minutes from UTC.

Eg0

startTime#objectOPTIONAL
Start time of day.
hours#numberOPTIONAL
Hour, 1-12.

Rule1-12

Eg12

minutes#numberOPTIONAL
Minute, 0-59.

Rule0-59

Eg0

ampm#stringOPTIONAL
AM or PM.

RuleAM, PM

Eg"AM"

endTime#objectOPTIONAL
End time of day.
hours#numberOPTIONAL
Hour, 1-12.

Rule1-12

Eg11

minutes#numberOPTIONAL
Minute, 0-59.

Rule0-59

Eg59

ampm#stringOPTIONAL
AM or PM.

RuleAM, PM

Eg"PM"

rankedUserRoles#objectOPTIONAL
The rank lists as one object. Alias for the allowed...ToRank fields, which win if you send them.
users#arrayOPTIONAL
Traders, by platform user ID, username or email.

Eg[]

roles#arrayOPTIONAL
Roles, by name or ID.

Eg["@all"]

tags#arrayOPTIONAL
Tags, by name or ID.

Eg[]

viewPermissionUserRoles#objectOPTIONAL
The view lists as one object. Alias for the allowed...ToView fields, which win if you send them.
users#arrayOPTIONAL
Traders, by platform user ID, username or email.

Eg[]

roles#arrayOPTIONAL
Roles, by name or ID.

Eg["@all"]

tags#arrayOPTIONAL
Tags, by name or ID.

Eg[]

performanceDisplay#objectOPTIONAL
Table display options as one object. Alias for topRankOnly, topRankLimit, onlyPositiveRanks and includeDummyUsers, which win if you send them.
showTop#objectREQUIRED
Same as topRankOnly (enabled) and topRankLimit (value).
enabled#booleanREQUIRED
Same as topRankOnly.

Egfalse

value#numberOPTIONAL
Same as topRankLimit. 1 or more when enabled is true.

Rule1 or more when enabled is true

Eg0

showPositive#objectREQUIRED
Same as onlyPositiveRanks.
enabled#booleanREQUIRED
Same as onlyPositiveRanks.

Egtrue

showDummy#objectREQUIRED
Same as includeDummyUsers.
enabled#booleanREQUIRED
Same as includeDummyUsers.

Egfalse

enabled#booleanOPTIONAL
Alias for isEnabled. isEnabled wins if you send both.

Egtrue

previewEnabled#booleanOPTIONAL
Alias for isPreviewEnabled. isPreviewEnabled wins if you send both.

Egfalse

order#integerOPTIONAL
Alias for 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#objectALWAYS
Status of the request. There is no meta.code on success.

Eg{"status": "success", "statusCode": 201}

status#stringALWAYS
Result of the request.

Rulesuccess

statusCode#integerALWAYS
The HTTP status, repeated.

Eg201

message#stringALWAYS
Human-readable summary. Do not branch on it.

Eg"Create leaderboard success."

data#objectALWAYS
The new leaderboard.

Eg{ ... }

_id#string
Leaderboard ID. Save it to read, update or delete the leaderboard.

Eg"66f000000000000000000301"

communityID#string
Your community ID.

Eg"66f000000000000000000010"

kind#string
custom for a leaderboard you create.
name#string
The stored name.

Eg"Monthly Trading Volume"

slug#string
The stored slug.

Eg"monthly-trading-volume"

description#string
The stored description.

Eg"Top traders by trading volume each month."

rankBy#string
What traders are ranked by.

Eg"tradingvolume"

displayedFields#string[]
Visible columns. user comes first.

Eg["user", "tier", "level"]

displayFieldsOrder#string[]
Column order.

Eg["user", "tier", "level"]

timeFilters#string[]
Period tabs.

Eg["monthly", "all-time"]

performanceDisplay#object
Table display options, with defaults filled in.

Eg{ ... }

duration#object
The schedule, with defaults filled in. timeZone is minutes from UTC.

Eg{ ... }

rankedUserRoles#object
Rank lists, expanded: traders as id (numeric platform user ID), _id, username and email; roles and tags as _id and name.

Eg{ ... }

viewPermissionUserRoles#object
View lists, in the same shape.

Eg{ ... }

banner#object
Banner settings.

Eg{}

enableLeaderboardReset#boolean
true when scores restart every period.

Egtrue

leaderboardResetFrequency#string
How often scores restart.

Eg"monthly"

enablePrizePool#boolean
true when prizes are paid.

Egfalse

prizes#object[]
Prize rows.

Eg[]

userInformationDisplay#object[]
Trader detail display settings.

Eg[]

enabled#boolean
true when the leaderboard is live.

Egtrue

previewEnabled#boolean
true when guests can see it.

Egfalse

selected#boolean
false. A new leaderboard is not your community's active leaderboard.

Egfalse

displayOrder#integer
Position among your leaderboards.

Eg2

order#integer
Same value as displayOrder.

Eg2

updatedAt#string
When the leaderboard last changed, ISO 8601 UTC.

RuleDate-time

Eg"2026-09-26T08:30:00.000Z"

createdAt#string
When the leaderboard was created, ISO 8601 UTC.

RuleDate-time

Eg"2026-09-26T08:30:00.000Z"

image#string
Leaderboard image URL, when you sent one.
widget#object
Widget settings, when you sent them.
translations#object
Translations, when you sent them.
leaderboardPageConfig#object
Page layout settings, when you sent them.
{
  "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

400Fix the request
A required field is missing, a date is invalid, a user, role or tag isn't in your community, or 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.
400VALIDATION_FAILEDFix the request
A field breaks a format rule, such as a slug with capitals or spaces, a rankingField with spaces, or topRankOnly without a topRankLimit of 1 or more. detail names the field. Nothing was created.
401AUTH_API_KEY_REQUIREDFix the request
No key was sent. Send Authorization: Bearer <API_KEY>.
401AUTH_API_KEY_INVALIDFix the request
The key is unknown, expired or malformed. Use a current Community API key.
403AUTH_PERMISSION_REQUIREDFix the request
The key lacks leaderboard. Add the permission in Settings > Integration > API Keys.

Fix the data01

409Fix the data
Another leaderboard in your community already has this name or slug; 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

500Retry with backoff
The outcome is unknown. List leaderboards with search=slug:<slug> and create again only if it isn't there.
502Retry with backoff
The outcome is unknown. List leaderboards with search=slug:<slug> and create again only if it isn't there.
401AUTH_API_KEY_VALIDATION_FAILEDRetry with backoff
The key could not be checked just now, and nothing was created. Retry 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"
}

Next step#

Update a user field valuePOST/v1/communities/{communityId}/users/{userId}/user-fields/{fieldIdOrName}/historiesWrite each trader's numbers to the user field the leaderboard ranks by.