diff --git a/keyserver/src/responders/entry-responders.js b/keyserver/src/responders/entry-responders.js
--- a/keyserver/src/responders/entry-responders.js
+++ b/keyserver/src/responders/entry-responders.js
@@ -4,28 +4,33 @@
 import type { TInterface } from 'tcomb';
 
 import { filteredThreadIDs } from 'lib/selectors/calendar-filter-selectors.js';
-import type {
-  CalendarQuery,
-  SaveEntryRequest,
-  CreateEntryRequest,
-  DeleteEntryRequest,
-  DeleteEntryResponse,
-  RestoreEntryRequest,
-  RestoreEntryResponse,
-  FetchEntryInfosResponse,
-  DeltaEntryInfosResult,
-  SaveEntryResponse,
+import {
+  type CalendarQuery,
+  type SaveEntryRequest,
+  type CreateEntryRequest,
+  type DeleteEntryRequest,
+  type DeleteEntryResponse,
+  type RestoreEntryRequest,
+  type RestoreEntryResponse,
+  type FetchEntryInfosResponse,
+  type DeltaEntryInfosResult,
+  type SaveEntryResponse,
+  rawEntryInfoValidator,
 } from 'lib/types/entry-types.js';
 import {
   type CalendarFilter,
   calendarThreadFilterTypes,
 } from 'lib/types/filter-types.js';
-import type {
-  FetchEntryRevisionInfosResult,
-  FetchEntryRevisionInfosRequest,
+import {
+  type FetchEntryRevisionInfosResult,
+  type FetchEntryRevisionInfosRequest,
+  historyRevisionInfoValidator,
 } from 'lib/types/history-types.js';
+import { rawMessageInfoValidator } from 'lib/types/message-types.js';
+import { serverCreateUpdatesResponseValidator } from 'lib/types/update-types.js';
+import { accountUserInfoValidator } from 'lib/types/user-types.js';
 import { ServerError } from 'lib/utils/errors.js';
-import { tString, tShape, tDate } from 'lib/utils/validation-utils.js';
+import { tString, tShape, tDate, tID } from 'lib/utils/validation-utils.js';
 
 import createEntry from '../creators/entry-creator.js';
 import { deleteEntry, restoreEntry } from '../deleters/entry-deleters.js';
@@ -123,6 +128,12 @@
   }
 }
 
+export const fetchEntryInfosResponseValidator: TInterface<FetchEntryInfosResponse> =
+  tShape<FetchEntryInfosResponse>({
+    rawEntryInfos: t.list(rawEntryInfoValidator),
+    userInfos: t.dict(t.String, accountUserInfoValidator),
+  });
+
 async function entryFetchResponder(
   viewer: Viewer,
   input: any,
@@ -140,6 +151,11 @@
   id: t.String,
 });
 
+export const fetchEntryRevisionInfosResultValidator: TInterface<FetchEntryRevisionInfosResult> =
+  tShape<FetchEntryRevisionInfosResult>({
+    result: t.list(historyRevisionInfoValidator),
+  });
+
 async function entryRevisionFetchResponder(
   viewer: Viewer,
   input: any,
@@ -160,6 +176,13 @@
   calendarQuery: t.maybe(newEntryQueryInputValidator),
 });
 
+export const saveEntryResponseValidator: TInterface<SaveEntryResponse> =
+  tShape<SaveEntryResponse>({
+    entryID: tID,
+    newMessageInfos: t.list(rawMessageInfoValidator),
+    updatesResult: serverCreateUpdatesResponseValidator,
+  });
+
 async function entryCreationResponder(
   viewer: Viewer,
   input: any,
@@ -195,6 +218,13 @@
   calendarQuery: t.maybe(newEntryQueryInputValidator),
 });
 
+export const deleteEntryResponseValidator: TInterface<DeleteEntryResponse> =
+  tShape<DeleteEntryResponse>({
+    newMessageInfos: t.list(rawMessageInfoValidator),
+    threadID: tID,
+    updatesResult: serverCreateUpdatesResponseValidator,
+  });
+
 async function entryDeletionResponder(
   viewer: Viewer,
   input: any,
@@ -211,6 +241,12 @@
   calendarQuery: t.maybe(newEntryQueryInputValidator),
 });
 
