# Members (/docs/concepts/participants)



A member is one person in your community program. Domino keeps everything they do with you in one place: the quests they finish, their points, their rewards, and the accounts they've proved are theirs, such as their X handle, their Discord account, or their wallet.

* A member who signs in with X can earn points for posting about you.
* A member who links their wallet can take part in a holders-only quest.
* A member you bring over from another platform keeps the points they had there.

A member belongs to one project. Someone who joins two of your projects, even in the same organization, is a separate member in each, with their own accounts and progress. Test and live members are separate too.

```mermaid
flowchart LR
    Identity["Proved accounts"] -->|sign in, match activity| P[Member]
    Login["Your app's own login"] --> P
    P --> Progress["Quest progress"]
    P --> Earned["Points and rewards"]
```

> [!DEV]
> A hosted app's address decides the environment: sign-in on staging and previews uses test, and on the live app, at `<project-slug>.domino.page` or its [custom domain](/docs/concepts/hosting#custom-domains), live. A session belongs to the address it was made on, so a member signed in at one address of the live app signs in again at another.

## Verified identities [#verified-identities]

Members prove which accounts are theirs: an email address, an X, Discord, Google or Apple account, a Telegram account, or a wallet. Domino signs members in with them, and quests only credit a member's X, Discord, Telegram and wallet activity through accounts they proved. A name, a handle or a profile picture is never enough.

