diff --git a/keyserver/src/responders/message-responders.js b/keyserver/src/responders/message-responders.js
--- a/keyserver/src/responders/message-responders.js
+++ b/keyserver/src/responders/message-responders.js
@@ -1,7 +1,7 @@
 // @flow
 
 import invariant from 'invariant';
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
 
 import { onlyOneEmojiRegex } from 'lib/shared/emojis.js';
 import {
@@ -23,11 +23,14 @@
   type SendEditMessageResponse,
   type FetchPinnedMessagesRequest,
   type FetchPinnedMessagesResult,
+  messageTruncationStatusesValidator,
+  rawMessageInfoValidator,
 } from 'lib/types/message-types.js';
 import type { EditMessageData } from 'lib/types/messages/edit.js';
 import type { ReactionMessageData } from 'lib/types/messages/reaction.js';
 import type { TextMessageData } from 'lib/types/messages/text.js';
 import { threadPermissions } from 'lib/types/thread-types.js';
+import { userInfosValidator } from 'lib/types/user-types.js';
 import { ServerError } from 'lib/utils/errors.js';
 import { values } from 'lib/utils/objects.js';
 import {
@@ -65,6 +68,10 @@
   text: t.String,
   sidebarCreation: t.maybe(t.Boolean),
 });
+
+export const sendMessageResponseValidator: TInterface<SendMessageResponse> =
+  tShape<SendMessageResponse>({ newMessageInfo: rawMessageInfoValidator });
+
 async function textMessageCreationResponder(
   viewer: Viewer,
   input: any,
@@ -118,6 +125,14 @@
   cursors: t.dict(t.String, t.maybe(t.String)),
   numberPerThread: t.maybe(t.Number),
 });
+
+export const fetchMessageInfosResponseValidator: TInterface<FetchMessageInfosResponse> =
+  tShape<FetchMessageInfosResponse>({
+    rawMessageInfos: t.list(rawMessageInfoValidator),
+    truncationStatuses: messageTruncationStatusesValidator,
+    userInfos: userInfosValidator,
+  });
+
 async function messageFetchResponder(
   viewer: Viewer,
   input: any,
@@ -305,6 +320,12 @@
   targetMessageID: t.String,
   text: t.String,
 });
+
+export const sendEditMessageResponseValidator: TInterface<SendEditMessageResponse> =
+  tShape<SendEditMessageResponse>({
+    newMessageInfos: t.list(rawMessageInfoValidator),
+  });
+
 async function editMessageCreationResponder(
   viewer: Viewer,
   input: any,
@@ -388,6 +409,12 @@
 const fetchPinnedMessagesResponderInputValidator = tShape({
   threadID: t.String,
 });
+
+export const fetchPinnedMessagesResultValidator: TInterface<FetchPinnedMessagesResult> =
+  tShape<FetchPinnedMessagesResult>({
+    pinnedMessages: t.list(rawMessageInfoValidator),
+  });
+
 async function fetchPinnedMessagesResponder(
   viewer: Viewer,
   input: any,
diff --git a/keyserver/src/responders/report-responders.js b/keyserver/src/responders/report-responders.js
--- a/keyserver/src/responders/report-responders.js
+++ b/keyserver/src/responders/report-responders.js
@@ -2,7 +2,7 @@
 
 import type { $Response, $Request } from 'express';
 import t from 'tcomb';
-import type { TStructProps } from 'tcomb';
+import type { TInterface, TStructProps } from 'tcomb';
 
 import {
   type ReportCreationResponse,
@@ -12,7 +12,9 @@
   type ThreadInconsistencyReportShape,
   type EntryInconsistencyReportShape,
   reportTypes,
+  reportInfoValidator,
 } from 'lib/types/report-types.js';
+import { userInfoValidator } from 'lib/types/user-types.js';
 import { ServerError } from 'lib/utils/errors.js';
 import {
   tShape,
@@ -131,6 +133,9 @@
   userInconsistencyReportCreationRequest,
 ]);
 
+export const reportCreationResponseValidator: TInterface<ReportCreationResponse> =
+  tShape<ReportCreationResponse>({ id: t.String });
+
 async function reportCreationResponder(
   viewer: Viewer,
   input: any,
@@ -203,6 +208,12 @@
   cursor: t.maybe(t.String),
 });
 
