diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts
index 69e2f2504c..593ab208de 100644
--- a/packages/backend/src/server/api/endpoints/channels/create.ts
+++ b/packages/backend/src/server/api/endpoints/channels/create.ts
@@ -8,49 +8,10 @@ import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
 import { DI } from '@/di-symbols.js';
 import { ApiError } from '../../error.js';
 
-export const meta = {
-	tags: ['channels'],
-
-	requireCredential: true,
-
-	prohibitMoved: true,
-
-	kind: 'write:channels',
-
-	limit: {
-		duration: ms('1hour'),
-		max: 10,
-	},
-
-	res: {
-		type: 'object',
-		optional: false, nullable: false,
-		ref: 'Channel',
-	},
-
-	errors: {
-		noSuchFile: {
-			message: 'No such file.',
-			code: 'NO_SUCH_FILE',
-			id: 'cd1e9f3e-5a12-4ab4-96f6-5d0a2cc32050',
-		},
-	},
-} as const;
-
-export const paramDef = {
-	type: 'object',
-	properties: {
-		name: { type: 'string', minLength: 1, maxLength: 128 },
-		description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
-		bannerId: { type: 'string', format: 'misskey:id', nullable: true },
-		color: { type: 'string', minLength: 1, maxLength: 16 },
-	},
-	required: ['name'],
-} as const;
-
 // eslint-disable-next-line import/no-default-export
 @Injectable()
