Admin instance
Instance configuration is everything an operator can change at runtime. It covers single sign-on, Gateway rollout, registration policy, branding and legal links, instance policy, third party integrations, premium billing, media retention, and the ordered limit configuration. The Instance resource serves the subset published to unauthenticated clients.
Every write is a merge over the stored configuration, and an omitted key leaves the stored value unchanged. The limit configuration write and Replace bot system are the exceptions and replace what they cover.
Reading configuration requires the Admin ACL instance:config:view, and writing it requires instance:config:update. The limit configuration has its own pair, instance:limit_config:view and instance:limit_config:update.
That relaxation applies only to a session credential, so an Admin API key and a bearer token are evaluated normally even before setup is complete. Completing setup grants the acting session the wildcard ACL. Registration URLs, pending registrations, and limit configuration always need their own ACL.
Instance configuration object
Section titled “Instance configuration object”The complete runtime configuration of the deployment. Every configuration operation here except the limit configuration returns it.
Missing settings use the defaults documented below. Invalid stored configuration causes an error rather than silently resetting a policy. Operators can find recovery guidance under stored instance policy.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| sso | SSO configuration object | Single sign-on settings |
| gateway_rollout | Gateway rollout configuration object | Gateway admission and dispatch tuning |
| voice_room | voice room configuration object | 3D voice room, table game, room camera, and room character switches |
| push_relay | push relay configuration object | Operator consent to the Fluxer-run push relay |
| domain_migration | domain migration configuration object | Web domain migration rollout |
| plutonium_page | Plutonium page configuration object | Plutonium page rollout |
| captcha | captcha configuration object | ALTCHA proof-of-work captcha settings |
| experiment_delivery | experiment delivery configuration object | Cadence every client polls the experiments route on |
| registration | registration configuration object | Registration policy, issued URLs, and pending registrations |
| self_hosted | boolean | Whether the deployment runs in self-hosted mode |
| account_identity | account identity configuration object | How members sign in, and whether that can still change |
| app_public | public application configuration object | Branding, legal, setup, and registration field policy |
| policy | instance policy object | Community, direct message, premium, and gating policy |
| integrations | instance integrations object | Third party provider settings and their resolved availability |
| media | instance media object | Attachment retention settings |
| billing | instance billing object | Premium billing settings and the state resolved from them |
| booster_role_enabled | boolean | Whether a member who boosts a guild is given its booster role, false by default |
| badge_inventory_enabled | boolean | Whether accounts can change badge visibility, false by default |
Account identity configuration object
Section titled “Account identity configuration object”How members of the deployment sign in. It is read-only here. The setup wizard chooses it through set the setup sign-in method, and Sign-in methods explains the rules.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| mode | string | The account identity mode in effect, email or username |
| locked1 | boolean | Whether the mode can no longer change |
| tag_style | string | How usernames are tagged, one of the tag styles |
1 True on a hosted deployment, and on a self-hosted one once setup is complete or the first account exists
SSO configuration object
Section titled “SSO configuration object”Single sign-on settings for the deployment’s OpenID Connect provider.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | boolean | Whether single sign-on is offered |
| enforced1 | boolean | Whether single sign-on is the only accepted login method |
| display_name | ?string | Provider name shown on the login screen |
| issuer | ?string | OpenID Connect issuer |
| authorization_url | ?string | Authorisation endpoint |
| token_url | ?string | Token endpoint |
| userinfo_url | ?string | Userinfo endpoint |
| jwks_url | ?string | JWKS endpoint |
| client_id | ?string | Registered client identifier |
| client_secret_set | boolean | Whether a client secret is stored |
| scope | ?string | Space-separated scope string |
| allowed_domains2 | array[string] | Email domains permitted to sign in (max 100 entries) |
| auto_provision | boolean | Whether a first-time sign-in creates an account |
| redirect_uri3 | ?string | Redirect URI to register with the provider |
1 A deployment that has never stored the value reports the same value as enabled
2 Each entry is stored lowercased and IDNA encoded, duplicates are collapsed, and an empty entry is dropped
3 The configured web application endpoint followed by /auth/sso/callback. It is the only redirect URI the provider needs, mobile sign-in included. No operation can set it
Gateway rollout configuration object
Section titled “Gateway rollout configuration object”Admission and dispatch tuning for the Gateway cluster.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| session_rollout_percentage | number | Percentage of sessions admitted to the new Gateway (0-100, default 100) |
| session_rollout_mode | string | modulo or random (default modulo) |
| guild_rollout_percentage | number | Percentage of guilds admitted to the new Gateway (0-100, default 100) |
| rpc_request_timeout_ms | integer | Deadline for one Gateway RPC (1000-60000, default 10000) |
| max_concurrent_session_starts | integer | Session starts admitted at once (1-10000, default 512) |
| max_concurrent_guild_starts | integer | Guild starts admitted at once (1-10000, default 256) |
| gateway_dispatch_relay_shards | integer | Dispatch relay shard count (1-10000, default 32) |
| gateway_dispatch_relay_max_queue | integer | Dispatch relay queue ceiling (0-1000000, default 50000) |
| voice_e2ee_scope | string | guild_feature_only or platform_wide (default guild_feature_only) |
| max_connections | integer | Per-node connection soft limit (1-200000; default 0 uses the environment value) |
| game_activity_enabled | boolean | Whether current game sharing is enabled for the instance (default false) |
| game_activity_epoch | integer | Read-only rollout revision (0-9007199254740991, default 0) |
| member_list_diff_sync | number | Percentage of guilds whose member lists send only changed rows (0-100, default 0) |
| member_list_flush_workers | number | Percentage of guilds with 5000 or more members that flush member lists from worker processes (0-100, default 0) |
| socket_relay_enabled | boolean | Reserved for the Gateway socket relay (default false) |
| large_guild_presence_defer | boolean | Batch member list updates from presence changes in guilds with 5000 or more members (default false) |
| game_member_interest | boolean | Tells clients to follow the game activity of visible member rows through game_members instead of members (default false) |
| member_list_large_sync_delay_ms | integer | Batching window for member list updates in guilds with 5000 or more members (100-10000, default 1000) |
| member_list_count_interval_ms | integer | Shortest gap between member list updates that change only the counts (0-300000; default 0 sends every change) |
| member_list_diff_full_interval_ms | integer | Age at which a member list diff sync baseline gets a full sync again (1000-3600000, default 60000) |
| large_guild_voice_state_passive | boolean | In guilds with 5000 or more members, skip passive sessions in Voice State Update (default false) |
| large_guild_typing_cap | integer | In guilds with 5000 or more members, people per channel sent Typing Start within 10 seconds (0-100; 0 is no limit) |
| typing_channel_focus | boolean | In guilds with 5000 or more members, honor typing_channels from Lazy Request (default false) |
| voice_channel_interest | boolean | In guilds with 5000 or more members, honor voice_channels from Lazy Request; ignored while off (default false) |
Every field is present on read. An absent document or missing field uses the defaults above.
max_connections overrides FLUXER_GATEWAY_MAX_CONNECTIONS on each Gateway node without a restart. Set it to 0 to restore the environment value. The hard limit uses the same 5% headroom as the environment setting. Lowering the limit leaves existing connections open. Monitor fluxer_gateway_websocket_connection_limit and node memory before raising it.
member_list_flush_workers takes effect without a restart, on each large guild’s next member list flush. A guild is included when its ID hashes into the percentage, so values below 100 select a stable subset of guilds. Every subscriber of a guild gets one full member list sync when the guild moves in or out. A guild whose worker crashes flushes from the guild process for 60 seconds before starting workers again. Watch fluxer_gateway_member_list_flush_busy_microseconds_total and fluxer_gateway_member_list_flush_queued_total against fluxer_gateway_member_list_flush_jobs_total after turning it on.
member_list_diff_sync takes effect without a restart. A guild is included when its ID hashes into the percentage, so values below 100 select a stable subset of guilds. Setting it to 0 sends full member list syncs again on the next update. Compare fluxer_gateway_member_list_sync_bytes_total by kind and watch fluxer_gateway_member_list_diff_baselines and Gateway memory when raising it.
large_guild_presence_defer, member_list_large_sync_delay_ms, member_list_count_interval_ms and member_list_diff_full_interval_ms take effect without a restart. With large_guild_presence_defer on, a status change in a large guild reaches member lists on the next batch flush, at most member_list_large_sync_delay_ms later; the presence update itself and permission changes are still sent at once. member_list_count_interval_ms and member_list_diff_full_interval_ms apply only to guilds included by member_list_diff_sync: an update that changes only the member and online counts waits until the interval since the last update has passed, then sends the latest counts. Watch fluxer_gateway_dispatch_total by event, fluxer_gateway_member_list_count_sync_total by result and fluxer_gateway_large_guild_reductions_total when changing them.
game_member_interest takes effect without a restart and closes no connection. The Gateway adds game_member_interest: true to the gateway_rollout object of Ready and to Gateway Rollout Update while it is on, and omits the field while it is off; clients that see it move visible member rows from the Lazy Request members field to game_members, which carries game activity without presence. While it is off, a game_members field only clears that list. Turn it on only when every Gateway node runs a version that accepts game_members. Compare fluxer_gateway_member_subscription_presence_total with fluxer_gateway_dispatch_total{event="PRESENCE_UPDATE"}, and watch fluxer_gateway_member_subscription_updates_total by kind.
large_guild_voice_state_passive, large_guild_typing_cap, typing_channel_focus and voice_channel_interest take effect without a restart. Clients learn typing_channel_focus and voice_channel_interest from gateway_rollout, which carries each only while it is on. With large_guild_voice_state_passive on, active sessions, bot sessions, the voice state’s own user and the users connected to that channel still receive Voice State Update at once, and any other passive session learns of a voice state change from its next Passive Updates, at most 30 seconds later. With large_guild_typing_cap set, a person already counted in a channel keeps being sent while they type, and a further person is not sent until a slot frees up. Watch fluxer_gateway_large_guild_filtered_total by kind and fluxer_gateway_dispatch_total by event when changing them.
Micup raises game_activity_epoch by one when game_activity_enabled changes. Clients use the epoch to discard older rollout updates. An update cannot set game_activity_epoch.
Admin reads and writes name this field rpc_request_timeout_ms. The legacy stored name is covered in the operator configuration reference.
Push relay configuration object
Section titled “Push relay configuration object”The operator’s consent to the push relay supplemental privacy notice.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| relay_consent_accepted | boolean | Whether the operator accepted the push relay supplemental privacy notice (default false) |
| relay_consent_accepted_at | ?string | ISO 8601 timestamp of that acceptance, or null when the notice stands unaccepted (default null) |
| relay_consent_accepted_by | ?snowflake | Account that accepted the notice, or null when the notice stands unaccepted (default null) |
Every field is present on read. An absent document or missing field uses the defaults above.
The notice covers only the Fluxer-run relay that reaches Apple and Google for the official mobile apps. A subscription whose endpoint points at another distributor, such as a self-hosted UnifiedPush server or ntfy, never reaches that relay and needs no acceptance.
Voice room configuration object
Section titled “Voice room configuration object”The instance switches for the 3D room view of voice channels, for the table games played in it, for the cameras shown in it, and for the 3D characters of the people in it. A client reads them as the voice_room assignment of Get experiment assignments, where rooms is rooms_enabled, games is true only while rooms_enabled and games_enabled are both on, cameras is true only while rooms_enabled and room_cameras_enabled are both on, avatars is true only while rooms_enabled and room_avatars_enabled are both on, walk is true only while rooms_enabled, room_avatars_enabled and room_walk_enabled are all on, and watch is true only while rooms_enabled and room_watch_enabled are both on.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| rooms_enabled | boolean | Whether a voice channel with a room theme opens as a 3D room (default false) |
| games_enabled | boolean | Whether table games can be played, which needs rooms_enabled (default false) |
| room_cameras_enabled | boolean | Whether the 3D room shows cameras on avatars, which needs rooms_enabled (default false) |
| room_avatars_enabled | boolean | Whether the 3D room shows people as 3D characters, which needs rooms_enabled (default false) |
| room_walk_enabled | boolean | Whether the 3D characters walk around the room, which needs rooms_enabled and room_avatars_enabled (default false) |
| room_watch_enabled | boolean | Whether people play a shared YouTube video on the room TV, which needs rooms_enabled (default false) |
| room_watch_enabled_at? | integer | When room TV videos last came on, in milliseconds since the Unix epoch. The server sets it and no update carries it |
| rollout_basis_points | integer | Share of accounts the switches reach, in basis points (0-10000, default 10000) |
| rollout_salt | string | Salt of the sampling hash (1-64 printable ASCII characters, default voice-room-v1) |
| included_user_ids | array[snowflake] | Accounts the switches always reach, up to 1000 entries (default empty) |
| excluded_user_ids | array[snowflake] | Accounts the switches never reach, up to 1000 entries (default empty) |
Every field but room_watch_enabled_at is present on read. An absent document or missing field uses the defaults above.
excluded_user_ids wins over every other rule. Otherwise the switches reach an account in included_user_ids, whatever rollout_basis_points says, and any other account whose sampling bucket falls inside rollout_basis_points. Unlike the other rollouts, rollout_basis_points defaults to 10000, so a stored configuration from before these fields reaches every account. The rollout is a feature gate, not a privacy boundary: a modified client can still send position, head direction and wave signals in a voice channel where reached and unreached members are mixed.
An account the rollout does not reach is treated as if rooms_enabled were false: its voice_room assignment has every switch off, and the routes and server writes described below behave for it as they do while rooms are off. It can still leave a table and stop watching one, and a moderator it does not reach can still stop another member’s room TV video. These, and timers and cleanup that act on no one account, such as ending tables while games are off and stamping room_watch_enabled_at, follow the switches alone. A table with a player the rollout no longer reaches ends as canceled with reason disabled on its next timer pass or move, and a running game also when one of its players leaves it.
Room TV videos come on when an update turns on room_watch_enabled while rooms_enabled is on, or rooms_enabled while room_watch_enabled is on, and the server then sets room_watch_enabled_at to the time of that update. The voice_room assignment carries it as watch_since, and a client shows no room TV video written before it, so switching videos off and on again ends every one that was playing.
While rooms_enabled is false, the server seats nobody, and Take a voice seat and every table game route return 403 FEATURE_TEMPORARILY_DISABLED. A room theme can still be set on a channel, and it has no effect until rooms are switched on.
While table games are off, every table game route returns 403 FEATURE_TEMPORARILY_DISABLED, and the server ends each open table as canceled with reason disabled on its next timer pass. Switching games on again restores no ended table.
room_cameras_enabled changes nothing on the server. It tells clients whether the 3D room shows the cameras of the people in it on their avatars and subscribes to them. While it is off, a client shows the room without cameras, and the grid view of the call is unaffected.
room_avatars_enabled is off until an Admin switches it on, and it has no effect while rooms_enabled is false. While it is off, Choose a room character and Refresh my voice room character return 403 FEATURE_TEMPORARILY_DISABLED, the server writes no character attribute, and a client shows the room without characters. A stored configuration written before the field existed reads it as false.
room_walk_enabled has no effect while rooms_enabled or room_avatars_enabled is false. A member it reaches in a guild voice channel may publish LiveKit data, the channel the room’s position, head direction and wave signals use, even without permission to speak, stream or show video. A deafened member, a member of a DM call and a member it does not reach publish data only while they may publish media. A member gets this data permission when they connect. Every update of this object also queues a pass that, a few seconds later, rewrites it for the members already connected. A pass that cannot reach a LiveKit server or a member is retried, and until one gets through those members keep the permission they had.
Domain migration configuration object
Section titled “Domain migration configuration object”The instance rollout that moves the official web client from its legacy origin to a new one. Experiments defines what a signed-in client resolves from it. The instance discovery document publishes enabled, anonymous_rollout_basis_points, rollout_salt, and standalone_forwarding for clients that are not signed in.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | boolean | Whether the rollout runs at all (default false) |
| config_version | integer | Revision counter, raised by Micup and never accepted from a request |
| rollout_basis_points | integer | Share of accounts the rollout selects, in basis points (0-10000, default 0) |
| rollout_salt | string | Salt of the sampling hash (1-64 printable ASCII characters, default domain-migration-v1) |
| included_user_ids | array[snowflake] | Accounts the rollout always selects, up to 1000 entries (default empty) |
| included_guild_ids | array[snowflake] | Guilds whose members the rollout always selects, up to 1000 entries (default empty) |
| include_premium_users | boolean | Whether the rollout always selects accounts with active premium (default false) |
| excluded_user_ids | array[snowflake] | Accounts the rollout never selects, up to 1000 entries (default empty) |
| anonymous_rollout_basis_points | integer | Share of logged-out devices the rollout moves, in basis points (0-10000, default 0) |
| standalone_forwarding | boolean | Whether installed desktop web apps forward to the new origin once their data has moved (default false) |
Every field is present on read. An absent document or missing field uses the defaults above.
excluded_user_ids wins over every other rule. Otherwise the rollout selects an account in included_user_ids, a member of a guild in included_guild_ids, or a premium account while include_premium_users is true, whatever rollout_basis_points says.
An installed Chromium desktop web app moves its data like a browser tab, then stays on the legacy origin and offers to install the app from the new one. Set standalone_forwarding once the web app manifest lists the new origin in scope_extensions and the new origin serves the matching association file. From then on the installed app forwards like a browser tab. Installed mobile and Safari web apps never forward, whatever the value.
Only the official web client acts on this configuration. On any other instance it changes nothing a client does.
Plutonium page configuration object
Section titled “Plutonium page configuration object”The instance rollout that replaces the Plutonium settings tab with a full Plutonium page, makes app pages linkable in chat, and uses a minimal gift purchase modal. Experiments defines what a client resolves from it.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | boolean | Whether the rollout runs at all (default false) |
| config_version | integer | Revision counter, raised by Micup and never accepted from a request |
| rollout_basis_points | integer | Share of accounts the rollout selects, in basis points (0-10000, default 0) |
| rollout_salt | string | Salt of the sampling hash (1-64 printable ASCII characters, default plutonium-page-v1) |
| included_user_ids | array[snowflake] | Accounts the rollout always selects, up to 1000 entries (default empty) |
| included_guild_ids | array[snowflake] | Guilds whose members the rollout always selects, up to 1000 entries (default empty) |
| include_premium_users | boolean | Whether the rollout always selects accounts with active premium (default false) |
| excluded_user_ids | array[snowflake] | Accounts the rollout never selects, up to 1000 entries (default empty) |
Every field is present on read. An absent document or missing field uses the defaults above.
excluded_user_ids wins over every other rule. Otherwise the rollout selects an account in included_user_ids, a member of a guild in included_guild_ids, or a premium account while include_premium_users is true, whatever rollout_basis_points says.
Captcha configuration object
Section titled “Captcha configuration object”The ALTCHA proof-of-work check that the API issues and verifies itself on gated operations. CAPTCHA handling defines the challenge exchange and lists the gated operations.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | boolean | Whether gated operations require a solved challenge (default true) |
| cost | integer | PBKDF2 iterations per solving attempt (1000-20000, default 5000) |
| max_counter | integer | Upper bound of the hidden counter a client searches for (100-20000, default 1000) |
Every field is present on read. An absent document or missing field uses the defaults above, so the check is on until an administrator sets enabled to false. Setting enabled to false turns the check off for the whole instance.
Each challenge hides its counter between half of max_counter and max_counter, and a client tries counters from 0 upward. Solve time grows with cost times max_counter. Micup spends one attempt at cost to issue each challenge.
Experiment delivery configuration object
Section titled “Experiment delivery configuration object”How often a client polls Get experiment assignments, and how widely those polls are spread. The setting is instance-wide and applies to every experiment at once, so adding an experiment adds no second cadence to tune.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| poll_interval_seconds | integer | Seconds between client revalidations (60-86400, default 300) |
| poll_jitter_percent | integer | Maximum random change to each revalidation interval, as a percentage in either direction (0-50, default 15) |
Every field is present on read. An absent document or missing field uses the defaults above.
Both fields are served to every account, whether or not any experiment targets that account, and neither one is versioned by config_version. A client that has never received a response from the experiments route uses built-in defaults of 300 seconds and 15 percent, which equal the defaults above. A client that cannot read the route never receives either field.
Registration configuration object
Section titled “Registration configuration object”Registration policy in force, plus every issued registration URL and every account awaiting a decision.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| mode | string | Registration mode |
| admin_registration_urls_enabled1 | boolean | Whether Admin-issued registration URLs are accepted |
| urls2 | array[registration URL object] | Every issued registration URL, including revoked and exhausted records |
| pending_registrations3 | array[pending registration object] | Accounts awaiting a decision |
1 While the value is false, registration refuses every supplied registration URL code, so an issued URL stops working without being revoked
2 Ordered by creation time, newest first
3 Ordered by request time, oldest first
Both collections are embedded in the configuration response. There is no separate listing operation and no pagination, so every configuration read returns every issued URL.
Registration modes
Section titled “Registration modes”| Value | Description |
|---|---|
| open | Anyone can register |
| approval | Anyone can register, and an Admin decision is required before the account can be used |
| closed | Public registration is closed |
A valid registration URL is accepted in every mode, including closed, and its own approval_required replaces the mode for the account it creates.
Registration URL object
Section titled “Registration URL object”A registration URL is an invitation an Admin can issue while the registration mode is closed or approval. It has its own expiry, use budget, and approval requirement.
Micup accepts a URL while it has no revocation time, has not passed its expiry, and has a use count below max_uses. A URL failing any of those tests is still reported here.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| id1 | string | Identifier of the registration URL (1-128 characters) |
| label | ?string | Admin note attached to the URL, or null when unset |
| created_by_user_id | snowflake | Admin account that issued the URL |
| created_at | ISO8601 timestamp | Time the URL was issued |
| expires_at | ?ISO8601 timestamp | Time the URL stops working, or null when it never expires |
| max_uses | ?integer | Maximum permitted uses, or null for unlimited use |
| use_count | integer | How many registrations have completed through the URL |
| revoked_at | ?ISO8601 timestamp | Time the URL was revoked, or null while it has not been revoked |
| approval_required2 | boolean | Whether an account created through the URL still needs an Admin decision |
| last_used_at | ?ISO8601 timestamp | Time the URL was last used, or null when it never has been |
| last_used_by_user_id | ?snowflake | Most recent account created through the URL, or null when there is none |
1 A randomly generated UUID that is also the bearer code authorising registration, so every reader of the configuration can redeem an unrevoked URL
2 The value replaces the instance registration mode for an account created through this URL, in both directions. A URL with the value false lets an account skip approval on an instance in approval mode
Example
Section titled “Example”{ "id": "3f2a91c4-6d1e-4a77-9f0b-2c5d8e114a20", "label": "Design team", "created_by_user_id": "1478812292088791040", "created_at": "2026-08-20T10:00:00.000Z", "expires_at": null, "max_uses": 25, "use_count": 3, "revoked_at": null, "approval_required": false, "last_used_at": "2026-08-29T18:22:10.000Z", "last_used_by_user_id": "1500901337221828608"}Pending registration object
Section titled “Pending registration object”One account that registered and is still waiting for an Admin decision.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| user_id | snowflake | Account awaiting a decision |
| username | string | Username chosen at registration |
| discriminator | integer | Discriminator tag from 0 to 9999 |
| global_name | ?string | Display name of the account, or null when unset |
| ?string | Email address of the account, or null when none is stored | |
| requested_at | ISO8601 timestamp | Time the account registered |
| registration_url_id | ?string | Registration URL the account signed up through (1-128 characters), or null when it registered directly |
| client_ip1 | ?string | IP address the account registered from, or null when none was recorded |
1 Stored at registration time and never refreshed, so it can be stale by the time an Admin reads it
Public application configuration object
Section titled “Public application configuration object”Branding, legal, setup and registration field policy, in the Admin form of what the Instance resource publishes to clients.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| branding | public branding object | Product name, image URLs, and theme colour |
| setup1 | object | Has the single boolean configured |
| legal | public legal configuration object | Terms, privacy, and source code URLs |
| registration2 | public registration fields object | Registration field collection policy |
| localization?3 | object | Default client language for visitors who have not chosen one |
1 The Instance resource publishes admin_url in this object as well
2 The object has the single boolean collect_date_of_birth
3 The object has the nullable string default_locale and the string array default_locale_time_zones, as the Instance resource publishes them
Instance policy object
Section titled “Instance policy object”Community, direct message, premium and gating policy for the whole deployment.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| single_community_enabled | boolean | Whether the deployment presents one community |
| single_community_guild_id | ?string | Guild used as that community, or null before one has been created |
| direct_messages_disabled | boolean | Whether direct messages are disabled |
| direct_messages_locked1 | boolean | Whether the direct message setting is locked against further change |
| guild_create_access | boolean | Whether every account can create communities, or only admins and holders of the feature_guild_create limit |
| premium_mode | string | Premium mode |
| premium_trial_days | integer | Length in days of the one-time premium trial, where 0 turns the trial off |
| services | object | Operator overrides for gif_enabled, youtube_enabled, and bluesky_enabled. Each is nullable, and null means no override |
| services_resolved2 | object | The same keys as concrete booleans, resolved from the override and the provider’s own availability |
| services_available3 | object | Provider availability for gif, youtube, and bluesky, with no operator override applied |
1 The lock is set each time direct messages are re-enabled. Update instance configuration clears it when the policy object has direct_messages_locked set to false
2 Each key is the operator override when one is set, and otherwise the matching services_available value
3 gif and youtube report whether an API key resolves from the stored configuration or the deployment configuration. bluesky is the value of integrations.bluesky.effective_enabled
Bot system object
Section titled “Bot system object”The two bot lists shown in the bot catalog.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| official_apps1 | array[bot entry object] | Up to 20 Micup bots, the same list as policy.official_apps in the instance configuration |
| community_apps2 | array[bot entry object] | Up to 100 community bots, made and run by independent developers |
1 Published in instance discovery as features.official_apps and in the micup section of the bot catalog
2 Shown only in the community section of the bot catalog, never in features.official_apps. A community bot is listed only while its application is public, has a bot user, and that bot user has the verified flag and is not deleted, disabled, or banned. An ID on both lists is shown only as a Micup bot
Each list keeps its order, and an application ID appears at most once in a list.
Bot entry object
Section titled “Bot entry object”Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| application_id | snowflake | The ID of the bot’s application, in the signed 64-bit range |
| invite_permissions1 | string | Decimal unsigned 64-bit permission string to preselect when inviting the bot |
1 Only known permission bits are accepted, and ADMINISTRATOR never is
Premium modes
Section titled “Premium modes”| Value | Description |
|---|---|
| mirror | Resolve premium access from the account’s own entitlement and premium flags |
| everyone | Grant premium access to every account on a self-hosted deployment |
A self-hosted deployment issues gift codes and sells premium only in mirror.
Instance integrations object
Section titled “Instance integrations object”Every provider reports its stored settings, a _set boolean in place of each secret, and the availability resolved from the stored settings and the deployment configuration.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| gif | object | klipy_api_key_set and effective_available |
| youtube | object | api_key_set and effective_available |
| email integration object | Outbound email settings | |
| bluesky | Bluesky integration object | Bluesky client settings |
Email integration object
Section titled “Email integration object”Outbound email settings, and the provider resolved from them.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | ?boolean | Operator override, or null for no override |
| effective_enabled | boolean | Whether outbound email is in force |
| provider | ?string | Operator override of smtp or none, or null for no override |
| effective_provider | string | Provider in use, either smtp or none |
| from_email | ?string | Envelope sender address |
| from_name | ?string | Envelope sender name |
| smtp1 | object | host, port, username, secure, and password_set |
| disable_new_ip_authorization | boolean | Whether new-IP authorisation email is suppressed by the stored setting |
| effective_disable_new_ip_authorization2 | boolean | Whether it is suppressed once outbound email state is taken into account |
1 host, username, and secure are nullable, port is a nullable integer from 1 to 65535, and password_set is a plain boolean
2 True whenever the stored setting is true or outbound email is not in force
On a deployment whose account identity mode is username, effective_enabled is always false whatever the stored settings hold.
Bluesky integration object
Section titled “Bluesky integration object”Client identity the deployment presents to Bluesky, and the number of signing keys in its effective configuration.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | ?boolean | Operator override, or null for no override |
| effective_enabled | boolean | Whether the integration is enabled with at least one configured signing key |
| client_name | ?string | Client name presented to Bluesky |
| client_uri | ?string | Client URI |
| logo_uri | ?string | Client logo URI |
| tos_uri | ?string | Client terms URI |
| policy_uri | ?string | Client policy URI |
| key_count | integer | Number of configured signing keys |
Signing keys are write-only and must have unique identifiers.
Instance billing object
Section titled “Instance billing object”Stripe billing for the premium tier. Each stored field is nullable, and null falls back to the deployment configuration.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| enabled | ?boolean | Operator override of the billing switch, or null for no override |
| effective_enabled | boolean | Whether billing is switched on once the override and the deployment configuration are combined |
| stripe_secret_key_set | boolean | Whether a Stripe secret key is stored or supplied by deployment configuration |
| stripe_webhook_secret_set | boolean | Whether a Stripe webhook secret is stored or supplied by deployment configuration |
| stripe_secret_key_stored | boolean | Whether a Stripe secret key is stored, not counting deployment configuration |
| stripe_webhook_secret_stored | boolean | Whether a Stripe webhook secret is stored, not counting deployment configuration |
| automatic_tax4 | ?boolean | Stored switch for Stripe automatic tax at checkout, or null for the default |
| tax_id_collection4 | ?boolean | Stored switch for collecting a buyer tax ID at checkout, or null for the default |
| terms_consent_required4 | ?boolean | Stored switch for requiring terms of service consent at checkout, or null for the default |
| effective_automatic_tax | boolean | Whether checkout uses Stripe automatic tax |
| effective_tax_id_collection | boolean | Whether checkout collects a buyer tax ID |
| effective_terms_consent_required | boolean | Whether checkout requires terms of service consent |
| default_currency | ?string | Currency used when no country mapping applies, or null |
| prices1 | ?object | Stored billing price sets keyed by currency, or null to use the deployment configuration |
| country_currencies | ?object | Stored map of two-letter country codes to currencies, or null |
| legacy_prices2 | ?object | Stored map of legacy price slots to arrays of Stripe price IDs, or null to use the deployment configuration |
| billing_active3 | boolean | Whether premium purchases are available |
| stripe_serviceable5 | boolean | Whether existing Stripe subscriptions can be managed, cancelled and billed |
| catalog_mode | string | operator while prices is stored, otherwise env |
| webhook_url | string | The URL to register as the Stripe webhook endpoint |
1 Stored prices replace the deployment catalogue entirely and take any three-letter currency code. A buyer gets the currency mapped to their country, then default_currency, then the first configured currency. Micup’s country checks for localised currencies do not apply to them
2 A slot is monthly, yearly, gift_1_month, or gift_1_year, an underscore, and a currency, such as monthly_GBP. Existing subscriptions on a listed price keep renewing
3 True when billing is switched on, a Stripe secret key is set, at least one currency has both a monthly and a yearly price, and premium tiering is in force. Premium tiering is always in force on a hosted deployment, and on a self-hosted one only in the mirror premium mode
4 A hosted deployment always turns all three on. A self-hosted deployment defaults all three to off. Automatic tax needs Stripe Tax set up, and terms consent needs a terms of service URL in the Stripe public details
5 True while a Stripe secret key is set and premium tiering is in force. On a hosted deployment billing must also be switched on. Only the checkout routes follow billing_active
Billing price set object
Section titled “Billing price set object”The Stripe price IDs for one currency. Each is nullable.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| monthly | ?string | Price ID of the monthly recurring plan |
| yearly | ?string | Price ID of the yearly recurring plan |
| gift_1_month | ?string | Price ID of the one-month gift |
| gift_1_year | ?string | Price ID of the one-year gift |
Instance media object
Section titled “Instance media object”Attachment retention overrides the operator has set, and the values in force.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| attachment_decay1 | object | Nullable operator overrides plus an effective object of the same keys with concrete values |
1 The override keys are enabled, min_size_mb, max_size_mb, max_eligible_size_mb, min_lifetime_days, max_lifetime_days, curve, renew_threshold_days, and renew_window_days. Each is null when the deployment default applies, and effective reports the value in force. enabled is a boolean, curve is a number from 0 to 1, the _mb keys are positive numbers, and the _days keys are positive safe integers
Micup clears max_size_mb when it is not above min_size_mb, clears max_eligible_size_mb when it is below max_size_mb, and clears max_lifetime_days when it is below min_lifetime_days. A cleared key uses the deployment default. The effective size range must have a finite maximum above its minimum, and retention must produce a valid expiry date. Check the returned effective values after an update.
Branding asset kinds
Section titled “Branding asset kinds”| Value | Description |
|---|---|
| icon | Writes branding.icon_url |
| symbol | Writes branding.symbol_url |
| logo | Writes branding.logo_url |
| wordmark | Writes branding.wordmark_url |
| favicon | Writes branding.favicon_url |
SMTP test result object
Section titled “SMTP test result object”Whether one Create SMTP test connection attempt succeeded, and the failure text when it did not.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| ok | boolean | Whether the server accepted the connection and credentials |
| error1 | ?string | Failure text, or null when the test succeeded |
1 The message reported by the SMTP client, so it can repeat text supplied by the remote server
Example
Section titled “Example”{ "ok": false, "error": "Invalid login: 535 5.7.8 Authentication credentials invalid"}Registration URL creation object
Section titled “Registration URL creation object”One issued registration URL together with the link an Admin hands out.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| registration_url | registration URL object | Record that was issued |
| code1 | string | Bearer code that authorises registration (1-256 characters) |
| url2 | string | Complete registration link built from the configured web application endpoint |
1 Equal to registration_url.id, so it can be recovered from any later configuration read
2 The configured web application endpoint followed by /register?registration_url= and the percent-encoded code
Limit configuration response object
Section titled “Limit configuration response object”The effective limit configuration together with the deployment defaults and the metadata an editor needs.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| limit_config | limit configuration object | Effective configuration on the serving node |
| limit_config_json | string | The same document rendered as JSON indented by two spaces, for an editor to display |
| self_hosted | boolean | Whether the deployment runs in self-hosted mode |
| defaults1 | map[string, map[string, integer]] | Deployment default limits, keyed by rule identifier and then by limit key |
| metadata | map[string, limit key metadata object] | Display metadata for each limit key |
| categories2 | map[string, string] | Display label for each metadata category |
| limit_keys | array[string] | Every limit key in registry order |
| bounds?3 | map[string, object] | Optional min and max pair for each limit key |
1 Built for the deployment and the premium mode currently loaded by the serving node. Self-hosted mirror mode includes the premium rule
2 The keys are messages, guilds, channels, expressions, files, social, and features
3 Absent from every response
Limit configuration object
Section titled “Limit configuration object”Trait definitions and the ordered rules that decide each limit key.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| traitDefinitions | array[string] | Trait names a rule filter can match |
| rules | array[limit rule object] | Ordered limit rules |
The field names are camelCase, unlike the rest of the Admin API.
Limit rule object
Section titled “Limit rule object”One rule in that ordered set, with the filters that scope it and the limits it sets.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| id | string | Rule identifier (at least 1 character) |
| filters? | object | Optional traits and guildFeatures string arrays that scope the rule |
| limits | map[string, integer] | Non-negative value for each limit key the rule sets |
| modifiedFields?1 | array[string] | Limit keys whose value differs from the deployment default |
1 Compared with the deployment default rule of the same identifier, or with the deployment’s default rule for a custom identifier. A set key absent from that default counts as modified. A rule with no differing key omits the field. Computing this field changes no value in limits
Limit key metadata object
Section titled “Limit key metadata object”Display metadata for one limit key, which an editor uses to render its control.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| key | string | The limit key |
| label | string | Display label |
| description | string | Description of what the limit bounds |
| category | string | Category key, resolved against categories |
| scope | string | user, guild, or both |
| isToggle | boolean | Whether the key is a feature gate whose value is 0 or 1 |
| unit? | string | bytes or count |
| min? | number | Suggested minimum for an editor |
| max? | number | Suggested maximum for an editor |
Username policy object
Section titled “Username policy object”The stored username policy. It sets which short usernames people can select during username migration, which dictionary generation screens names, and how fast selections are admitted.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| revision | integer | Policy revision, raised by every accepted update |
| tiers1 | object | Mode of one-, two-, and three-character usernames, keyed 1, 2, and 3 |
| dictionary_gen | integer | The published username dictionary generation, 0 when none |
| dictionary_hash | ?string | SHA-256 hex digest of that generation, or null when none is published |
| next_dictionary_gen | integer | The generation number the next dictionary publication receives |
| admission2 | object | global_per_second, the selections admitted each second, and paused |
| held_manifest | ?array[string] | Usernames that must be held or admin-assigned before migration can start, or null |
1 Each value is locked, for_sale, or public. A stored policy starts with every tier locked
2 A stored policy starts paused with a budget of 0
Username migration state object
Section titled “Username migration state object”The instance username migration state. The public part is the username migration object of discovery.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| state | string | legacy, preparing, or selecting |
| epoch | integer | Migration generation, raised by every preparation |
| preparing_at | ?ISO8601 timestamp | When the current preparation began, or null in legacy |
| started_at | ?ISO8601 timestamp | When selection began, or null before selecting |
| forced_at | ?ISO8601 timestamp | The selection deadline, seven days after started_at, or null before selecting |
Username migration inspection object
Section titled “Username migration inspection object”The evidence Start username migration checks, read for the current epoch. A part that cannot be proven for that epoch is null or not ready.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| migration | username migration state object | The current migration state |
| scan1 | ?object | epoch, scanned, found, and done_at of the account scan, or null when none ran for this epoch |
| holds2 | object | required, ready, and proof for the held username manifest |
| capacity3 | object | available, ready, and proof for the declared guild capacity |
1 The scan counts accounts that still need a username. found must be 0 and done_at set before selection can start
2 proof records the policy revision, check time, and the held, assigned, and missing names
3 proof records the epoch, policy revision, account total, the latest guild capacity declaration, and the holds proof
Get instance configuration
Section titled “Get instance configuration”GET/v1/admin/instance/configReturns the instance configuration object. Requires instance:config:view, or a session credential until setup is marked complete.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | instance configuration object | Configuration was returned |
Side effects
Section titled “Side effects”The operation records one Admin audit entry with action get_instance_config, target type instance_config, target ID 0, and metadata keys registration_url_count and pending_registration_count. Before setup is complete, a session credential holding no Admin ACL records the entry with its own account as the acting Admin.
Rate limit
Section titled “Rate limit”200 requests per minute for each authenticated user, on the admin:lookup bucket.
Update instance configuration
Section titled “Update instance configuration”PATCH/v1/admin/instance/configApplies a merge patch to the stored configuration and returns the resulting instance configuration object. Requires instance:config:update, or a session credential until setup is marked complete.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| sso?1 | object | Every SSO configuration field except client_secret_set and redirect_uri, plus client_secret |
| gateway_rollout? | object | Any subset of the Gateway rollout configuration fields except game_activity_epoch, each bound as documented there |
| voice_noise_suppression? | object | Any subset of the voice noise suppression configuration fields |
| voice_room? | object | Any subset of the voice room fields except room_watch_enabled_at |
| push_relay? | object | relay_consent_accepted from the push relay configuration |
| domain_migration? | object | Any subset of the domain migration fields |
| plutonium_page? | object | Any subset of the Plutonium page fields |
| captcha? | object | Any subset of the captcha configuration fields |
| experiment_delivery? | object | Any subset of the experiment delivery fields |
| registration? | object | mode and admin_registration_urls_enabled |
| app_public?2 | object | branding, setup, legal, registration, and localization sub-objects, each merged field by field |
| integrations?3 | object | gif, youtube, email, and bluesky sub-objects, the last of which also has the keys array |
| media? | object | attachment_decay overrides, each nullable to restore the deployment default |
| policy? | instance policy update object | Community, direct message, premium, and gating policy |
| billing?4 | object | Stored instance billing fields, with stripe_secret_key and stripe_webhook_secret for the secrets |
| booster_role_enabled? | boolean | Whether a member who boosts a guild is given its booster role |
| badge_inventory_enabled? | boolean | Whether accounts can change badge visibility |
1 The supplied fields are merged over the stored configuration and the result is validated as a whole. Every supplied endpoint URL uses https, has no credentials and no fragment, and resolves to a publicly routable address, otherwise the request returns 400 INVALID_FORM_BODY with INVALID_URL_FORMAT or URL_NOT_PUBLICLY_ROUTABLE
2 branding.product_name is 1 to 80 characters, every branding and legal URL is at most 2048 characters and nullable, branding.theme_color is at most 64 characters and nullable, and setup.configured and registration.collect_date_of_birth are booleans. localization.default_locale is a supported locale or null, and localization.default_locale_time_zones is at most 32 IANA time zone names of at most 64 characters each. To clear default_locale, send it together with default_locale_time_zones; an object whose supplied values are all null is ignored. branding.premium_product_name is 1 to 40 characters, and null restores the default. branding.premium_info_url is an absolute http or https URL. Every string is trimmed before it is stored
push_relay takes only relay_consent_accepted. Micup sets relay_consent_accepted_at and relay_consent_accepted_by itself on the request that changes that flag, and accepts neither from a request. Turning the flag on stamps the current time and the acting account, and turning it off clears both to null. A request that repeats the flag it already holds leaves the stamp alone.
domain_migration takes every domain migration configuration field except config_version, each bound as documented there. Micup raises config_version by one on each request that supplies at least one of them. A section that is absent, or present with no field set, writes nothing and leaves config_version alone.
plutonium_page works the same way, over the Plutonium page configuration fields and its own config_version.
captcha takes any subset of the captcha configuration fields, each bound as documented there. Micup merges the supplied fields over the stored ones. The section has no config_version.
voice_room takes rooms_enabled, games_enabled, room_cameras_enabled, room_avatars_enabled, room_walk_enabled, and room_watch_enabled, each a boolean, default_room_theme, rollout_basis_points, rollout_salt, included_user_ids, and excluded_user_ids, each bound as documented there. It has no config_version, and a section with none of them writes nothing.
experiment_delivery takes both experiment delivery configuration fields, each bound as documented there. It is a section of its own, so a write to it changes no config_version and changes no assignment, only the cadence on which clients ask for one.
3 A secret such as klipy_api_key, api_key, or the SMTP password is written when supplied and left alone when absent. integrations.bluesky.keys is the only way to write the Bluesky signing keys counted as bluesky.key_count. It takes up to 8 entries of kid (1-255 characters) and nullable private_key (up to 10000 characters), and replaces the stored key set outright
4 Accepted only on a self-hosted deployment. A hosted deployment rejects the section, and app_public.branding.premium_product_name and premium_info_url, with 400 INVALID_FORM_BODY. A Stripe secret, enabled, automatic_tax, tax_id_collection and terms_consent_required are written when supplied, cleared by null, and left alone when absent. A null enabled follows FLUXER_STRIPE_ENABLED. prices, country_currencies, and legacy_prices replace the stored value outright, a price slot left out is stored as null, and an empty prices object restores the deployment catalogue. A price ID is price_ followed by letters and digits. A currency is three upper-case letters and a country code is two
booster_role_enabled and badge_inventory_enabled require instance:config:update even before setup is marked complete. Each is written when supplied and left alone when absent.
Instance policy update structure
Section titled “Instance policy update structure”| Field | Type | Description |
|---|---|---|
| single_community_enabled?1 | boolean | Whether the deployment presents one community |
| single_community_name?1 | string | Name used only when the community has to be created (1-100 characters) |
| direct_messages_disabled?2 | boolean | Whether direct messages are disabled |
| direct_messages_locked?2 | boolean | Whether the direct message setting stays locked |
| guild_create_access? | boolean | Whether every account can create communities |
| premium_mode? | string | Premium mode |
| premium_trial_days? | integer | Length in days of the one-time premium trial (0-30), where 0 turns the trial off |
| services? | object | Nullable gif_enabled, youtube_enabled, and bluesky_enabled overrides |
1 Setting single_community_enabled to true adopts the already designated guild when one still exists. When none is designated or the designated guild was deleted, it creates a community using single_community_name or the configured product name. When the stored guild ID is not a valid ID, or the guild lookup fails for a reason other than an unknown guild, the operation fails and Micup creates no community. On a deployment whose setup is already complete, enabling it while no guild is designated fails with 400 INSTANCE_POLICY_TRANSITION_NOT_ALLOWED, as does enabling it when the acting Admin account cannot be resolved. Setting it to false only clears the flag and leaves the guild in place
2 The setting can be changed only while direct_messages_locked is false, and a change attempted after the lock is set fails with 400 INSTANCE_POLICY_TRANSITION_NOT_ALLOWED unless the same request sets direct_messages_locked to false. Re-enabling direct messages sets the lock again
direct_messages_locked accepts only false, and a body that sets it to true fails with 400 INVALID_FORM_BODY.
On a self-hosted deployment, billing and the everyone premium mode exclude each other. A body that would leave billing switched on in everyone fails with 400 INVALID_FORM_BODY and writes nothing, whether it enables billing or switches the premium mode.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | instance configuration object | The patch was applied |
| 400 | error response | A policy transition is refused, returned as INSTANCE_POLICY_TRANSITION_NOT_ALLOWED |
Side effects
Section titled “Side effects”Micup publishes a gateway_rollout change to the Gateway cluster. A push_relay change reaches the push service without a restart. A billing change applies without a restart. Premium mode changes affect the limits in force without replacing the saved limit configuration. On self-hosted deployments, everyone hides premium-filtered rules. Switching back to mirror restores them unless an Admin has replaced the limit configuration in the meantime. Enabling single community mode creates the community when none is designated, with the acting Admin as owner.
Initial setup completes on the first update that sets app_public.setup.configured to true from a session credential whose account holds neither admin:authenticate nor the wildcard. That update grants the account the wildcard Admin ACL and marks the deployment as bootstrapped.
The operation records one Admin audit entry with action update_instance_config, target type instance_config, and target ID 0. The metadata key sections lists the names of the non-null top-level sections in the body, comma-separated in alphabetical order, and is absent when the body supplies none. The update that completes initial setup and grants the wildcard ACL also records granted_acls as *. No value from the body is recorded. A request that fails part way records no entry.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Create branding asset
Section titled “Create branding asset”POST/v1/admin/instance/config/branding-assetsUploads an image, stores its Media Proxy URL in the selected branding slot, and returns the resulting instance configuration object. Requires instance:config:update, or a session credential until setup is marked complete.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| kind | string | Branding asset kind naming the slot to write |
| image?1 2 | ?string | Base64 image or data URI (max 16000000 characters) |
1 Omitting the key and sending null both clear the slot
2 The image decodes to no more than the resolved avatar_max_size limit, which defaults to 10485760 bytes, and is a PNG, JPEG, WebP, GIF, APNG, AVIF, HEIC, HEIF, JXL, or SVG. An animated AVIF is refused
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | instance configuration object | The slot was written or cleared |
| 4001 | error response | The image cannot be decoded, exceeds the size ceiling, or is not an accepted format |
1 Returned as 400 INVALID_FORM_BODY with IMAGE_SIZE_EXCEEDS_LIMIT, INVALID_IMAGE_FORMAT, or FAILED_TO_UPLOAD_IMAGE against image
Side effects
Section titled “Side effects”The stored image is served through the Media Proxy. Non-JPEG images are re-encoded to strip metadata and JPEG images are re-encoded at quality 100. The previously referenced image is not deleted.
The operation records one Admin audit entry with action upload_branding_asset, target type instance_config, target ID 0, and metadata keys kind and cleared. cleared is true when the request cleared the slot.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Create SMTP test
Section titled “Create SMTP test”POST/v1/admin/instance/config/smtp-testsOpens a connection to the supplied SMTP server, authenticates against it, and reports the outcome as an SMTP test result object without storing anything. Requires instance:config:update, or a session credential until setup is marked complete.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| host | string | SMTP host to connect to (1-255 characters after trimming) |
| port | integer | SMTP port to connect to (1-65535) |
| username | string | SMTP username to authenticate with (1-320 characters after trimming) |
| password | string | SMTP password to authenticate with (1-4096 characters after trimming) |
| secure? | boolean | Whether to connect with implicit TLS (default true) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | SMTP test result object | The test ran to completion, including a rejected credential |
Side effects
Section titled “Side effects”No configuration is written and the supplied credentials are discarded when the request completes. The connection, greeting, and socket each have a ten-second deadline.
The operation records one Admin audit entry with action test_smtp_connection, target type instance_config, target ID 0, and metadata keys port, secure, and ok. The host, username, password, and failure text are not recorded.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Create registration URL
Section titled “Create registration URL”POST/v1/admin/instance/registration-urlsIssues a registration URL an Admin can hand out while the registration mode is closed or approval, and returns a registration URL creation object. Requires instance:config:update.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| label?1 | ?string | Admin note to attach to the URL (1-120 characters), or null for none |
| expires_at? | ?ISO8601 timestamp | Time the URL stops working, or null for a URL that never expires |
| max_uses? | ?integer | Maximum permitted uses (1-1000000), or null for unlimited use |
| approval_required? | boolean | Whether an account created through the URL still needs an Admin decision (default false) |
1 The label is trimmed before it is length checked, so a whitespace-only label fails body validation. Omit the key or send null for a URL with no label
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | registration URL creation object | The URL was issued |
Side effects
Section titled “Side effects”A newly issued URL has a use count of zero, no revocation time, and the acting Admin as its issuer. It is the first entry of registration.urls on the next configuration read. The operation changes no account.
The operation records one Admin audit entry with action create_registration_url, target type registration_url, target ID 0, and metadata key approval_required, plus max_uses when the body sets it. The label is not recorded. The entry has no registration URL identifier, because the identifier is the bearer code.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Revoke registration URL
Section titled “Revoke registration URL”DELETE/v1/admin/instance/registration-urls/{registration_url_id}Revokes one registration URL so it can no longer be redeemed and returns the resulting instance configuration object. Requires instance:config:update.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| registration_url_id | string | Identifier of the registration URL to revoke (1-128 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 2001 | instance configuration object | The revocation was applied |
1 An identifier naming no registration URL answers 200 with the configuration unchanged. Revoking an already revoked URL keeps the original revocation time
Side effects
Section titled “Side effects”The URL records its revocation time and stays in the configuration response afterwards. The operation changes no account.
The operation records one Admin audit entry with action revoke_registration_url, target type registration_url, target ID 0, and no metadata, including for an identifier that names no registration URL. The entry has no registration URL identifier, because the identifier is the bearer code.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Update pending registration
Section titled “Update pending registration”PATCH/v1/admin/instance/pending-registrations/{user_id}Approves or rejects one pending registration and returns the resulting instance configuration object. Requires instance:config:update.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| user_id | snowflake | Account awaiting a decision |
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| status | string | Either approved or rejected |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 2001 | instance configuration object | The decision was applied |
1 An account that no longer exists still answers 200. The pending registration is removed and no trait is written
Side effects
Section titled “Side effects”Approval removes both the registration_pending_approval trait and the registration_rejected trait, and joins the account to the single community when that mode is enabled and a guild is designated. A join that fails is logged and does not fail the request. Rejection removes the registration_pending_approval trait and adds the registration_rejected trait, which blocks login and every later session creation. A session issued before the decision stays valid. The pending registration is removed either way.
When the stored pending registration list fails validation, the request fails before Micup changes the account. A failure after Micup writes the account traits leaves those traits written and can leave the entry in the pending list. Check the account traits and the pending list before retrying.
One Admin audit entry with the action approve_registration or reject_registration targets the account and records the audit reason. It has no metadata, except for an account that no longer exists, whose entry has the metadata key account_found set to false.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Get limit configuration
Section titled “Get limit configuration”GET/v1/admin/limit-configReturns the limit configuration response object. Requires instance:limit_config:view.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | limit configuration response object | The configuration was returned |
Side effects
Section titled “Side effects”The response reflects the configuration in force on the node that serves the request, so two nodes can report different values while a change propagates.
The operation records one Admin audit entry with action get_limit_config, target type limit_config, target ID 0, and metadata key rule_count.
Rate limit
Section titled “Rate limit”200 requests per minute for each authenticated user, on the admin:lookup bucket.
Replace limit configuration
Section titled “Replace limit configuration”PUT/v1/admin/limit-configReplaces the stored limit configuration with the supplied document and returns the resulting limit configuration response object. Requires instance:limit_config:update.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| limit_config1 | limit configuration object | Complete replacement document |
1 traitDefinitions can be omitted and is then stored as an empty array. Every key inside a rule’s limits map is a known limit key and every value is a non-negative safe integer, otherwise the body fails validation. modifiedFields is not accepted on input and is recomputed
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | limit configuration response object | The configuration was replaced |
| 400 | error response | Body validation fails, including an unknown limit key, returned as INVALID_FORM_BODY |
Side effects
Section titled “Side effects”On a self-hosted deployment whose premium mode is everyone, Micup drops the premium trait definition and every rule filtered on the premium trait before storing the document.
Each rule’s modifiedFields is then recomputed and the merged document replaces the stored one. Every API node adopts the new configuration. Clients observe it through the published limit configuration.
The operation records one Admin audit entry with action update_limit_config, target type limit_config, target ID 0, and metadata keys rule_count, changed_rule_count, and trait_definition_count, each taken from the stored document. changed_rule_count is the number of rule identifiers added, removed, or stored with different filters or limits, compared with the configuration the serving node held before the write.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Get username migration
Section titled “Get username migration”GET/v1/admin/instance/username-migrationReturns the username migration inspection object. Requires username:migration:start.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | username migration inspection object | The evidence was read |
| 503 | error response | USERNAME_UNAVAILABLE, because evidence could not be read or changed during the read |
Side effects
Section titled “Side effects”A successful read records one Admin audit entry with action get_instance_config, target type username_migration, target ID 0, and metadata keys epoch and state. A 503 records nothing.
Rate limit
Section titled “Rate limit”200 requests per minute for each authenticated user, on the admin:lookup bucket.
Prepare username migration
Section titled “Prepare username migration”POST/v1/admin/instance/username-migration/prepareMoves the migration from legacy to preparing with a new epoch, starts the account scan, and returns the username migration state object. Requires username:migration:start and an audit reason.
Run it only after every API and worker process serves this version. A migration already preparing is returned unchanged, and a selecting migration cannot be prepared again.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| processes_ready | boolean | Must be true, confirming every process runs this version |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | username migration state object | The migration is preparing |
| 400 | error response | Body validation fails or the audit reason is missing |
Side effects
Section titled “Side effects”The operation records one Admin audit entry with action prepare_username_migration, target type username_migration, target ID 0, and metadata keys epoch, processes_ready, and preparing_at.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Start username migration
Section titled “Start username migration”POST/v1/admin/instance/username-migration/startMoves a preparing migration to selecting and returns the username migration state object, with forced_at seven days after started_at. Requires username:migration:start and an audit reason.
The server checks the published dictionary, the held username manifest, a finished scan of this epoch that found no account to fix, the preparation barrier, and the guild capacity declaration. A migration already selecting in the same epoch is returned unchanged.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| epoch | integer | The epoch being started, which must be the current one |
| mobile_published | boolean | Must be true, confirming the mobile release is published |
| mobile_version | string | The published mobile version (1-100 characters) |
| guild_capacity1 | object | max_guild_members, max_guild_online, source, and observed_at of the largest community |
1 max_guild_online cannot exceed max_guild_members, source holds 1-1000 characters, and observed_at must be less than an hour old
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | username migration state object | Selection started |
| 400 | error response | Body validation fails, the declaration is stale, or the audit reason is missing |
| 503 | error response | USERNAME_UNAVAILABLE, because the prerequisites could not be read |
Side effects
Section titled “Side effects”The operation records an Admin audit entry with action declare_username_migration_capacity before it stores the declaration, also for a start that then fails. A successful start records a second entry with action start_username_migration, target type username_migration, target ID 0, and metadata keys epoch, mobile_published, mobile_version, dictionary_gen, and the declaration fields.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Roll back username migration
Section titled “Roll back username migration”POST/v1/admin/instance/username-migration/rollbackReturns a preparing migration to legacy and returns the username migration state object. Requires username:migration:start and an audit reason. Only the current preparing epoch can be rolled back. A selecting migration cannot.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| epoch | integer | The current preparing epoch |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | username migration state object | The migration is legacy again |
| 400 | error response | Body validation fails or the audit reason is missing |
Side effects
Section titled “Side effects”The operation records one Admin audit entry with action rollback_username_migration, target type username_migration, target ID 0, and metadata key epoch.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Get bot system
Section titled “Get bot system”GET/v1/admin/instance/bot-systemReturns the bot system object, read straight from storage. Requires instance:config:view.
Unlike Get instance configuration, a session credential without an Admin ACL is refused even before setup is complete.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | bot system object | The lists were returned |
| 403 | error response | The caller lacks instance:config:view |
Side effects
Section titled “Side effects”The operation records one Admin audit entry with action get_bot_system, target type instance_config, target ID 0, and metadata keys official_count and community_count.
Rate limit
Section titled “Rate limit”200 requests per minute for each authenticated user, on the admin:lookup bucket.
Replace bot system
Section titled “Replace bot system”PUT/v1/admin/instance/bot-systemReplaces both lists of the bot system object and returns what was stored. Requires instance:config:update.
Unlike Update instance configuration, a session credential without an Admin ACL is refused even before setup is complete.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| official_apps | array[bot entry object] | Up to 20 Micup bots with unique application IDs |
| community_apps | array[bot entry object] | Up to 100 community bots with unique application IDs |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | bot system object | Both lists were replaced |
| 400 | error response | Body validation fails |
| 403 | error response | The caller lacks instance:config:update |
Validation fails when a list is too long, an ID repeats or is not a signed 64-bit snowflake, or a permission string has an unknown bit or ADMINISTRATOR. A body that fails validation changes nothing.
Side effects
Section titled “Side effects”The Micup list is written first, then the community list. A list equal to the stored one is not written. After a write, every API process refreshes its configuration and the bot catalog, and a community bot appears in the catalog within about 30 seconds.
The operation records one Admin audit entry with action update_bot_system, target type instance_config, target ID 0, and metadata keys official_count and community_count. For each list it adds official_added, official_removed, and official_permissions_changed, or the matching community_ keys, as comma-separated application IDs. A key with no IDs is left out. If the Micup list was written and the community write then fails, the entry carries only the official_ keys and official_count, adds failed_write set to community, and the request returns the error.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.
Get username policy
Section titled “Get username policy”GET/v1/admin/instance/username-policyReturns the username policy object. Requires instance:config:view.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | username policy object | The policy was returned |
Side effects
Section titled “Side effects”The operation records one Admin audit entry with action get_instance_config, target type username_policy, target ID 0, and metadata key revision.
Rate limit
Section titled “Rate limit”200 requests per minute for each authenticated user, on the admin:lookup bucket.
Update username policy
Section titled “Update username policy”PATCH/v1/admin/instance/username-policyReplaces all three tier modes together, optionally with the held manifest and admission, and returns the resulting username policy object. Requires instance:config:update and an audit reason.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| tiers | object | Mode of each tier, keyed 1, 2, and 3: locked, for_sale, or public |
| held_manifest? | array[string] | Up to 1000 distinct usernames that must be held or admin-assigned before migration starts |
| admission? | object | global_per_second, a non-negative integer, and paused |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | username policy object | The policy was replaced |
| 400 | error response | Body validation fails or the audit reason is missing |
Side effects
Section titled “Side effects”The operation records one Admin audit entry with action update_username_policy, target type username_policy, target ID 0, and metadata keys revision, tiers, admission, and held_manifest.
Rate limit
Section titled “Rate limit”100 requests per minute for each authenticated user, on the admin:user:modify bucket.