+export const restoreEntryResponseValidator: TInterface<RestoreEntryResponse> =
+  tShape<RestoreEntryResponse>({
+    newMessageInfos: t.list(rawMessageInfoValidator),
+    updatesResult: serverCreateUpdatesResponseValidator,
+  });
+
 async function entryRestorationResponder(
   viewer: Viewer,
   input: any,
@@ -220,6 +256,13 @@
   return await restoreEntry(viewer, request);
 }
 
+export const deltaEntryInfosResultValidator: TInterface<DeltaEntryInfosResult> =
+  tShape<DeltaEntryInfosResult>({
+    rawEntryInfos: t.list(rawEntryInfoValidator),
+    deletedEntryIDs: t.list(tID),
+    userInfos: t.list(accountUserInfoValidator),
+  });
+
 async function calendarQueryUpdateResponder(
   viewer: Viewer,
   input: any,
diff --git a/keyserver/src/responders/keys-responders.js b/keyserver/src/responders/keys-responders.js
--- a/keyserver/src/responders/keys-responders.js
+++ b/keyserver/src/responders/keys-responders.js
@@ -1,10 +1,13 @@
 // @flow
 
-import t from 'tcomb';
+import t, { type TUnion } from 'tcomb';
 
 import type { GetSessionPublicKeysArgs } from 'lib/types/request-types.js';
-import type { SessionPublicKeys } from 'lib/types/session-types.js';
-import { tShape } from 'lib/utils/validation-utils.js';
+import {
+  type SessionPublicKeys,
+  sessionPublicKeysValidator,
+} from 'lib/types/session-types.js';
+import { tShape, tNull } from 'lib/utils/validation-utils.js';
 
 import { fetchSessionPublicKeys } from '../fetchers/key-fetchers.js';
 import type { Viewer } from '../session/viewer.js';
@@ -14,10 +17,14 @@
   session: t.String,
 });
 
+type GetSessionPublicKeysResponse = SessionPublicKeys | null;
+export const getSessionPublicKeysResponseValidator: TUnion<GetSessionPublicKeysResponse> =
+  t.union([sessionPublicKeysValidator, tNull]);
+
 async function getSessionPublicKeysResponder(
   viewer: Viewer,
   input: any,
-): Promise<SessionPublicKeys | null> {
+): Promise<GetSessionPublicKeysResponse> {
   if (!viewer.loggedIn) {
     return null;
   }
diff --git a/keyserver/src/responders/message-report-responder.js b/keyserver/src/responders/message-report-responder.js
--- a/keyserver/src/responders/message-report-responder.js
+++ b/keyserver/src/responders/message-report-responder.js
@@ -1,11 +1,12 @@
 // @flow
 
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
 
 import {
   type MessageReportCreationRequest,
   type MessageReportCreationResult,
 } from 'lib/types/message-report-types.js';
+import { rawMessageInfoValidator } from 'lib/types/message-types.js';
 import { tShape } from 'lib/utils/validation-utils.js';
 
 import createMessageReport from '../creators/message-report-creator.js';
@@ -16,6 +17,9 @@
   messageID: t.String,
 });
 
+export const messageReportCreationResultValidator: TInterface<MessageReportCreationResult> =
+  tShape<MessageReportCreationResult>({ messageInfo: rawMessageInfoValidator });
+
 async function messageReportCreationResponder(
   viewer: Viewer,
   input: any,
diff --git a/keyserver/src/responders/relationship-responders.js b/keyserver/src/responders/relationship-responders.js
--- a/keyserver/src/responders/relationship-responders.js
+++ b/keyserver/src/responders/relationship-responders.js
@@ -1,6 +1,6 @@
 // @flow
 
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
 
 import {
   type RelationshipRequest,
@@ -18,6 +18,13 @@
   userIDs: t.list(t.String),
 });
 