-export default class extends Endpoint<typeof meta, typeof paramDef> {
+export default class extends Endpoint<'channels/create'> {
+	name = 'channels/create' as const;
 	constructor(
 		@Inject(DI.driveFilesRepository)
 		private driveFilesRepository: DriveFilesRepository,
@@ -61,7 +22,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 		private idService: IdService,
 		private channelEntityService: ChannelEntityService,
 	) {
-		super(meta, paramDef, async (ps, me) => {
+		super(async (ps, me) => {
 			let banner = null;
 			if (ps.bannerId != null) {
 				banner = await this.driveFilesRepository.findOneBy({
@@ -70,7 +31,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 				});
 
 				if (banner == null) {
-					throw new ApiError(meta.errors.noSuchFile);
+					throw new ApiError(this.meta.errors.noSuchFile);
 				}
 			}
 
diff --git a/packages/backend/src/server/api/endpoints/channels/favorite.ts b/packages/backend/src/server/api/endpoints/channels/favorite.ts
index c8544273a1..77405da9eb 100644
--- a/packages/backend/src/server/api/endpoints/channels/favorite.ts
+++ b/packages/backend/src/server/api/endpoints/channels/favorite.ts
@@ -5,35 +5,10 @@ import { IdService } from '@/core/IdService.js';
 import { DI } from '@/di-symbols.js';
 import { ApiError } from '../../error.js';
 
-export const meta = {
-	tags: ['channels'],
-
-	requireCredential: true,
-
-	prohibitMoved: true,
-
-	kind: 'write:channels',
-
-	errors: {
-		noSuchChannel: {
-			message: 'No such channel.',
-			code: 'NO_SUCH_CHANNEL',
-			id: '4938f5f3-6167-4c04-9149-6607b7542861',
-		},
-	},
-} as const;
-
-export const paramDef = {
-	type: 'object',
-	properties: {
-		channelId: { type: 'string', format: 'misskey:id' },
-	},
-	required: ['channelId'],
-} as const;
-
 // eslint-disable-next-line import/no-default-export
 @Injectable()
-export default class extends Endpoint<typeof meta, typeof paramDef> {
+export default class extends Endpoint<'channels/favorite'> {
+	name = 'channels/favorite' as const;
 	constructor(
 		@Inject(DI.channelsRepository)
 		private channelsRepository: ChannelsRepository,
@@ -43,13 +18,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 
 		private idService: IdService,
 	) {
-		super(meta, paramDef, async (ps, me) => {
+		super(async (ps, me) => {
 			const channel = await this.channelsRepository.findOneBy({
 				id: ps.channelId,
 			});
 
 			if (channel == null) {
-				throw new ApiError(meta.errors.noSuchChannel);
+				throw new ApiError(this.meta.errors.noSuchChannel);
 			}
 
 			await this.channelFavoritesRepository.insert({
diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts
index 1a8d1164c7..095b8c6444 100644
--- a/packages/backend/src/server/api/endpoints/channels/featured.ts
+++ b/packages/backend/src/server/api/endpoints/channels/featured.ts
@@ -4,38 +4,17 @@ import type { ChannelsRepository } from '@/models/index.js';
 import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
 import { DI } from '@/di-symbols.js';
 
-export const meta = {
-	tags: ['channels'],
-
-	requireCredential: false,
-
-	res: {
-		type: 'array',
-		optional: false, nullable: false,
-		items: {
-			type: 'object',
-			optional: false, nullable: false,
-			ref: 'Channel',
-		},
-	},
-} as const;
-
-export const paramDef = {
-	type: 'object',
-	properties: {},
-	required: [],
-} as const;
-
 // eslint-disable-next-line import/no-default-export
 @Injectable()
-export default class extends Endpoint<typeof meta, typeof paramDef> {
+export default class extends Endpoint<'channels/featured'> {
+	name = 'channels/featured' as const;
 	constructor(
 		@Inject(DI.channelsRepository)
 		private channelsRepository: ChannelsRepository,
 
 		private channelEntityService: ChannelEntityService,
 	) {
-		super(meta, paramDef, async (ps, me) => {
+		super(async (ps, me) => {
 			const query = this.channelsRepository.createQueryBuilder('channel')
 				.where('channel.lastNotedAt IS NOT NULL')
 				.andWhere('channel.isArchived = FALSE')
diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts
index f3ca66cfd2..70a7e2ee16 100644
--- a/packages/backend/src/server/api/endpoints/channels/follow.ts
+++ b/packages/backend/src/server/api/endpoints/channels/follow.ts
@@ -6,35 +6,10 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
 import { DI } from '@/di-symbols.js';
 import { ApiError } from '../../error.js';
 
-export const meta = {
-	tags: ['channels'],
-
-	requireCredential: true,
-
-	prohibitMoved: true,
-
-	kind: 'write:channels',
-
-	errors: {
-		noSuchChannel: {
-			message: 'No such channel.',
-			code: 'NO_SUCH_CHANNEL',
-			id: 'c0031718-d573-4e85-928e-10039f1fbb68',
-		},
-	},
-} as const;
-
-export const paramDef = {
-	type: 'object',
-	properties: {
-		channelId: { type: 'string', format: 'misskey:id' },
-	},
-	required: ['channelId'],
-} as const;
-
 // eslint-disable-next-line import/no-default-export
 @Injectable()
-export default class extends Endpoint<typeof meta, typeof paramDef> {
+export default class extends Endpoint<'channels/follow'> {
+	name = 'channels/follow' as const;
 	constructor(
 		@Inject(DI.channelsRepository)
 		private channelsRepository: ChannelsRepository,
@@ -44,13 +19,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 
 		private idService: IdService,
 	) {
-		super(meta, paramDef, async (ps, me) => {
+		super(async (ps, me) => {
 			const channel = await this.channelsRepository.findOneBy({
 				id: ps.channelId,
 			});
 
 			if (channel == null) {
-				throw new ApiError(meta.errors.noSuchChannel);
+				throw new ApiError(this.meta.errors.noSuchChannel);
 			}
 
 			await this.channelFollowingsRepository.insert({
diff --git a/packages/backend/src/server/api/endpoints/channels/followed.ts b/packages/backend/src/server/api/endpoints/channels/followed.ts
index f49f3105d5..0868c482ee 100644
--- a/packages/backend/src/server/api/endpoints/channels/followed.ts
+++ b/packages/backend/src/server/api/endpoints/channels/followed.ts
@@ -5,37 +5,10 @@ import { QueryService } from '@/core/QueryService.js';
 import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
 import { DI } from '@/di-symbols.js';
 
-export const meta = {
-	tags: ['channels', 'account'],
-
-	requireCredential: true,
-
-	kind: 'read:channels',
-
-	res: {
-		type: 'array',
-		optional: false, nullable: false,
-		items: {
-			type: 'object',
-			optional: false, nullable: false,
-			ref: 'Channel',
-		},
-	},
-} as const;
-
-export const paramDef = {
-	type: 'object',
-	properties: {
-		sinceId: { type: 'string', format: 'misskey:id' },
-		untilId: { type: 'string', format: 'misskey:id' },
-		limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
-	},
-	required: [],
-} as const;
-
 // eslint-disable-next-line import/no-default-export
 @Injectable()
-export default class extends Endpoint<typeof meta, typeof paramDef> {
+export default class extends Endpoint<'channels/followed'> {
+	name = 'channels/followed' as const;
 	constructor(
 		@Inject(DI.channelFollowingsRepository)
 		private channelFollowingsRepository: ChannelFollowingsRepository,
@@ -43,7 +16,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 		private channelEntityService: ChannelEntityService,
 		private queryService: QueryService,
 	) {
-		super(meta, paramDef, async (ps, me) => {
+		super(async (ps, me) => {
 			const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder(), ps.sinceId, ps.untilId)
 				.andWhere({ followerId: me.id });
 
diff --git a/packages/misskey-js/src/endpoints.ts b/packages/misskey-js/src/endpoints.ts
index fb291a9a37..c34ecf1b1d 100644
--- a/packages/misskey-js/src/endpoints.ts
+++ b/packages/misskey-js/src/endpoints.ts
@@ -2593,6 +2593,153 @@ export const endpoints = {
 		}],
 	},
 	//#endregion
+
+	//#region channels
+	'channels/create': {
+		tags: ['channels'],
+	
+		requireCredential: true,
+	
+		prohibitMoved: true,
+	
+		kind: 'write:channels',
+	
+		limit: {
+			duration: ms('1hour'),
+			max: 10,
+		},
+
+		errors: {
+			noSuchFile: {
+				message: 'No such file.',
+				code: 'NO_SUCH_FILE',
+				id: 'cd1e9f3e-5a12-4ab4-96f6-5d0a2cc32050',
+			},
+		},
+
+		defines: [{
+			req: {
+				type: 'object',
+				properties: {
+					name: { type: 'string', minLength: 1, maxLength: 128 },
+					description: {
+						oneOf: [
+							{ type: 'string', minLength: 1, maxLength: 2048 },
+							{ type: 'null' },
+						],
+					},
+					bannerId: {
+						oneOf: [
+							{ type: 'string', format: 'misskey:id' },
+							{ type: 'null' },
+						],
+					},
+					color: { type: 'string', minLength: 1, maxLength: 16 },
+				},
+				required: ['name'],
+			},
+			res: {
+				$ref: 'https://misskey-hub.net/api/schemas/Channel',
+			}
+		}],
+	},
+	'channels/favorite': {
+		tags: ['channels'],
+	
+		requireCredential: true,
+	
+		prohibitMoved: true,
+	
+		kind: 'write:channels',
+	
+		errors: {
+			noSuchChannel: {
+				message: 'No such channel.',
+				code: 'NO_SUCH_CHANNEL',
+				id: '4938f5f3-6167-4c04-9149-6607b7542861',
+			},
+		},
+
+		defines: [{
+			req: {
+				type: 'object',
+				properties: {
+					channelId: { type: 'string', format: 'misskey:id' },
+				},
+				required: ['channelId'],
+			},
+			res: undefined,
+		}]
+	},
+	'channels/featured': {
+		tags: ['channels'],
+	
+		requireCredential: false,
+
+		defines: [{
+			req: undefined,
+			res: {
+				type: 'array',
+				items: {
+					$ref: 'https://misskey-hub.net/api/schemas/Channel',
+				},
+			},
+		}],
+	},
+	'channels/follow': {
+		tags: ['channels'],
+	
+		requireCredential: true,
+	
+		prohibitMoved: true,
+	
+		kind: 'write:channels',
+	
+		errors: {
+			noSuchChannel: {
+				message: 'No such channel.',
+				code: 'NO_SUCH_CHANNEL',
+				id: 'c0031718-d573-4e85-928e-10039f1fbb68',
+			},
+		},
+
+		defines: [{
+			req: {
+				type: 'object',
+				properties: {
+					channelId: { type: 'string', format: 'misskey:id' },
+				},
+				required: ['channelId'],
+			},
+			res: undefined,
+		}],
+	},
+	'channels/followed': {
+		tags: ['channels', 'account'],
+	
+		requireCredential: true,
+	
+		kind: 'read:channels',
+	
+		defines: [{
+			req: {
+				type: 'object',
+				properties: {
+					sinceId: { type: 'string', format: 'misskey:id' },
+					untilId: { type: 'string', format: 'misskey:id' },
+					limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
+				},
+				required: [],
+			},
+			res: {
+				type: 'array',
+				items: {
+					$ref: 'https://misskey-hub.net/api/schemas/Channel',
+				},
+			},
+		}],
+	},
+	//#endregion
 } as const satisfies { [x: string]: IEndpointMeta; };
 
 /**