+export const fetchErrorReportInfosResponseValidator: TInterface<FetchErrorReportInfosResponse> =
+  tShape<FetchErrorReportInfosResponse>({
+    reports: t.list(reportInfoValidator),
+    userInfos: t.list(userInfoValidator),
+  });
+
 async function errorReportFetchInfosResponder(
   viewer: Viewer,
   input: any,
diff --git a/keyserver/src/responders/responder-validators.test.js b/keyserver/src/responders/responder-validators.test.js
--- a/keyserver/src/responders/responder-validators.test.js
+++ b/keyserver/src/responders/responder-validators.test.js
@@ -15,9 +15,24 @@
 } from './entry-responders.js';
 import { getSessionPublicKeysResponseValidator } from './keys-responders.js';
 import { messageReportCreationResultValidator } from './message-report-responder.js';
+import {
+  fetchMessageInfosResponseValidator,
+  fetchPinnedMessagesResultValidator,
+  sendEditMessageResponseValidator,
+  sendMessageResponseValidator,
+} from './message-responders.js';
 import { relationshipErrorsValidator } from './relationship-responders.js';
+import { reportCreationResponseValidator } from './report-responders.js';
 import { userSearchResultValidator } from './search-responders.js';
 import { siweNonceResponseValidator } from './siwe-nonce-responders.js';
+import {
+  changeThreadSettingsResultValidator,
+  leaveThreadResultValidator,
+  newThreadResponseValidator,
+  threadFetchMediaResultValidator,
+  threadJoinResultValidator,
+  toggleMessagePinResultValidator,
+} from './thread-responders.js';
 import {
   logInResponseValidator,
   registerResponseValidator,
@@ -617,3 +632,289 @@
     ).toBe(false);
   });
 });