+export const relationshipErrorsValidator: TInterface<RelationshipErrors> =
+  tShape<RelationshipErrors>({
+    invalid_user: t.maybe(t.list(t.String)),
+    already_friends: t.maybe(t.list(t.String)),
+    user_blocked: t.maybe(t.list(t.String)),
+  });
+
 async function updateRelationshipsResponder(
   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
@@ -1,5 +1,23 @@
 // @flow
 
+import {
+  setThreadUnreadStatusResult,
+  updateActivityResultValidator,
+} from 'lib/types/activity-types.js';
+
+import {
+  fetchEntryInfosResponseValidator,
+  fetchEntryRevisionInfosResultValidator,
+  saveEntryResponseValidator,
+  deleteEntryResponseValidator,
+  deltaEntryInfosResultValidator,
+  restoreEntryResponseValidator,
+} from './entry-responders.js';
+import { getSessionPublicKeysResponseValidator } from './keys-responders.js';
+import { messageReportCreationResultValidator } from './message-report-responder.js';
+import { relationshipErrorsValidator } from './relationship-responders.js';
+import { userSearchResultValidator } from './search-responders.js';
+import { siweNonceResponseValidator } from './siwe-nonce-responders.js';
 import {
   logInResponseValidator,
   registerResponseValidator,
@@ -331,3 +349,271 @@
     ).toBe(false);
   });
 });