| Account                                                | Proved by                                                                                             | Signs in                                                                                                                                                       | Quests and trackers use it to                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Email address                                          | A one-time code sent to it                                                                            | Yes, with Domino sign-in                                                                                                                                       | —                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| X, Discord, Google, Apple                              | Signing in with the provider                                                                          | Yes, for the providers Domino configures                                                                                                                       | Read the member's X or Discord account in a quest, and match [tracker](/docs/concepts/trackers) records by stable X or Discord user ID                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| Telegram account                                       | Telegram Login, or Telegram's signature on your Mini App's launch data                                | Yes, with Telegram Login where Domino configures it, and in your [Mini App](/docs/build/telegram#sign-in-inside-your-mini-app) where the project names its bot | Check membership in the project's connected [Telegram chats](/docs/build/telegram#check-membership-in-a-quest), and match reaction records by Telegram user ID                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| YouTube channel ([creator account](#creator-accounts)) | Linking it while signed in, on Google's consent screen                                                | No                                                                                                                                                             | Match [YouTube Shorts](/docs/build/trackers#reward-youtube-shorts) to the member who linked the channel                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| TikTok account ([creator account](#creator-accounts))  | Linking it while signed in, on TikTok's consent screen                                                | No                                                                                                                                                             | Match [TikTok videos](/docs/build/trackers#reward-tiktok-videos) to the member who linked the account                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| Wallet: Solana, EVM, Cosmos SDK                        | Signing a one-time message in the wallet                                                              | A wallet first used to sign in, where the project enables its chain family; a wallet linked while signed in only once an operator enables sign-in for it       | Check which wallets the member controls, the token balances they hold and, on EVM chains and Solana, how many NFTs of a collection they hold ([Wallets](/docs/build/wallets#check-nft-holdings)), and what they stake in a contract or delegate on a Cosmos SDK chain ([Wallets](/docs/build/wallets#check-staking-and-contract-state)), all at verification time, which events of an EVM contract name their wallets ([on-chain actions](/docs/build/wallets#check-on-chain-actions)) and which of their Solana transactions called a program ([on Solana](/docs/build/wallets#check-on-chain-actions-on-solana)), and match tracker records by CAIP-10 account ID |
| Your app's user ID (`app:<name>`)                      | Your app server, when it signs the user in through an app login integration that has an identity kind | Yes, through your app                                                                                                                                          | Match [tracker](/docs/concepts/trackers) records by your app's user ID, and list it with the member's other identities in a quest                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

> [!DEV] Every sign-in provider in one list
> SDK 1.x keeps `AuthProvider`, and the lists typed with it, to Google, Apple, X and Discord. `relay.auth.providers().signInProviders`, `relay.auth.signInAccounts()` and `useAccount(provider)` list every sign-in provider, Telegram included, with an open `provider` a newer Domino may extend; `relay.auth.start({ provider, mode })` and `relay.auth.disconnect(provider)` take any of them. Operators read and unlink a member's X, Discord and Telegram accounts the same way with `management.members.accounts(member)` and `unlinkAccount`.

A few paths take your organization's word instead of the member's proof:

* **Imported members.** A [member import](#imported-members) attaches the X, Telegram and Discord accounts and wallets you vouch for.
* **Accounts your app vouches for.** With an [existing app login](#sign-in), your server can attach those accounts each time it signs a member in, once an admin with **Publish** permission [allows it](/docs/build/app-login#vouch-for-your-members-accounts) for the key.
* **Your own login.** With an [existing app login](#sign-in), your app server vouches for its user. It also links that user as an `app:<name>` identity when the integration has an [identity kind](/docs/build/app-login#link-your-apps-user-ids).
* **Your server's records.** A [custom tracker](/docs/build/trackers) record that names a Domino member ID is taken on the word of the server that sends it.
* **Test members.** In test, an operator can give a [test member](#test-members) wallets and X or Discord accounts.

### Sign-in [#sign-in]

Your app signs members in one of two ways. See [app login](/docs/build/app-login).

| Sign-in            | How it works                                                                                                                                                                                                            |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Domino sign-in     | Members sign in with the X, Discord, Google or Apple accounts, Telegram Login and email code Domino configures, and with a wallet or inside a [Telegram Mini App](/docs/build/telegram) where the project enables them. |
| Existing app login | Your app keeps its own login. Your server checks the user's session and exchanges their stable user ID for a Domino member session.                                                                                     |

When a member first signs in with an email code, Domino reuses the member of an OAuth account with the same verified email, provided that account is enabled for sign-in. Accounts connected only to check activity can't link the two. If several members match, email sign-in stops instead of choosing one. An existing email identity keeps its current member; this does not repair accounts already split.

Domino recovers older Google and Apple sign-in profiles before matching a new email identity. If an older sign-in grant cannot be recovered, the attempt stops: the member signs in with their original method to refresh the account, or contacts you. Existing email identities can still sign in.

> [!DEV]
> A signed-in member reads their own email addresses with `relay.me.get()`, or `useMe()` in React. `emails` lists the verified addresses that sign them in: each email-code address, then the verified email of each Google or Apple account enabled for sign-in. `email` is the first of them, for showing who is signed in. Accounts connected only for activity verification are not listed. A member who signs in only with a wallet, X, Discord, Telegram or your app's own login has none: `email` is null and `emails` is empty. Participant routes never return another member's email.

### Connected accounts [#connected-accounts]

A signed-in member adds accounts by connecting them, so Domino can check their activity with a provider such as Discord. Connecting a member's Discord account and connecting your Discord server to the project are separate steps:

|            | Connected account                    | Project integration                               |
| ---------- | ------------------------------------ | ------------------------------------------------- |
| Belongs to | The member                           | The project                                       |
| Purpose    | Identifies the member                | Gives the project access to its configured server |
| Discord    | Linking the member's Discord account | Connecting the project's Discord server           |

Rewarding Discord messages and reactions needs both. An organization administrator installs Domino's bot into a server once, or [sends a one-time link](/docs/build/integrations#send-the-install-to-your-server-admin) to whoever manages the server; other projects of the organization then connect the same server without installing it again. The integration names the server Domino listens to, and Domino keeps a message or reaction only when its Discord account is linked to a member of the project. Activity from before the link is not kept. See [Discord messages and reactions](/docs/build/trackers#reward-discord-messages-and-reactions) and [project integrations](/docs/build/integrations).

A quest's [announcements](/docs/concepts/quests#announcements) mention the member through the Telegram or Discord account they connected, with their Telegram @username when their sign-in profile has one. A member who connected none there is named by their display name instead. A test-linked account is someone else's, so announcements never mention it.

Quests that need Discord fail while the project's integration is missing or needs attention, whatever the member linked. Once it's ready again, Domino retries the failed attempts of automatic quests without a tracker on its own. See [recover a configuration failure](/docs/build/integrations#recover-a-configuration-failure).

### Accounts Domino reads in the background [#accounts-domino-reads-in-the-background]

Some providers let Domino keep reading a member's own account after they link it, with their permission, for example to follow their posts. Linking such an account also asks for the permissions those reads need. If the member later revokes access, or the access lapses, the account needs reconnecting: Console shows **Needs reconnect** and the reason on the member, and the member fixes it by linking the same account again. A temporary provider outage doesn't count; Domino just tries again later.

> [!DEV]
> Domino keeps the account's OAuth tokens, encrypted, while the account stays linked, and refreshes them before they expire. Only the background reads open them; account reads, management reads and audit events never include them. Unlinking the account, resetting a test member, or purging a deleted project deletes the tokens and asks the provider to revoke them. YouTube channels and TikTok accounts are the exception: Google or TikTok would revoke every link of that account to Domino, in every project, so Domino only deletes the tokens, and the member can remove Domino's access in their Google account or TikTok settings.
>
> | Reason | When |
> | --- | --- |
> | `revoked` | The provider refused the refresh: the member revoked Domino's access, or the provider ended it |
> | `expired` | The tokens expired and the provider gave nothing to refresh them with |
> | `missing-scope` | A source needs a permission the member did not grant |
>
> While an account needs reconnecting, `relay.auth.accounts()` and `useAccounts()` report `status: "reconnect"`, and the management member read reports `status: "needs-reconnect"` with the `reason` (`connected` while the tokens work; accounts Domino keeps no tokens for carry neither field). Linking again asks for every permission the provider's sources need, so a member who granted fewer is asked again.

### Creator accounts [#creator-accounts]

A creator account is the account a member publishes from: their YouTube channel or their TikTok account. Domino reads it in the background, so trackers like [YouTube Shorts](/docs/build/trackers#reward-youtube-shorts) and [TikTok videos](/docs/build/trackers#reward-tiktok-videos) can credit the member for what they post there.

* **Linked, never used to sign in.** A member signs in some other way first, then links the account. On Google's consent screen they pick the YouTube channel; Domino identifies it by its channel ID, not by the Google account. On TikTok's consent screen they approve Domino reading their profile and public videos; Domino identifies the account by the ID TikTok gives Domino for it, not by the @username.
* **One per platform.** Linking another channel or TikTok account replaces the current one. Content the earlier account posted stays where it is.
* **Only where Domino configures it.** Until then, members aren't offered that platform at all.

Creator accounts are [read in the background](#accounts-domino-reads-in-the-background), so an account whose access stopped working shows **Needs reconnect** until the member links it again. TikTok shares a member's videos only with their own permission, so while a TikTok account needs reconnecting Domino reads nothing from it. In Console, open a member: **Creator accounts** lists their linked accounts, and a reviewer can **Unlink** one with a reason. Domino then stops reading the account; the records it already collected stay.

> [!DEV]
> In SDK 1.x creator accounts sit beside the closed provider lists. `relay.auth.creatorAccounts.list()` (`GET /v1/auth/creator-accounts`) answers `{ accounts }`: one entry per provider Domino configured, each shaped like an `AccountConnection` with the account's `profile`. `connect("youtube")` or `connect("tiktok")` answers the consent-screen URL, and `disconnect(provider)` unlinks it. A TikTok account's `subject` is its `open_id`, and its `profile` has a name and picture but no `username`. In React, `useCreatorAccounts()` wraps the three. `provider` is an open string: `knownCreatorAccountProviders`, from `@domino-sdk/relay/schema`, lists the values this SDK knows.
>
> Operators read them on `management.members.get(member).creatorAccounts` and `management.members.creatorAccounts(member)`. `management.members.unlinkCreatorAccount(member, { provider, subject, expectedRevision, reason })` needs **Review** permission and answers the remaining accounts. `expectedRevision` is the account's `revision` as you read it; the older name `revision` still works. A retry with the same `actionId` answers with the first result.

### Operator identity changes [#operator-identity-changes]

Sometimes an account needs to stop counting for a member, such as a shared wallet or a hijacked X account. Your team can unlink it, and relink it later. Each account has three separate facts:

| Fact        | Changes when                                                                                                                             | Who changes it                                           |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| Ownership   | Never for an account the member proved or signed in with. An imported or vouched account they never used goes when a reviewer unlinks it | **Unlink**, for imported and vouched accounts            |
| Attribution | The member or a reviewer unlinks it; a reviewer relinks it                                                                               | **Unlink** and **Relink**                                |
| Sign-in     | A reviewer turns a wallet's sign-in on or off                                                                                            | **Enable sign-in** and **Disable sign-in**, wallets only |

In Console, open a member. **Identities** lists their X, Discord and Telegram accounts and app identities; **Wallets** lists their wallets. A reviewer chooses **Unlink** or **Relink** and enters a reason, which is recorded. Unlinking stops new quest checks and tracker records from crediting activity through that account in the project and environment. Activity already accepted and rewards already earned stay.

Each kind keeps its own rules:

* **Wallets and accounts** keep their sign-in when unlinked. A wallet's sign-in has its own command.
* **App identities** sign in only while linked: unlinking one also ends the sessions your app started for it.
* **X, Discord and Telegram** select one account per provider. To relink another account the member proved, unlink the selected one first.

Another member cannot claim an unlinked account, and the original member can link it again.

An account or wallet the member holds only on your organization's word is different: a [member import](/docs/use/imports#what-an-import-records) or your [app login](/docs/build/app-login#vouch-for-your-members-accounts) vouched for it, and Console marks it **Imported** or **Vouched by**. If the member never signed in with it or proved it, **Unlink** releases it. It leaves the member with nothing to relink, its owner can link it and sign in with it, and no import or app can attach it to that member again. Use it when the organization vouched for the wrong account.

If an account changed while you were looking at it, Console reports a conflict: refresh the member and review the current state before trying again.

> [!DEV]
> Scripts use `management.members.identityStates`. `list(member)` reads every identity with its `revision`, `linked`, `signIn`, `canUnlink` and `canRelink`, and `source`: where it came from. `unlink(member, input)` and `relink(member, input)` take the `identity`, the `expectedRevision` you read, and a `reason`. `setSignIn(member, { identity, enabled, reason })` changes a wallet's sign-in. Each command accepts an `actionId`: a retry with the same ID answers the first result. All of them need **Review** permission, except `list`, which needs **Read**.
>
> Name the identity the way a [member import](/docs/use/imports) names it. `members.lookup` and the test-member account commands take the same shape.
>
> | Kind | `identity` |
> | --- | --- |
> | Wallet | `{ kind: "wallet", chain, address }` |
> | X, Discord or Telegram | `{ kind: "x" \| "discord" \| "telegram", subject }`, with the numeric user ID |
> | App identity | `{ kind: "app:<name>", subject }` |
>
> For an X or Discord account, Relay uses the account with that subject the member has selected, or the only one they hold. If they hold it through more than one sign-in and have none of them selected, the command fails with 409 `identity-ambiguous`. Name it then with the selector the list returned.
>
> `source` is `member` when the member proved the identity, `import` when a member import attached it (with the import's ID in `import`), `app-login` when your app login's server vouched for it, and `test-link` when an operator linked it to a test member. New values may appear, so treat any other value as unknown.
>
> The selectors the list returns still work as input: `{ kind: "oauth", provider, issuer, subject }` and `{ kind: "app", appKind, subject }` are deprecated and removed in 2.0.0. So are `members.lookup({ provider, subject })` and the test-member `{ provider, id }`. The per-kind methods (`members.unlinkWallet`, `unlinkOAuthAccount`, `unlinkTelegramAccount`, `unlinkIdentity`, `relinkIdentity`, `setWalletSignIn`, `oauthAccounts`, `telegramAccount` and `identityLinks`) keep working through SDK 1.x and are deprecated.
>
> Management member reads always carry these fields: every connected account has `kind: "account" | "wallet"`, and the member detail has `wallets`, `balanceChecks`, `profile`, and `identities`. `profile` is `null` when the member has no participant profile. Clients should reject a response that omits these fields instead of guessing what an older server meant.

### Wallets [#wallets]

A member links Solana, EVM and Cosmos SDK wallets to a project by signing a message in each wallet; a Cosmos wallet links on a chain the app names by its chain ID. Quests can then check which wallets the member controls and the token balances they hold, for a holders-only quest or reward, on Solana, EVM and the Cosmos SDK chains Domino lists (see [token balances](/docs/build/wallets#check-token-balances)), how many NFTs of an EVM collection or a Solana Metaplex verified collection they hold (see [NFT holdings](/docs/build/wallets#check-nft-holdings)), their staking: a view function's value on an EVM contract, or Cosmos native delegations (see [staking and contract state](/docs/build/wallets#check-staking-and-contract-state)), and whether a wallet took part in an event of an EVM contract, such as a swap, mint or vote, in the last 30 days (see [on-chain actions](/docs/build/wallets#check-on-chain-actions)), and whether a Solana wallet's transaction called a program, with how its balances changed (see [on-chain actions on Solana](/docs/build/wallets#check-on-chain-actions-on-solana)). See [wallets](/docs/build/wallets).

|              | Project wallet list                              | Address ownership                                          |
| ------------ | ------------------------------------------------ | ---------------------------------------------------------- |
| Scope        | One project and environment                      | One project and environment                                |
| Changes when | The member links or unlinks; an operator unlinks | Never: an address belongs to the first member who links it |
| Read by      | Quests, the member's app, Console                | Domino, to refuse the address to anyone else               |

Linking and signing in are separate:

|                     | Linked wallet                                 | Sign-in wallet                                                 |
| ------------------- | --------------------------------------------- | -------------------------------------------------------------- |
| How it starts       | A signed-in member links it                   | Someone signs in with it; a new address creates a new member   |
| Signs in            | No, unless an operator enables sign-in for it | Yes, while the project enables its chain family                |
| In the project list | Yes                                           | Yes: signing in links it to the project                        |
| Turned off by       | Unlinking removes it from the list            | An operator disabling sign-in; unlinking does not stop sign-in |

### Imported members [#imported-members]

Moving from another platform? A [member import](/docs/use/imports) brings your members over, keyed by the account each will sign in with: your app's user ID, a wallet, or an X account. When that person signs in, they are the imported member, with their opening balances, quest progress and [referral](/docs/concepts/referrals): who invited them, and the friends they invited. An import never merges two members, and refuses an account another member holds. A row names an inviter who already signs in by the account they sign in with, the same way. Console shows who invited a member under the member's summary in **Members**, marked **Imported** when an import recorded it.

An import can also attach X, Telegram and Discord accounts and wallets on your organization's word. Quests, trackers and wallet checks trust these vouched accounts like proved ones, and Console marks them **Imported**. The one exception is a leaderboard's [payout list](/docs/build/leaderboards#export-the-payout-list): it lists only wallets a member proved, so an off-platform payout never goes to an address you vouched for. When the member links an account of that kind themselves, by connecting X, Telegram or Discord, signing in with the X account, or signing with the wallet, their own link replaces the vouched one. A vouched Telegram or Discord account never signs in.

Your app's server can vouch for accounts the same way when it signs a member in, so members who join after an import arrive with their accounts too. Console marks those **Vouched by** and the app login key's name. See [vouch for your members' accounts](/docs/build/app-login#vouch-for-your-members-accounts).

A wrong import can be [reverted](/docs/use/imports#revert-an-import): its opening balances, imported quest completions, and the accounts it attached that nobody signed in with since are taken back. The members it brought over stay.

## Profiles [#profiles]

A profile is the name and picture other members see in one project and environment, for example next to their score on a leaderboard. The member chooses a display name, and a picture they upload, take from a connected X, Discord or Google account, or have generated. A member's profile in one project never changes their profile in another.

| Who               | Controls                                                                                                                                                                 |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| You, the operator | Who sees profiles: nobody (the default), signed-in members, or anyone. Which accounts, X or Discord and in which order, fill in names and pictures until members choose. |
| The member        | Their name and picture, and whether to hide their profile from everyone else.                                                                                            |
| Reviewers         | Resetting a name, removing a picture, and locking or unlocking a profile, each with a recorded reason.                                                                   |

Where profiles are visible, leaderboard rows show the profile's name and picture. A profile page can also show the member's place on a leaderboard, their completions of quests that opt in to profiles, and their progress in a referral program, but only what the viewer could read anyway. Emails, wallet addresses, member IDs and account IDs are never shown. Google and Apple accounts never supply a default name or picture. See [participant profiles](/docs/build/profiles).

> [!DEV]
> Apps read a profile by its public profile ID, along with separate reads keyed by it; each read applies its own resource's access. A generated avatar comes from a seed Domino derives from the member with a secret per project. Connecting accounts or linking wallets does not change it, and it reveals nothing about the member.

## Ownership of progress [#ownership-of-progress]

* **Completions** are recorded for the member who did the quest.
* **Quest rewards** belong to the member who completed the quest.
* **Referral rewards** go to both sides: a [referral program](/docs/concepts/referrals) connects an inviter and an invited member so each can receive their own rewards.

Your app shows progress, and Domino checks activity and records the result on its server:

| Who             | Does                                   | Uses                                                   |
| --------------- | -------------------------------------- | ------------------------------------------------------ |
| Your app        | Shows progress                         | The [participant API](/docs/reference/participant-api) |
| Domino          | Checks activity and records the result | Server-side verification                               |
| Trusted backend | Staff operations                       | Scoped management credentials                          |

> [!IMPORTANT] Member sessions cannot act as staff
> A member's session cannot grant points or approve a review. Run staff operations on a trusted backend with scoped management credentials.

## Erased members [#erased-members]

When a person asks you to delete their data, you [erase their member](/docs/use/member-erasure). Their profile, accounts, sign-in, consent and submitted evidence are deleted, and the member stays as an anonymous ID with the points, completions and rewards it earned, so leaderboards and other members' referral rewards don't change. Nothing new reaches an erased member, and the same person signing in again becomes a new member. Erasing needs the **Publish** permission and can't be undone.

## Banned members [#banned-members]

You can [ban a member](/docs/use/member-bans) who farms or abuses your program. A banned member can still sign in, but can't take part: Domino refuses their attempts, completions and invitations, skips tracker records that would count for them, leaves them off every leaderboard and settlement, and stops referral payouts to and from them. When you ban, you can also take back their completions, the referral payouts they received and their manual awards, after a preview of what that reverses. Banning needs the **Review** permission, and you can unban later. A ban covers one member: the same person signing in with another account is a different member.

## Test members [#test-members]

A test member is a pretend member you create in the test environment to try your quests end to end before launch. It has a display name, no sign-in, and a **Test** badge in Console. Someone with `publish` permission in test can act for it:

* **Submit a quest** on its behalf. The submission is checked, reviewed and rewarded like a real member's, and the history names who did it.
* **Pass a quest, or accept a rejected try anyway.** Completion rules, budgets and rewards still apply. See [Pass a quest or accept an attempt anyway](/docs/use/quests#pass-a-quest-or-accept-an-attempt-anyway).
* **Accept a referral invitation**, with the same refusals, qualification and rewards as a member's own acceptance.
* **Redeem an offer**, with the same price, stock, limits and refusals as a member's own redemption.
* **Move its clock forward**, by days, hours or minutes or to a later instant, to try streaks, weekly limits and time-of-day rules without waiting.
* **Give it a wallet** to try balance and holding quests. See [Give the member a wallet](/docs/use/quests#3-give-the-member-a-wallet).
* **Link a real X or Discord account** to try follower, repost and role checks. See [Link an X or Discord account](/docs/use/quests#4-link-an-x-or-discord-account).
* **Send X posts, Discord messages and reactions** as the member. See [Send X and Discord activity](/docs/use/quests#5-send-x-and-discord-activity).
* **Reset it** to start again.

These actions work from Console, a personal API key, or a `domino login` CLI session. Hosted app keys and service keys can't create, list, act as, accept referrals or redeem offers as, pass quests for, advance, give wallets or accounts to, send records for, reset or purge test members. Management credentials still can't issue member sessions.

The one exception is the project's staging app. An operator who signed in to it through Console and holds `publish` can sign that app in as a test member. The member gets an ordinary 8-hour member session, so the app runs as that member, and the history records the operator. Signing out or resetting the member ends the session. Staging opened with the project password cannot do this, and live never issues one.

> [!DEV] Test member details
> Management member detail and list reads include `test: true` and the profile display name as `name`. So do the reads that name members elsewhere: `members.people()`, and the `people` or `person` of attempt and entitlement reads. A submission on a test member's behalf uses member admission, evaluation, human review, and rewards; a pass admits the attempt as a submission would, then accepts it in place of the quest's check, and the attempt's history names the operator.
>
> **Clock.** A test member has its own clock, initially real time. Operators can advance it by 1–30 project-calendar days per call, preserving local time where possible, or by an exact number of hours or minutes, or to a later instant. The clock can run at most 90 days ahead of real time. `offsetDays` counts the days advanced by date, initially zero. Each advance captures a fixed duration shift for all activity and progress until the next advance. A later DST change can cause an hour of wall-clock drift; elapsed ages and timestamp ordering stay intact. Optional `today` is the server’s current project-calendar date for that member (`YYYY-MM-DD`). Shared tracker records retain real time; each beneficiary’s attempt pins its own projected activity. An omitted `offsetDays` in an older response means zero. Other members and live are unchanged. Existing evaluations keep their frozen clock; workflow timers remain on real time. Reset and create a new member to return to day zero.
>
> **Records.** Custom tracker records can name a test member with a `member` account. No identity row is required. The test member belongs to the project that created it.
>
> **Wallets.** A test member can hold Solana, EVM or Cosmos addresses, up to five per chain family, added without a signature. Quest code and tracker attribution read them like wallets a member linked. They can't sign in, and an address that belongs to another member is refused. When the wallet's owner signs in with it or connects it, the address moves to them.
>
> **X and Discord accounts.** An operator links someone else's public account on their word, without OAuth, so quest code's X profile, follower and repost reads and Discord role reads answer for a real account. Attribution reads it like a proved link, and Console marks it **Test-linked**. It can't sign in, Domino never writes to it (a test-linked Discord account never receives role rewards), and an account that belongs to another member is refused. When the account's owner signs in with it or connects it in the same project and environment, the account moves to them.
>
> **Synthetic records.** Each X post, Discord message or reaction an operator sends is one synthetic record in a managed X or Discord tracker, which otherwise only Domino's X collector and Discord gateway fill. Relay attributes it, applies quest filters and decides quest triggers as it does for collected activity, and marks it `synthetic: true` in the tracker's records. The record names the member's linked X or Discord account when it has one. Otherwise the first record links the member a synthetic X or Discord account: a verified link that attribution and `x.connection()` read, but that X and Discord don't know and that can't sign in.
>
> **Reset.** Reset deletes the test member, its wallet addresses, its synthetic accounts and records, and its supported participation history. It unlinks the X and Discord accounts an operator linked to the member and the accounts the member connected while the staging app acted as it, without touching the accounts themselves. A permanent reset marker prevents the old ID from being recreated. Shared tracker datasets, creation and reset receipts, the reset audit record, and the audit of operators signing a staging app in as the member remain. Reset refuses states whose shared or external effects cannot safely be removed. See [Try quests with test members](/docs/use/quests#try-quests-with-test-members) for the API and refusal conditions.

## Active members [#active-members]

Domino counts a project's **active members** each calendar month, in UTC. A member is active in a month when, on a UTC day of it after the UTC day they joined the project, they sent a signed-in request to the participant API. Their attempts and redemptions are such requests, and so is every call your app makes with their session.

These never make a member active:

* the day they joined, so a member who signs up and never comes back is not counted;
* a [member import](#imported-members) or a [tracker](/docs/concepts/trackers) record your server reports, on its own;
* anything in the test environment, so [test members](#test-members) never count.

Each member counts once a month, however often they come back. A member's active days stay in the months they happened, and move with the project when it moves to another organization.

Read the count with `management.usage.activeMembers()` or `domino usage active-members` (`GET /management/v1/usage/active-members`, `read` permission). It returns this month's `activeMembers`, the project's `plan` and its `limit` of live active members a month (null when the plan has none), and the six earlier months in `history`, newest first. The count is the same whichever environment you select. In Console, **Settings → Plan & usage** shows this month's count against the limit, with last month's beside it.

Going over the limit refuses nothing. Where plans apply, a project over its limit in two calendar months in a row moves up:

| Plan                                          | After two months over                                                                                                                         |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Launch or Growth, paid through Domino billing | The next plan starts at the project's next renewal. Domino tells you the plan and the date first, and Domino support can call the change off. |
| Scale                                         | Domino gets in touch about Enterprise.                                                                                                        |
| A plan Domino support set                     | Domino suggests the next plan; nothing changes on its own.                                                                                    |

## Real people in test [#real-people-in-test]

Where plans apply, a project's test environment admits a limited number of **real people**: members who joined test, by signing in or through a [member import](#imported-members). The limit is the plan's: 100 on Free and Launch, 250 on Growth, 1,000 on Scale, and what Domino agreed on Enterprise. [Test members](#test-members) never count.

Once test holds that many, a person who never joined test cannot sign in to it: sign-in fails with `limit-reached` (403, `limit: "real-people-in-test"`) and a message that the test version is full. Nothing else changes:

* people who already joined test keep signing in, even over the limit;
* live sign-in is not limited this way;
* staff and operator sessions are not counted.

A bigger plan raises the limit. While the limit is enforced, Console shows a notice on project pages from 80% of it. Read the count with `management.usage.realPeopleInTest()` or `domino usage real-people-in-test` (`GET /management/v1/usage/real-people-in-test`, `read` permission). It returns `realPeople`, the project's `plan`, its `limit`, and whether the limit is `enforced`, whichever environment you select.

## Recover saved submissions [#recover-saved-submissions]

If a member's saved answer refers to a submission Domino has permanently closed, the member reviews the current quest and chooses to discard the saved answer before sending again.

> [!DEV]
> If the server confirms that the operation is permanently retired, the SDK preserves that terminal state across reloads. A lost response or an unknown conflict does not authorize discard: resume the original operation instead. In React, `useQuest().retired` identifies this state and `restart()` discards it without submitting a new claim.

## Restore quest identity attribution [#restore-quest-identity-attribution]

When a reviewer relinks an account from the member's page in Console, Domino looks again at that member's activity from while it was unlinked, under the quest's current rules.

> [!DEV]
> Reviewers relink a retained proved wallet or OAuth identity. Wallet attribution retains its first-link time. X and Discord selections receive a fresh link time on relink. Both belong to the project and environment. Ownership, sign-in grants and existing sessions remain unchanged. Wallet sign-in control is separate; app identity unlink retains its existing session-ending policy.
>
> Relink redecides unlinked historical observations under the current quest policy, while stored observations and admitted attempts remain pinned. See [relink retained identities](/docs/concepts/trackers#relink-retained-identities).