+
+describe('thread responders', () => {
+  it('should validate change thread settings response', () => {
+    const response = {
+      updatesResult: {
+        newUpdates: [
+          {
+            type: 1,
+            id: '93601',
+            time: 1682759546258,
+            threadInfo: {
+              id: '92796',
+              type: 6,
+              name: '',
+              description: '',
+              color: 'b8753d',
+              creationTime: 1682076700918,
+              parentThreadID: '1',
+              members: [],
+              roles: {},
+              currentUser: {
+                role: '85172',
+                permissions: {},
+                subscription: {
+                  home: true,
+                  pushNotifs: true,
+                },
+                unread: false,
+              },
+              repliesCount: 0,
+              containingThreadID: '1',
+              community: '1',
+              pinnedCount: 0,
+            },
+          },
+        ],
+      },
+      newMessageInfos: [
+        {
+          type: 4,
+          threadID: '92796',
+          creatorID: '83928',
+          time: 1682759546275,
+          field: 'color',
+          value: 'b8753d',
+          id: '93602',
+        },
+      ],
+    };
+    expect(changeThreadSettingsResultValidator.is(response)).toBe(true);
+    expect(
+      changeThreadSettingsResultValidator.is({
+        ...response,
+        newMessageInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate leave thread response', () => {
+    const response = {
+      updatesResult: {
+        newUpdates: [
+          { type: 3, id: '93595', time: 1682759498811, threadID: '93561' },
+        ],
+      },
+    };
+    expect(leaveThreadResultValidator.is(response)).toBe(true);
+    expect(
+      leaveThreadResultValidator.is({
+        ...response,
+        updatedResult: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate new thread response', () => {
+    const response = {
+      newThreadID: '93619',
+      updatesResult: {
+        newUpdates: [
+          {
+            type: 4,
+            id: '93621',
+            time: 1682759805331,
+            threadInfo: {
+              id: '93619',
+              type: 5,
+              name: 'a',
+              description: '',
+              color: 'b8753d',
+              creationTime: 1682759805298,
+              parentThreadID: '92796',
+              members: [],
+              roles: {},
+              currentUser: {
+                role: '85172',
+                permissions: {},
+                subscription: {
+                  home: true,
+                  pushNotifs: true,
+                },
+                unread: false,
+              },
+              repliesCount: 0,
+              containingThreadID: '92796',
+              community: '1',
+              sourceMessageID: '93614',
+              pinnedCount: 0,
+            },
+            rawMessageInfos: [],
+            truncationStatus: 'exhaustive',
+            rawEntryInfos: [],
+          },
+        ],
+      },
+      userInfos: {
+        '256': { id: '256', username: 'ashoat' },
+        '83928': { id: '83928', username: 'temp_user3' },
+      },
+      newMessageInfos: [],
+    };
+    expect(newThreadResponseValidator.is(response)).toBe(true);
+    expect(
+      newThreadResponseValidator.is({
+        ...response,
+        newMessageInfos: {},
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate thread join response', () => {
+    const response = {
+      rawMessageInfos: [
+        {
+          type: 8,
+          threadID: '93619',
+          creatorID: '83928',
+          time: 1682759915935,
+          id: '93640',
+        },
+      ],
+      truncationStatuses: {},
+      userInfos: {
+        '256': { id: '256', username: 'ashoat' },
+        '83928': { id: '83928', username: 'temp_user3' },
+      },
+      updatesResult: {
+        newUpdates: [],
+      },
+    };
+    expect(threadJoinResultValidator.is(response)).toBe(true);
+    expect(
+      threadJoinResultValidator.is({
+        ...response,
+        updatesResult: [],
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate thread fetch media response', () => {
+    const response = {
+      media: [
+        {
+          type: 'photo',
+          id: '93642',
+          uri: 'http://0.0.0.0:3000/comm/upload/93642/1e0d7a5262952e3b',
+          dimensions: { width: 220, height: 220 },
+        },
+      ],
+    };
+    expect(threadFetchMediaResultValidator.is(response)).toBe(true);
+    expect(
+      threadFetchMediaResultValidator.is({ ...response, media: undefined }),
+    ).toBe(false);
+  });
+
+  it('should validate toggle message pin response', () => {
+    const response = { threadID: '123', newMessageInfos: [] };
+    expect(toggleMessagePinResultValidator.is(response)).toBe(true);
+    expect(
+      toggleMessagePinResultValidator.is({ ...response, threadID: undefined }),
+    ).toBe(false);
+  });
+});
+
+describe('message responders', () => {
+  it('should validate send message response', () => {
+    const response = {
+      newMessageInfo: {
+        type: 0,
+        threadID: '93619',
+        creatorID: '83928',
+        time: 1682761023640,
+        text: 'a',
+        localID: 'local3',
+        id: '93649',
+      },
+    };
+    expect(sendMessageResponseValidator.is(response)).toBe(true);
+    expect(
+      sendMessageResponseValidator.is({
+        ...response,
+        newMEssageInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate fetch message infos response', () => {
+    const response = {
+      rawMessageInfos: [
+        {
+          type: 0,
+          id: '83954',
+          threadID: '83938',
+          time: 1673561155110,
+          creatorID: '256',
+          text: 'welcome to Comm!',
+        },
+      ],
+      truncationStatuses: { '83938': 'exhaustive' },
+      userInfos: {
+        '256': { id: '256', username: 'ashoat' },
+        '83928': { id: '83928', username: 'temp_user3' },
+      },
+    };
+    expect(fetchMessageInfosResponseValidator.is(response)).toBe(true);
+    expect(
+      fetchMessageInfosResponseValidator.is({
+        ...response,
+        userInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate send edit message response', () => {
+    const response = {
+      newMessageInfos: [
+        {
+          type: 0,
+          id: '83954',
+          threadID: '83938',
+          time: 1673561155110,
+          creatorID: '256',
+          text: 'welcome to Comm!',
+        },
+      ],
+    };
+    expect(sendEditMessageResponseValidator.is(response)).toBe(true);
+    expect(
+      sendEditMessageResponseValidator.is({
+        ...response,
+        newMessageInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate fetch pinned message response', () => {
+    const response = {
+      pinnedMessages: [
+        {
+          type: 0,
+          id: '83954',
+          threadID: '83938',
+          time: 1673561155110,
+          creatorID: '256',
+          text: 'welcome to Comm!',
+        },
+      ],
+    };
+    expect(fetchPinnedMessagesResultValidator.is(response)).toBe(true);
+    expect(
+      fetchPinnedMessagesResultValidator.is({
+        ...response,
+        pinnedMessages: undefined,
+      }),
+    ).toBe(false);
+  });
+});
+
+describe('report responders', () => {
+  it('should validate report creation response', () => {
+    const response = { id: '123' };
+    expect(reportCreationResponseValidator.is(response)).toBe(true);
+    expect(reportCreationResponseValidator.is({})).toBe(false);
+  });
+});
diff --git a/keyserver/src/responders/thread-responders.js b/keyserver/src/responders/thread-responders.js
--- a/keyserver/src/responders/thread-responders.js
+++ b/keyserver/src/responders/thread-responders.js
@@ -1,8 +1,14 @@
 // @flow
 
 import t from 'tcomb';
-import type { TUnion } from 'tcomb';
+import type { TInterface, TUnion } from 'tcomb';
 
+import { rawEntryInfoValidator } from 'lib/types/entry-types.js';
+import { mediaValidator } from 'lib/types/media-types.js';
+import {
+  rawMessageInfoValidator,
+  messageTruncationStatusesValidator,
+} from 'lib/types/message-types.js';
 import {
   type ThreadDeletionRequest,
   type RoleChangeRequest,
@@ -20,7 +26,10 @@
   type ToggleMessagePinRequest,
   type ToggleMessagePinResult,
   threadTypes,
+  rawThreadInfoValidator,
 } from 'lib/types/thread-types.js';
+import { serverUpdateInfoValidator } from 'lib/types/update-types.js';
+import { userInfosValidator } from 'lib/types/user-types.js';
 import { updateUserAvatarRequestValidator } from 'lib/utils/avatar-utils.js';
 import { values } from 'lib/utils/objects.js';
 import {
@@ -28,6 +37,7 @@
   tNumEnum,
   tColor,
   tPassword,
+  tID,
 } from 'lib/utils/validation-utils.js';
 
 import {
@@ -53,6 +63,14 @@
   accountPassword: t.maybe(tPassword),
 });
 
+export const leaveThreadResultValidator: TInterface<LeaveThreadResult> =
+  tShape<LeaveThreadResult>({
+    threadInfos: t.maybe(t.dict(tID, rawThreadInfoValidator)),
+    updatesResult: tShape({
+      newUpdates: t.list(serverUpdateInfoValidator),
+    }),
+  });
+
 async function threadDeletionResponder(
   viewer: Viewer,
   input: any,
@@ -71,6 +89,16 @@
   }),
 });
 
+export const changeThreadSettingsResultValidator: TInterface<ChangeThreadSettingsResult> =
+  tShape<ChangeThreadSettingsResult>({
+    newMessageInfos: t.list(rawMessageInfoValidator),
+    threadInfo: t.maybe(rawThreadInfoValidator),
+    threadInfos: t.maybe(t.dict(tID, rawThreadInfoValidator)),
+    updatesResult: tShape({
+      newUpdates: t.list(serverUpdateInfoValidator),
+    }),
+  });
+
 async function roleUpdateResponder(
   viewer: Viewer,
   input: any,
@@ -154,6 +182,18 @@
     ...threadRequestValidationShape,
   }),
 ]);
+
+export const newThreadResponseValidator: TInterface<NewThreadResponse> =
+  tShape<NewThreadResponse>({
+    updatesResult: tShape({
+      newUpdates: t.list(serverUpdateInfoValidator),
+    }),
+    newMessageInfos: t.list(rawMessageInfoValidator),
+    newThreadInfo: t.maybe(rawThreadInfoValidator),
+    userInfos: userInfosValidator,
+    newThreadID: t.maybe(tID),
+  });
+
 async function threadCreationResponder(
   viewer: Viewer,
   input: any,
@@ -171,6 +211,19 @@
   calendarQuery: t.maybe(entryQueryInputValidator),
   inviteLinkSecret: t.maybe(t.String),
 });
+
+export const threadJoinResultValidator: TInterface<ThreadJoinResult> =
+  tShape<ThreadJoinResult>({
+    threadInfos: t.maybe(t.dict(tID, rawThreadInfoValidator)),
+    updatesResult: tShape({
+      newUpdates: t.list(serverUpdateInfoValidator),
+    }),
+    rawMessageInfos: t.list(rawMessageInfoValidator),
+    truncationStatuses: messageTruncationStatusesValidator,
+    userInfos: userInfosValidator,
+    rawEntryInfos: t.maybe(t.list(rawEntryInfoValidator)),
+  });
+
 async function threadJoinResponder(
   viewer: Viewer,
   input: any,
@@ -190,6 +243,10 @@
   limit: t.Number,
   offset: t.Number,
 });
+
+export const threadFetchMediaResultValidator: TInterface<ThreadFetchMediaResult> =
+  tShape<ThreadFetchMediaResult>({ media: t.list(mediaValidator) });
+
 async function threadFetchMediaResponder(
   viewer: Viewer,
   input: any,
@@ -203,6 +260,13 @@
   messageID: t.String,
   action: t.enums.of(['pin', 'unpin']),
 });
+
+export const toggleMessagePinResultValidator: TInterface<ToggleMessagePinResult> =
+  tShape<ToggleMessagePinResult>({
+    newMessageInfos: t.list(rawMessageInfoValidator),
+    threadID: tID,
+  });
+
 async function toggleMessagePinResponder(
   viewer: Viewer,
   input: any,
diff --git a/lib/types/report-types.js b/lib/types/report-types.js
--- a/lib/types/report-types.js
+++ b/lib/types/report-types.js
@@ -1,6 +1,7 @@
 // @flow
 
 import invariant from 'invariant';
+import t, { type TInterface } from 'tcomb';
 
 import { type PlatformDetails } from './device-types.js';
 import { type RawEntryInfo, type CalendarQuery } from './entry-types.js';
@@ -8,6 +9,7 @@
 import type { AppState, BaseAction } from './redux-types.js';
 import { type RawThreadInfo } from './thread-types.js';
 import type { UserInfo, UserInfos } from './user-types.js';
+import { tPlatformDetails, tShape } from '../utils/validation-utils.js';
 
 export type EnabledReports = {
   +crashReports: boolean,
@@ -188,6 +190,13 @@
   +creationTime: number,
 };
 
+export const reportInfoValidator: TInterface<ReportInfo> = tShape<ReportInfo>({
+  id: t.String,
+  viewerID: t.String,
+  platformDetails: tPlatformDetails,
+  creationTime: t.Number,
+});
+
 export type FetchErrorReportInfosRequest = {
   +cursor: ?string,
 };
diff --git a/lib/types/user-types.js b/lib/types/user-types.js
--- a/lib/types/user-types.js
+++ b/lib/types/user-types.js
@@ -1,6 +1,6 @@
 // @flow
 
-import t, { type TInterface } from 'tcomb';
+import t, { type TInterface, type TDict } from 'tcomb';
 
 import {
   type DefaultNotificationPayload,
@@ -45,6 +45,10 @@
   avatar: t.maybe(clientAvatarValidator),
 });
 export type UserInfos = { +[id: string]: UserInfo };
+export const userInfosValidator: TDict<UserInfos> = t.dict(
+  t.String,
+  userInfoValidator,
+);
 
 export type AccountUserInfo = {
   +id: string,