+
+describe('search responder', () => {
+  it('should validate search response', () => {
+    const response = {
+      userInfos: [
+        { id: '83817', username: 'temp_user0' },
+        { id: '83853', username: 'temp_user1' },
+        { id: '83890', username: 'temp_user2' },
+        { id: '83928', username: 'temp_user3' },
+      ],
+    };
+
+    expect(userSearchResultValidator.is(response)).toBe(true);
+    response.userInfos.push({ id: 123 });
+    expect(userSearchResultValidator.is(response)).toBe(false);
+  });
+});
+
+describe('message report responder', () => {
+  it('should validate message report response', () => {
+    const response = {
+      messageInfo: {
+        type: 0,
+        threadID: '101113',
+        creatorID: '5',
+        time: 1682429699746,
+        text: 'text',
+        id: '101121',
+      },
+    };
+
+    expect(messageReportCreationResultValidator.is(response)).toBe(true);
+    response.messageInfo.type = -2;
+    expect(messageReportCreationResultValidator.is(response)).toBe(false);
+  });
+});
+
+describe('relationship responder', () => {
+  it('should validate relationship response', () => {
+    const response = {
+      invalid_user: ['83817', '83890'],
+      already_friends: ['83890'],
+    };
+
+    expect(relationshipErrorsValidator.is(response)).toBe(true);
+    expect(
+      relationshipErrorsValidator.is({ ...response, user_blocked: {} }),
+    ).toBe(false);
+  });
+});
+
+describe('activity responder', () => {
+  it('should validate update activity response', () => {
+    const response = { unfocusedToUnread: ['93095'] };
+    expect(updateActivityResultValidator.is(response)).toBe(true);
+    response.unfocusedToUnread.push(123);
+    expect(updateActivityResultValidator.is(response)).toBe(false);
+  });
+
+  it('should validate set thread unread response', () => {
+    const response = { resetToUnread: false };
+    expect(setThreadUnreadStatusResult.is(response)).toBe(true);
+    expect(setThreadUnreadStatusResult.is({ ...response, unread: false })).toBe(
+      false,
+    );
+  });
+});
+
+describe('keys responder', () => {
+  it('should validate get session public keys response', () => {
+    const response = {
+      identityKey: 'key',
+      oneTimeKey: 'key',
+    };
+
+    expect(getSessionPublicKeysResponseValidator.is(response)).toBe(true);
+    expect(getSessionPublicKeysResponseValidator.is(null)).toBe(true);
+    expect(
+      getSessionPublicKeysResponseValidator.is({
+        ...response,
+        identityKey: undefined,
+      }),
+    ).toBe(false);
+  });
+});
+
+describe('siwe nonce responders', () => {
+  it('should validate siwe nonce response', () => {
+    const response = { nonce: 'nonce' };
+    expect(siweNonceResponseValidator.is(response)).toBe(true);
+    expect(siweNonceResponseValidator.is({ nonce: 123 })).toBe(false);
+  });
+});
+
+describe('entry reponders', () => {
+  it('should validate entry fetch response', () => {
+    const response = {
+      rawEntryInfos: [
+        {
+          id: '92860',
+          threadID: '85068',
+          text: 'text',
+          year: 2023,
+          month: 4,
+          day: 2,
+          creationTime: 1682082939882,
+          creatorID: '83853',
+          deleted: false,
+        },
+      ],
+      userInfos: {
+        '123': {
+          id: '123',
+          username: 'username',
+        },
+      },
+    };
+    expect(fetchEntryInfosResponseValidator.is(response)).toBe(true);
+    expect(
+      fetchEntryInfosResponseValidator.is({
+        ...response,
+        userInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate entry revision fetch response', () => {
+    const response = {
+      result: [
+        {
+          id: '93297',
+          authorID: '83853',
+          text: 'text',
+          lastUpdate: 1682603494202,
+          deleted: false,
+          threadID: '83859',
+          entryID: '93270',
+        },
+        {
+          id: '93284',
+          authorID: '83853',
+          text: 'text',
+          lastUpdate: 1682603426996,
+          deleted: true,
+          threadID: '83859',
+          entryID: '93270',
+        },
+      ],
+    };
+    expect(fetchEntryRevisionInfosResultValidator.is(response)).toBe(true);
+    expect(
+      fetchEntryRevisionInfosResultValidator.is({
+        ...response,
+        result: {},
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate entry save response', () => {
+    const response = {
+      entryID: '93270',
+      newMessageInfos: [
+        {
+          type: 9,
+          threadID: '83859',
+          creatorID: '83853',
+          time: 1682603362817,
+          entryID: '93270',
+          date: '2023-04-03',
+          text: 'text',
+          id: '93272',
+        },
+      ],
+      updatesResult: { viewerUpdates: [], userInfos: [] },
+    };
+
+    expect(saveEntryResponseValidator.is(response)).toBe(true);
+    expect(
+      saveEntryResponseValidator.is({
+        ...response,
+        entryID: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate entry delete response', () => {
+    const response = {
+      threadID: '83859',
+      newMessageInfos: [
+        {
+          type: 11,
+          threadID: '83859',
+          creatorID: '83853',
+          time: 1682603427038,
+          entryID: '93270',
+          date: '2023-04-03',
+          text: 'text',
+          id: '93285',
+        },
+      ],
+      updatesResult: { viewerUpdates: [], userInfos: [] },
+    };
+    expect(deleteEntryResponseValidator.is(response)).toBe(true);
+    expect(
+      deleteEntryResponseValidator.is({
+        ...response,
+        threadID: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate entry restore response', () => {
+    const response = {
+      newMessageInfos: [
+        {
+          type: 11,
+          threadID: '83859',
+          creatorID: '83853',
+          time: 1682603427038,
+          entryID: '93270',
+          date: '2023-04-03',
+          text: 'text',
+          id: '93285',
+        },
+      ],
+      updatesResult: { viewerUpdates: [], userInfos: [] },
+    };
+    expect(restoreEntryResponseValidator.is(response)).toBe(true);
+    expect(
+      restoreEntryResponseValidator.is({
+        ...response,
+        newMessageInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+
+  it('should validate entry delta response', () => {
+    const response = {
+      rawEntryInfos: [
+        {
+          id: '92860',
+          threadID: '85068',
+          text: 'text',
+          year: 2023,
+          month: 4,
+          day: 2,
+          creationTime: 1682082939882,
+          creatorID: '83853',
+          deleted: false,
+        },
+      ],
+      deletedEntryIDs: ['92860'],
+      userInfos: [
+        {
+          id: '123',
+          username: 'username',
+        },
+      ],
+    };
+    expect(deltaEntryInfosResultValidator.is(response)).toBe(true);
+    expect(
+      deltaEntryInfosResultValidator.is({
+        ...response,
+        rawEntryInfos: undefined,
+      }),
+    ).toBe(false);
+  });
+});
diff --git a/keyserver/src/responders/search-responders.js b/keyserver/src/responders/search-responders.js
--- a/keyserver/src/responders/search-responders.js
+++ b/keyserver/src/responders/search-responders.js
@@ -1,11 +1,12 @@
 // @flow
 
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
 
 import type {
   UserSearchRequest,
   UserSearchResult,
 } from 'lib/types/search-types.js';
+import { globalAccountUserInfoValidator } from 'lib/types/user-types.js';
 import { tShape } from 'lib/utils/validation-utils.js';
 
 import { searchForUsers } from '../search/users.js';
@@ -16,6 +17,11 @@
   prefix: t.maybe(t.String),
 });
 
+export const userSearchResultValidator: TInterface<UserSearchResult> =
+  tShape<UserSearchResult>({
+    userInfos: t.list(globalAccountUserInfoValidator),
+  });
+
 async function userSearchResponder(
   viewer: Viewer,
   input: any,
diff --git a/keyserver/src/responders/siwe-nonce-responders.js b/keyserver/src/responders/siwe-nonce-responders.js
--- a/keyserver/src/responders/siwe-nonce-responders.js
+++ b/keyserver/src/responders/siwe-nonce-responders.js
@@ -1,11 +1,16 @@
 // @flow
 
 import { generateNonce } from 'siwe';
+import t, { type TInterface } from 'tcomb';
 
 import type { SIWENonceResponse } from 'lib/types/siwe-types.js';
+import { tShape } from 'lib/utils/validation-utils.js';
 
 import { createSIWENonceEntry } from '../creators/siwe-nonce-creator.js';
 
+export const siweNonceResponseValidator: TInterface<SIWENonceResponse> =
+  tShape<SIWENonceResponse>({ nonce: t.String });
+
 async function siweNonceResponder(): Promise<SIWENonceResponse> {
   const generatedNonce = generateNonce();
   await createSIWENonceEntry(generatedNonce);
diff --git a/lib/types/activity-types.js b/lib/types/activity-types.js
--- a/lib/types/activity-types.js
+++ b/lib/types/activity-types.js
@@ -1,5 +1,9 @@
 // @flow
 
+import t, { type TInterface } from 'tcomb';
+
+import { tID, tShape } from '../utils/validation-utils.js';
+
 export type ActivityUpdate = {
   +focus: boolean,
   +threadID: string,
@@ -13,6 +17,10 @@
 export type UpdateActivityResult = {
   +unfocusedToUnread: $ReadOnlyArray<string>,
 };
+export const updateActivityResultValidator: TInterface<UpdateActivityResult> =
+  tShape<UpdateActivityResult>({
+    unfocusedToUnread: t.list(tID),
+  });
 
 export type ActivityUpdateSuccessPayload = {
   +activityUpdates: $ReadOnlyArray<ActivityUpdate>,
@@ -32,6 +40,9 @@
 export type SetThreadUnreadStatusResult = {
   +resetToUnread: boolean,
 };
+export const setThreadUnreadStatusResult: TInterface<SetThreadUnreadStatusResult> =
+  tShape<SetThreadUnreadStatusResult>({ resetToUnread: t.Boolean });
+
 export type SetThreadUnreadStatusPayload = {
   ...SetThreadUnreadStatusResult,
   +threadID: string,
diff --git a/lib/types/history-types.js b/lib/types/history-types.js
--- a/lib/types/history-types.js
+++ b/lib/types/history-types.js
@@ -1,5 +1,9 @@
 // @flow
 
+import t, { type TInterface } from 'tcomb';
+
+import { tID, tShape } from '../utils/validation-utils.js';
+
 export type HistoryMode = 'day' | 'entry';
 
 export type HistoryRevisionInfo = {
@@ -11,6 +15,16 @@
   +deleted: boolean,
   +threadID: string,
 };
+export const historyRevisionInfoValidator: TInterface<HistoryRevisionInfo> =
+  tShape<HistoryRevisionInfo>({
+    id: tID,
+    entryID: tID,
+    authorID: t.String,
+    text: t.String,
+    lastUpdate: t.Number,
+    deleted: t.Boolean,
+    threadID: tID,
+  });
 
 export type FetchEntryRevisionInfosRequest = {
   +id: string,
diff --git a/lib/types/session-types.js b/lib/types/session-types.js
--- a/lib/types/session-types.js
+++ b/lib/types/session-types.js
@@ -1,5 +1,7 @@
 // @flow
 
+import t, { type TInterface } from 'tcomb';
+
 import type { LogInActionSource } from './account-types.js';
 import type { Shape } from './core.js';
 import type { CalendarQuery } from './entry-types.js';
@@ -9,6 +11,7 @@
   type CurrentUserInfo,
   type LoggedOutUserInfo,
 } from './user-types.js';
+import { tShape } from '../utils/validation-utils.js';
 
 export const cookieLifetime = 30 * 24 * 60 * 60 * 1000; // in milliseconds
 // Interval the server waits after a state check before starting a new one
@@ -107,3 +110,9 @@
   +identityKey: string,
   +oneTimeKey?: string,
 };
+
+export const sessionPublicKeysValidator: TInterface<SessionPublicKeys> =
+  tShape<SessionPublicKeys>({
+    identityKey: t.String,
+    oneTimeKey: t.maybe(t.String),
+  });
diff --git a/lib/types/update-types.js b/lib/types/update-types.js
--- a/lib/types/update-types.js
+++ b/lib/types/update-types.js
@@ -13,6 +13,7 @@
 import { type RawThreadInfo, rawThreadInfoValidator } from './thread-types.js';
 import {
   type UserInfo,
+  userInfoValidator,
   type UserInfos,
   type LoggedInUserInfo,
   loggedInUserInfoValidator,
@@ -400,6 +401,12 @@
   +userInfos: $ReadOnlyArray<UserInfo>,
 };
 
+export const serverCreateUpdatesResponseValidator: TInterface<ServerCreateUpdatesResponse> =
+  tShape<ServerCreateUpdatesResponse>({
+    viewerUpdates: t.list(serverUpdateInfoValidator),
+    userInfos: t.list(userInfoValidator),
+  });
+
 export type ClientCreateUpdatesResponse = {
   +viewerUpdates: $ReadOnlyArray<ClientUpdateInfo>,
   +userInfos: $ReadOnlyArray<UserInfo>,
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
@@ -25,6 +25,12 @@
   +username: string,
   +avatar?: ?ClientAvatar,
 };
+export const globalAccountUserInfoValidator: TInterface<GlobalAccountUserInfo> =
+  tShape<GlobalAccountUserInfo>({
+    id: t.String,
+    username: t.String,
+    avatar: t.maybe(clientAvatarValidator),
+  });
 
 export type UserInfo = {
   +id: string,
@@ -46,6 +52,13 @@
   +relationshipStatus?: UserRelationshipStatus,
   +avatar?: ?ClientAvatar,
 };
+export const accountUserInfoValidator: TInterface<AccountUserInfo> =
+  tShape<AccountUserInfo>({
+    id: t.String,
+    username: t.String,
+    relationshipStatus: t.maybe(userRelationshipStatusValidator),
+    avatar: t.maybe(clientAvatarValidator),
+  });
 
 export type UserStore = {
   +userInfos: UserInfos,
diff --git a/lib/utils/validation-utils.js b/lib/utils/validation-utils.js
--- a/lib/utils/validation-utils.js
+++ b/lib/utils/validation-utils.js
@@ -55,7 +55,7 @@
     return false;
   });
 }
-
+const tNull: TIrreducible<null> = t.irreducible('null', x => x === null);
 const tDate: TRegex = tRegex(/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/);
 const tColor: TRegex = tRegex(validHexColorRegex); // we don't include # char
 const tPlatform: TEnums = t.enums.of([
@@ -108,6 +108,7 @@
   tShape,
   tRegex,
   tNumEnum,
+  tNull,
   tDate,
   tColor,
   tPlatform,