diff --git a/assets/openapi.json b/assets/openapi.json
index 62f4cbaa7..cced6947f 100644
Binary files a/assets/openapi.json and b/assets/openapi.json differ
diff --git a/assets/schemas.json b/assets/schemas.json
index 678371708..fe58930aa 100644
Binary files a/assets/schemas.json and b/assets/schemas.json differ
diff --git a/scripts/schemaExclusions.json b/scripts/schemaExclusions.json
index 82e545ab0..3305a4e4b 100644
--- a/scripts/schemaExclusions.json
+++ b/scripts/schemaExclusions.json
@@ -31,7 +31,6 @@
"UpdateRouteResponse",
"MessagesSendAPIResponse",
"APIWebhook",
- "WebhookResponse",
"WebhookValidationResponse",
"MessageResponse",
"ConnectionSettingsResponse",
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index c9b7a5406..762eae171 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -78,7 +78,7 @@ router.get(
},
responses: {
200: {
- body: "PublicMessageArray",
+ body: "PublicMessageListResponse",
},
400: {
body: "APIErrorResponse",
diff --git a/src/api/routes/channels/#channel_id/messages/pins/index.ts b/src/api/routes/channels/#channel_id/messages/pins/index.ts
index 062084e58..1b1254b92 100644
--- a/src/api/routes/channels/#channel_id/messages/pins/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/pins/index.ts
@@ -165,7 +165,7 @@ router.get(
permission: ["READ_MESSAGE_HISTORY"],
responses: {
200: {
- body: "PublicMessageArray",
+ body: "PublicMessageListResponse",
},
400: {
body: "APIErrorResponse",
diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts
index 499e3a980..2169d05cc 100644
--- a/src/api/routes/channels/#channel_id/pins.ts
+++ b/src/api/routes/channels/#channel_id/pins.ts
@@ -166,7 +166,7 @@ router.get(
permission: ["READ_MESSAGE_HISTORY"],
responses: {
200: {
- body: "PublicMessageArray",
+ body: "PublicMessageListResponse",
},
400: {
body: "APIErrorResponse",
diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts
index d38e18d7c..a27e1cf28 100644
--- a/src/api/routes/channels/#channel_id/webhooks.ts
+++ b/src/api/routes/channels/#channel_id/webhooks.ts
@@ -34,7 +34,7 @@ router.get(
permission: "MANAGE_WEBHOOKS",
responses: {
200: {
- body: "WebhookArray",
+ body: "WebhookListResponse",
},
},
}),
diff --git a/src/api/routes/channels/preload-messages.ts b/src/api/routes/channels/preload-messages.ts
index 8b860bc98..f8b0d9a09 100644
--- a/src/api/routes/channels/preload-messages.ts
+++ b/src/api/routes/channels/preload-messages.ts
@@ -20,7 +20,7 @@ import { Request, Response, Router } from "express";
import { route } from "@spacebar/api/middlewares";
import { Message } from "@spacebar/database";
import { Config } from "@spacebar/util";
-import { PreloadMessagesRequestSchema, PublicMessageArray } from "@spacebar/schemas";
+import { PreloadMessagesRequestSchema, PublicMessageListResponse } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -30,7 +30,7 @@ router.post(
requestBody: "PreloadMessagesRequestSchema",
responses: {
200: {
- body: "PublicMessageArray",
+ body: "PublicMessageListResponse",
},
400: {
body: "APIErrorResponse",
@@ -62,7 +62,7 @@ router.post(
// https://docs.discord.food/resources/message#preload-messages - reactions are not included in the response
x.reactions = undefined;
return x;
- }) as unknown as PublicMessageArray;
+ }) as unknown as PublicMessageListResponse;
return res.status(200).send(filteredMessages);
},
diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts
index ba8f4b3b9..fabc48f96 100644
--- a/src/api/routes/guilds/#guild_id/members/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/index.ts
@@ -42,7 +42,7 @@ router.get(
},
responses: {
200: {
- body: "PublicMemberArray",
+ body: "PublicMemberListResponse",
},
403: {
body: "APIErrorResponse",
diff --git a/src/api/routes/guilds/#guild_id/webhooks.ts b/src/api/routes/guilds/#guild_id/webhooks.ts
index 3ae2ad7ee..bc9c91a53 100644
--- a/src/api/routes/guilds/#guild_id/webhooks.ts
+++ b/src/api/routes/guilds/#guild_id/webhooks.ts
@@ -31,7 +31,7 @@ router.get(
permission: "MANAGE_WEBHOOKS",
responses: {
200: {
- body: "WebhookArray",
+ body: "WebhookListResponse",
},
},
}),
diff --git a/src/api/routes/users/#user_id/index.ts b/src/api/routes/users/#user_id/index.ts
index 228c87bb2..bee48dcb9 100644
--- a/src/api/routes/users/#user_id/index.ts
+++ b/src/api/routes/users/#user_id/index.ts
@@ -27,7 +27,7 @@ router.get(
route({
responses: {
200: {
- body: "APIPublicUser",
+ body: "PublicUser",
},
},
}),
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index 2ed525e82..f58f87ff2 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -30,7 +30,7 @@ router.get(
route({
responses: {
200: {
- body: "APIPrivateUser",
+ body: "PrivateUser",
},
},
}),
diff --git a/src/schemas/api/channels/Webhook.ts b/src/schemas/api/channels/Webhook.ts
index 22f78946f..fcceb1a83 100644
--- a/src/schemas/api/channels/Webhook.ts
+++ b/src/schemas/api/channels/Webhook.ts
@@ -29,7 +29,7 @@ export interface WebhookCreateResponse {
hook: WebhookResponse;
}
-export type WebhookArray = WebhookResponse[];
+export type WebhookListResponse = WebhookResponse[];
export interface WebhookResponse {
id: Snowflake;
type: WebhookType;
diff --git a/src/schemas/api/guilds/Emoji.ts b/src/schemas/api/guilds/Emoji.ts
index b0b358fda..607434748 100644
--- a/src/schemas/api/guilds/Emoji.ts
+++ b/src/schemas/api/guilds/Emoji.ts
@@ -1,3 +1,21 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2026 Spacebar and Spacebar Contributors
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
import { Snowflake } from "../../Identifiers";
import { PartialUser } from "../users";
diff --git a/src/schemas/api/guilds/GuildScheduledEvents.ts b/src/schemas/api/guilds/GuildScheduledEvents.ts
new file mode 100644
index 000000000..11522da3f
--- /dev/null
+++ b/src/schemas/api/guilds/GuildScheduledEvents.ts
@@ -0,0 +1,24 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2026 Spacebar and Spacebar Contributors
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+import { Snowflake } from "../../Identifiers";
+
+export enum EventPrivacyLevel {
+ PUBLIC = 1,
+ GUILD_ONLY = 2,
+}
diff --git a/src/schemas/api/guilds/GuildSchema.ts b/src/schemas/api/guilds/GuildSchema.ts
index a4c671c8a..96bb97391 100644
--- a/src/schemas/api/guilds/GuildSchema.ts
+++ b/src/schemas/api/guilds/GuildSchema.ts
@@ -1,6 +1,6 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2025 Spacebar and Spacebar Contributors
+ Copyright (C) 2026 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
@@ -28,3 +28,36 @@ export interface IntegrationGuild {
name: string;
icon: string | null;
}
+
+export enum GuildVerificationLevel {
+ NONE = 0,
+ // Verified email
+ LOW = 1,
+ // Registered >5min ago
+ MEDIUM = 2,
+ // Member for >10min
+ HIGH = 3,
+ // Verified phone number
+ VERY_HIGH = 4,
+}
+
+export enum GuildNsfwLevel {
+ DEFAULT = 0,
+ EXPLICIT = 1,
+ SAFE = 2,
+ AGE_RESTRICTED = 3,
+}
+
+// Unlocked boost perk level
+export enum GuildPremiumTier {
+ NONE = 0,
+ TIER_1 = 1,
+ TIER_2 = 2,
+ TIER_3 = 3,
+}
+
+export enum GuildHubType {
+ DEFAULT = 0,
+ HIGH_SCHOOL = 1,
+ COLLEGE = 2,
+}
diff --git a/src/schemas/api/guilds/Invite.ts b/src/schemas/api/guilds/Invite.ts
new file mode 100644
index 000000000..35e458592
--- /dev/null
+++ b/src/schemas/api/guilds/Invite.ts
@@ -0,0 +1,88 @@
+/*
+ Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
+ Copyright (C) 2026 Spacebar and Spacebar Contributors
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+import { Snowflake } from "../../Identifiers";
+import { PartialUser } from "../users";
+import { GuildNsfwLevel, GuildPremiumTier, GuildVerificationLevel } from "./GuildSchema";
+import { GuildProfileResponse, PublicChannel, RoleColors } from "@spacebar/schemas";
+import { Role } from "@spacebar/database";
+
+export interface Invite {
+ code: string;
+ type: number;
+ channel: PublicChannel | null; // TODO: Figure out what fields this is *supposed* to have as it's labeled as "Partial channel object"
+ guild_id?: Snowflake;
+ guild?: InviteGuild;
+ profile?: GuildProfileResponse;
+ inviter?: PartialUser;
+ flags?: number;
+ target_type?: number;
+ target_user?: PartialUser;
+ // target_application?: PartialApplication; // TODO - voice activities
+ roles?: InviteRole[]; // TODO: This is labeled as "Partial role object", is this used anywhere else?
+ approximate_member_count?: number;
+ approximate_presence_count?: number;
+ expires_at: string | null;
+ // guild_scheduled_event?: GuildScheduledEvent; //TODO - scheduled events
+ new_member?: boolean;
+ show_verification_form?: boolean;
+ is_nickname_changeable?: boolean;
+ target_users_job_status?: InviteTargetUsersJob; // TODO
+}
+
+export interface InviteTargetUsersJob {
+ status: InviteTargetUsersJobStatus;
+ total_users: number;
+ processed_users: number;
+ created_at: Date | null;
+ completed_at: Date | null;
+ error_message: string | null;
+}
+
+export enum InviteTargetUsersJobStatus {
+ UNSPECIFIED = 0,
+ PROCESSING = 1,
+ COMPLETED = 2,
+ FAILED = 3,
+}
+
+export interface InviteGuild {
+ id: Snowflake;
+ name: string;
+ icon: string | null;
+ description: string | null;
+ banner: string | null;
+ splash: string | null;
+ verification_level: GuildVerificationLevel;
+ features: string[];
+ vanity_url_code: string | null;
+ premium_subscription_count?: number;
+ premium_tier: GuildPremiumTier;
+ nsfw: boolean;
+ nsfw_level: GuildNsfwLevel;
+}
+
+export interface InviteRole {
+ id: Snowflake;
+ name: string;
+ position: number;
+ color: number;
+ colors: RoleColors;
+ icon?: string | null;
+ unicode_emoji?: string | null;
+}
diff --git a/src/schemas/api/messages/Message.ts b/src/schemas/api/messages/Message.ts
index 8d736aa68..b340a8637 100644
--- a/src/schemas/api/messages/Message.ts
+++ b/src/schemas/api/messages/Message.ts
@@ -163,7 +163,7 @@ export interface MessageSnapshot {
};
}
-export type PublicMessageArray = PublicMessage[];
+export type PublicMessageListResponse = PublicMessage[];
export interface PublicMessage {
id: Snowflake;
channel_id: Snowflake;
diff --git a/src/schemas/api/users/Member.ts b/src/schemas/api/users/Member.ts
index f6778509e..691b085bc 100644
--- a/src/schemas/api/users/Member.ts
+++ b/src/schemas/api/users/Member.ts
@@ -116,4 +116,4 @@ export type PublicMember = Omit, "roles"> & {
roles: string[]; // only role ids not objects
};
-export type PublicMemberArray = PublicMember[];
+export type PublicMemberListResponse = PublicMember[];
diff --git a/src/schemas/responses/TypedResponses.ts b/src/schemas/responses/TypedResponses.ts
index e43114201..b37c4b741 100644
--- a/src/schemas/responses/TypedResponses.ts
+++ b/src/schemas/responses/TypedResponses.ts
@@ -21,17 +21,15 @@ import { GeneralConfiguration, LimitsConfiguration } from "../../util/config/typ
import { DmChannelDTO } from "../../util/dtos";
// TODO: remove entity imports
import { Application, Categories, Channel, Guild, Invite, Template } from "@spacebar/database";
-import { GuildCreateResponse, PrivateUser, PublicUser } from "@spacebar/schemas";
+import { GuildCreateResponse, PrivateUser } from "@spacebar/schemas";
// TODO: remove this entire file!
// removes internal properties from the guild class
export type APIGuild = Omit;
-export type APIPublicUser = PublicUser;
-export type APIPrivateUser = PrivateUser;
export type APIGuildArray = APIGuild[];
export type APIDMChannelArray = DmChannelDTO[];
-export interface UserUpdateResponse extends APIPrivateUser {
+export interface UserUpdateResponse extends PrivateUser {
newToken?: string;
}