Instance¶
Discover a TEBHOS deployment's endpoints, enabled features, public configuration, and limits with one unauthenticated request.
Get instance discovery is the entry point of the API. A client that knows only the TEBHOS origin reads /.well-known/tebhos first, and that single response describes the API base URL, the Gateway WebSocket URL, the media base URL, the CAPTCHA provider, and the limits that apply to accounts and guilds.
The route is unauthenticated, and a credential changes nothing in the response. It is also exempt from the global rate limit when sent without an Authorization header.
Instance discovery object¶
The discovery document is the complete public description of one deployment. Every field listed here is always present.
Structure¶
| Field | Type | Description |
|---|---|---|
| api_code_version | integer | The version of the API contract this deployment serves. The current value is 1 |
| endpoints | instance endpoints object | Public service endpoints for this deployment |
| captcha | CAPTCHA configuration object | Public CAPTCHA configuration |
| features | instance features object | Deployment feature switches |
| gif | GIF provider object | The GIF provider and its attribution requirement |
| sso | SSO status object | Public single sign-on state |
| registration | registration policy object | Public registration policy |
| community | community policy object | Single-community and direct message policy |
| services | service availability object | Optional integration availability |
| limits | limit configuration object | Ordered limit rules and the traits the deployment declares |
| push | push configuration object | Public Web Push identity |
| app_public | public application configuration object | Branding, setup, legal, and registration-form configuration |
| version | string | The API server build version, for example 0.1.0 |
| gateway | ?string | The configured public Gateway URL, or null when none is configured. Prefer endpoints.gateway |
| cdn | ?string | The configured public base URL of uploaded files, or null when none is configured |
| experiments | object | Always an empty object; experiments are served by Experiments |
The last four fields are a compact legacy summary kept for older consumers. New clients read endpoints instead of gateway.
Example¶
{
"api_code_version": 1,
"version": "0.1.0",
"gateway": "wss://tebhos.com/ws",
"cdn": "https://cdn.tebhos.com",
"experiments": {},
"endpoints": {
"api": "https://tebhos.com/api",
"api_client": "https://tebhos.com/api",
"api_public": "https://tebhos.com/api",
"gateway": "wss://tebhos.com/ws",
"media": "https://tebhos.com/api/v1",
"static_cdn": "https://tebhos.com",
"marketing": "https://tebhos.com",
"admin": "https://admin.tebhos.com",
"invite": "https://tebhos.com",
"gift": "https://tebhos.com",
"webapp": "https://tebhos.com"
},
"captcha": {
"provider": "hcaptcha",
"hcaptcha_site_key": "00000000-0000-0000-0000-000000000000",
"turnstile_site_key": null
},
"features": {
"voice_enabled": true,
"stripe_enabled": true,
"payment_provider": "polar",
"self_hosted": true,
"presigned_attachment_uploads": true,
"emails_enabled": true,
"sms_enabled": false
},
"gif": {"provider": "klipy", "display_name": "KLIPY", "attribution_required": true},
"sso": {"enabled": false, "enforced": false, "display_name": null, "redirect_uri": "https://tebhos.com/auth/sso/callback"},
"registration": {"mode": "open", "admin_registration_urls_enabled": true},
"community": {"single_community": false, "single_community_guild_id": null, "direct_messages_disabled": false},
"services": {"gif_enabled": true, "youtube_enabled": false, "bluesky_enabled": false},
"limits": {"version": 1, "traitDefinitions": ["premium"], "rules": ["..."]},
"push": {"public_vapid_key": "BM4KrfS2..."},
"app_public": {
"branding": {"product_name": "TEBHOS", "icon_url": null, "symbol_url": null, "logo_url": null, "wordmark_url": null, "favicon_url": null, "theme_color": null},
"setup": {"configured": true, "admin_url": "https://admin.tebhos.com"},
"legal": {"terms_url": null, "privacy_url": null},
"registration": {"collect_date_of_birth": true}
}
}
The values above are illustrative. Always use the values the deployment actually returns.
Instance endpoints object¶
Each value is an absolute URL. Several endpoints can share one origin and differ only by path.
Structure¶
| Field | Type | Description |
|---|---|---|
| api | string | The API root. Append /v1 to get the REST base URL |
| api_client | string | Same value as api; the base the web app uses |
| api_public | string | Same value as api; the base a bot, library, or other third-party client uses |
| gateway | string | The Gateway WebSocket URL, with a ws or wss scheme |
| media | string | The base of the media routes (avatars, icons, banners, /files/...). This is the API v1 base itself, so an avatar URL is {media}/avatars/{user_id}/{hash}.{ext} |
| static_cdn | string | The base of static assets such as built-in emoji images |
| marketing | string | The marketing site base URL |
| admin | string | The administration panel base URL |
| invite | string | The base URL invite links are built on |
| gift | string | The base URL gift links are built on |
| webapp | string | The web application base URL |
invite and gift default to the web application URL unless the deployment configures separate domains.
Use a published endpoint exactly as published
A client MUST NOT upgrade a published http value to https, downgrade https after a failure, drop a port, or guess a hostname. A local development deployment publishes plain http and ws values with explicit ports.
CAPTCHA configuration object¶
Which CAPTCHA provider the deployment uses, and the site key a client needs to render its challenge.
Structure¶
| Field | Type | Description |
|---|---|---|
| provider | string | The active CAPTCHA provider |
| hcaptcha_site_key | ?string | The configured hCaptcha site key, or null |
| turnstile_site_key | ?string | The configured Turnstile site key, or null |
provider is hcaptcha when both the hCaptcha secret and site key are configured, otherwise turnstile when both Turnstile keys are configured, otherwise none. A site key can be present while provider is none, because the key is published whenever it is configured; branch on provider, not on the presence of a key.
CAPTCHA providers¶
| Value | Description |
|---|---|
| none | No CAPTCHA is required |
| hcaptcha | hCaptcha challenges gate the CAPTCHA-protected operations |
| turnstile | Cloudflare Turnstile challenges gate the CAPTCHA-protected operations |
The challenge handshake, including the X-Captcha-Token and X-Captcha-Type request headers, is described in CAPTCHA handling.
Instance features object¶
Deployment-wide switches a client reads before offering a feature.
Structure¶
| Field | Type | Description |
|---|---|---|
| voice_enabled | boolean | Whether voice and video (LiveKit) is configured |
| stripe_enabled | boolean | Whether paid Premium checkout is configured. The name is kept for client compatibility; the payment provider is always Polar |
| payment_provider | string | The payment provider, always polar. See Billing |
| self_hosted | boolean | Always true; every TEBHOS deployment is a single-tenant deployment |
| presigned_attachment_uploads | boolean | Whether uploads use presigned object-storage URLs (see Attachment uploads) |
| emails_enabled | boolean | Whether an email provider is configured |
| sms_enabled | boolean | Whether SMS delivery is available. While false, phone verification and SMS second factors cannot be used |
GIF provider object¶
The GIF provider and whether a client must show its attribution.
Structure¶
| Field | Type | Description |
|---|---|---|
| provider | string | Machine name of the provider, always klipy |
| display_name | string | Human-readable provider name, always KLIPY |
| attribution_required | boolean | Always true: a client that shows GIF results shows the provider attribution next to them |
A client reads services.gif_enabled to decide whether to offer the GIF picker at all.
Registration policy object¶
Who can register an account on this deployment.
Structure¶
| Field | Type | Description |
|---|---|---|
| mode | string | The registration mode |
| admin_registration_urls_enabled | boolean | Whether administrator-issued registration URLs are enabled in the admin panel |
Registration modes¶
| Value | Description |
|---|---|
| open | Anyone can register |
| approval | New accounts wait for administrator approval |
| closed | Public registration is closed |
The value reflects the setting stored by the administration panel. See Register an account for what the registration route itself checks.
Community policy object¶
Whether the deployment runs as one community, and whether direct messages are available.
Structure¶
| Field | Type | Description |
|---|---|---|
| single_community | boolean | Whether the deployment runs as one community |
| single_community_guild_id | ?snowflake | The community guild's ID, published only while single_community is true, otherwise null |
| direct_messages_disabled | boolean | Whether direct messages are disabled deployment-wide |
Service availability object¶
Whether each optional integration is available.
Structure¶
| Field | Type | Description |
|---|---|---|
| gif_enabled | boolean | Whether the GIF picker is available. Defaults to true when a GIF provider key is configured, and can be overridden by an administrator |
| youtube_enabled | boolean | Whether YouTube link enrichment is available. False unless an administrator enables it |
| bluesky_enabled | boolean | Whether Bluesky connections are available. False unless an administrator enables it; see Connections |
Push configuration object¶
The deployment's public Web Push identity.
Structure¶
| Field | Type | Description |
|---|---|---|
| public_vapid_key | ?string | The Web Push VAPID public key used when subscribing a browser to push notifications, or null when Web Push is not configured |
Limit configuration object¶
The ordered rules a client evaluates to work out the limits that apply to an account or a guild.
Structure¶
| Field | Type | Description |
|---|---|---|
| version | integer | The wire format version. 1 unless the stored configuration sets another value |
| traitDefinitions | array[string] | The trait names the deployment declares. The stock configuration declares premium |
| rules | array[limit rule object] | The rules to evaluate, in order |
The stock configuration has three rules: default (no filters, sets every limit key), premium (filtered on the premium trait), and very_large_guild (filtered on the VERY_LARGE_GUILD guild feature).
A client starts from the default rule, then applies each rule whose filters all match: every trait it names is one of the account's traits, and every guild feature it names is one of the guild's features. A matching rule's values replace the current ones for the keys it sets.
The operation enforces its own bound
The document lets a client show the right limits before it tries an operation. A request that exceeds a limit still fails with the operation's own documented error.
Limit rule object¶
One rule of the limit configuration.
Structure¶
| Field | Type | Description |
|---|---|---|
| id | string | The stable rule identifier |
| filters? | limit filters object | The traits and guild features that select the rule; absent when the rule always matches |
| limits | map[string, integer] | Values keyed by limit key |
A rule edited in the administration panel can carry extra bookkeeping members (for example modifiedFields). A client MUST ignore members it does not recognise.
Example¶
{
"id": "premium",
"filters": {"traits": ["premium"]},
"limits": {"feature_higher_video_quality": 1}
}
Limit filters object¶
The traits and guild features a limit rule requires.
Structure¶
| Field | Type | Description |
|---|---|---|
| traits? | array[string] | Trait names that must all be present |
| guildFeatures? | array[string] | Guild feature names that must all be present |
Limit keys¶
A key whose name begins with feature_ is a feature gate: 0 when the feature is unavailable and 1 when it is available. Every other key is a bound in the unit its description names. The defaults are the values of the stock default rule; a deployment can change them.
| Key | Default | Description |
|---|---|---|
| avatar_max_size | 10485760 | Maximum avatar upload size in bytes |
| emoji_max_size | 524288 | Maximum emoji upload size in bytes |
| sticker_max_size | 524288 | Maximum sticker upload size in bytes |
| feature_animated_avatar | 1 | Animated avatar uploads |
| feature_animated_banner | 1 | Animated banner uploads |
| feature_custom_discriminator | 1 | Custom discriminator selection |
| feature_custom_notification_sounds | 1 | Custom notification sounds |
| feature_early_access | 1 | Early access features |
| feature_global_expressions | 1 | Using expressions across all guilds |
| feature_higher_video_quality | 0 | Higher streaming quality (1 for the premium trait) |
| feature_per_guild_profiles | 1 | A different profile per guild |
| feature_voice_entrance_sounds | 1 | Playing a sound when joining voice |
| max_attachment_file_size | 524288000 | Maximum size of each attachment in bytes |
| max_attachments_per_message | 10 | Maximum attachments per message |
| max_bio_length | 320 | Maximum characters in a biography |
| max_bookmarks | 300 | Maximum saved messages |
| max_channels_per_category | 50 | Maximum channels per category |
| max_created_packs | 50 | Maximum expression packs an account can create |
| max_custom_backgrounds | 15 | Maximum custom profile backgrounds |
| max_embeds_per_message | 10 | Maximum embeds per message |
| max_favorite_meme_tags | 10 | Maximum tags per saved meme |
| max_favorite_memes | 500 | Maximum saved memes |
| max_group_dm_recipients | 50 | Maximum members of a group DM |
| max_group_dms_per_user | 150 | Maximum group DMs per account |
| max_guild_channels | 500 | Maximum channels per guild |
| max_guild_emojis | 500 | Maximum emojis per guild |
| max_guild_emojis_animated | 500 | Compatibility alias of max_guild_emojis |
| max_guild_emojis_animated_more | 500 | Compatibility alias of max_guild_emojis |
| max_guild_emojis_static | 500 | Compatibility alias of max_guild_emojis |
| max_guild_emojis_static_more | 500 | Compatibility alias of max_guild_emojis |
| max_guild_invites | 1000 | Maximum active invites per guild |
| max_guild_members | 1000000 | Maximum members per guild (10000000 with the VERY_LARGE_GUILD feature) |
| max_guild_roles | 250 | Maximum roles per guild |
| max_guild_stickers | 500 | Maximum stickers per guild |
| max_guild_stickers_more | 500 | Compatibility alias of max_guild_stickers |
| max_guilds | 200 | Maximum guilds an account can join |
| max_installed_packs | 50 | Maximum expression packs an account can install |
| max_message_length | 4000 | Maximum characters per message |
| max_pack_expressions | 200 | Maximum expressions per pack |
| max_private_channels_per_user | 250 | Maximum direct message channels per account |
| max_reactions_per_message | 30 | Maximum distinct reactions per message |
| max_relationships | 1000 | Maximum friends and blocks |
| max_users_per_message_reaction | 1000000 | Maximum users on one reaction |
| max_voice_message_duration | 1200 | Maximum voice message length in seconds |
| max_webhooks_per_channel | 15 | Maximum webhooks per channel |
| max_webhooks_per_guild | 1000 | Maximum webhooks per guild |
Public application configuration object¶
Branding, setup state, legal links, and registration-form settings a client reads before anyone signs in. The administration panel edits these values.
Structure¶
| Field | Type | Description |
|---|---|---|
| branding | public branding object | The instance identity |
| setup | public setup state object | Initial configuration state |
| legal | public legal configuration object | Legal document URLs |
| registration | public registration fields object | Registration form settings |
Public branding object¶
Structure¶
| Field | Type | Description |
|---|---|---|
| product_name | string | The instance name a client displays, TEBHOS unless changed |
| icon_url | ?string | Full application icon URL, or null |
| symbol_url | ?string | Compact application symbol URL, or null |
| logo_url | ?string | Application logo URL, or null |
| wordmark_url | ?string | Application wordmark URL, or null |
| favicon_url | ?string | Browser favicon URL, or null |
| theme_color | ?string | Browser theme colour, or null |
Public setup state object¶
Structure¶
| Field | Type | Description |
|---|---|---|
| configured | boolean | Whether initial deployment configuration is complete (default true) |
| admin_url | ?string | The administration panel URL, or null when none is configured |
Public legal configuration object¶
Structure¶
| Field | Type | Description |
|---|---|---|
| terms_url | ?string | Terms of service URL, or null |
| privacy_url | ?string | Privacy policy URL, or null |
Public registration fields object¶
Structure¶
| Field | Type | Description |
|---|---|---|
| collect_date_of_birth | boolean | Whether the registration form collects a date of birth (default true). Registration always requires birth_date |
Get instance discovery¶
GET /.well-known/tebhos
Returns the instance discovery object. Authentication is not required. The response has Cache-Control: no-cache, so a client revalidates it on each start; the web app uses version to notice a new deployment.
The path is under the v1 base: https://tebhos.com/api/v1/.well-known/tebhos.
Response¶
| Status | Body | Condition |
|---|---|---|
| 200 | instance discovery object | The discovery document was returned |
| 429 | error response | The route bucket denied the request |
Rate limit¶
60 requests per minute for each client, on the instance:info bucket. The client is identified by its Authorization header, or by its IP address when it sends none.
Example¶
Not supported on TEBHOS
TEBHOS serves no client geolocation route and no OpenAPI document. Use the discovery document above as the machine-readable description of a deployment.