diff --git a/lib/actions/link-actions.js b/lib/actions/link-actions.js
--- a/lib/actions/link-actions.js
+++ b/lib/actions/link-actions.js
@@ -4,6 +4,8 @@
   FetchInviteLinksResponse,
   InviteLinkVerificationRequest,
   InviteLinkVerificationResponse,
+  CreateOrUpdatePublicLinkRequest,
+  InviteLink,
 } from '../types/link-types.js';
 import type { CallServerEndpoint } from '../utils/call-server-endpoint.js';
 
@@ -47,9 +49,37 @@
     };
   };
 
+const createOrUpdatePublicLinkActionTypes = Object.freeze({
+  started: 'CREATE_OR_UPDATE_PUBLIC_LINK_STARTED',
+  success: 'CREATE_OR_UPDATE_PUBLIC_LINK_SUCCESS',
+  failed: 'CREATE_OR_UPDATE_PUBLIC_LINK_FAILED',
+});
+
+const createOrUpdatePublicLink =
+  (
+    callServerEndpoint: CallServerEndpoint,
+  ): ((request: CreateOrUpdatePublicLinkRequest) => Promise<InviteLink>) =>
+  async request => {
+    const response = await callServerEndpoint('create_or_update_public_link', {
+      name: request.name,
+      communityID: request.communityID,
+    });
+    return {
+      name: response.name,
+      primary: response.primary,
+      role: response.role,
+      communityID: response.communityID,
+      expirationTime: response.expirationTime,
+      limitOfUses: response.limitOfUses,
+      numberOfUses: response.numberOfUses,
+    };
+  };
+
 export {
   verifyInviteLinkActionTypes,
   verifyInviteLink,
   fetchPrimaryInviteLinkActionTypes,
   fetchPrimaryInviteLinks,
+  createOrUpdatePublicLinkActionTypes,
+  createOrUpdatePublicLink,
 };
diff --git a/lib/reducers/invite-links-reducer.js b/lib/reducers/invite-links-reducer.js
--- a/lib/reducers/invite-links-reducer.js
+++ b/lib/reducers/invite-links-reducer.js
@@ -1,6 +1,9 @@
 // @flow
 
-import { fetchPrimaryInviteLinkActionTypes } from '../actions/link-actions.js';
+import {
+  createOrUpdatePublicLinkActionTypes,
+  fetchPrimaryInviteLinkActionTypes,
+} from '../actions/link-actions.js';
 import type { InviteLinksStore } from '../types/link-types.js';
 import type { BaseAction } from '../types/redux-types.js';
 
@@ -19,6 +22,18 @@
     return {
       links,
     };
+  } else if (action.type === createOrUpdatePublicLinkActionTypes.success) {
+    const communityID = action.payload.communityID;
+    return {
+      ...state,
+      links: {
+        ...state.links,
+        [communityID]: {
+          ...state.links[communityID],
+          primaryLink: action.payload,
+        },
+      },
+    };
   }
   return state;
 }
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -38,6 +38,7 @@
 import type { LifecycleState } from './lifecycle-state-types.js';
 import type {
   FetchInviteLinksResponse,
+  InviteLink,
   InviteLinksStore,
   InviteLinkVerificationResponse,
 } from './link-types.js';
@@ -1081,6 +1082,22 @@
       +error: true,
       +payload: Error,
       +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'CREATE_OR_UPDATE_PUBLIC_LINK_STARTED',
+      +loadingInfo?: LoadingInfo,
+      +payload?: void,
+    }
+  | {
+      +type: 'CREATE_OR_UPDATE_PUBLIC_LINK_SUCCESS',
+      +payload: InviteLink,
+      +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'CREATE_OR_UPDATE_PUBLIC_LINK_FAILED',
+      +error: true,
+      +payload: Error,
+      +loadingInfo: LoadingInfo,
     };
 
 export type ActionPayload = ?(Object | Array<*> | $ReadOnlyArray<*> | string);