diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap
index 18663275..e4330bd4 100644
--- a/__tests__/__snapshots__/index.js.snap
+++ b/__tests__/__snapshots__/index.js.snap
@@ -303,7 +303,6 @@ Object {
       "default": undefined,
       "getService": [Function],
       "normalizeChallenge": [Function],
-      "normalizeChallengeDetails": [Function],
     },
     "communities": Object {
       "default": undefined,
diff --git a/docs/services.challenges.md b/docs/services.challenges.md
index bf0c48d9..0ef01ac2 100644
--- a/docs/services.challenges.md
+++ b/docs/services.challenges.md
@@ -18,7 +18,7 @@ This module provides a service for convenient manipulation with
             * [.close(challengeId, winnerId)](#module_services.challenges..ChallengesService+close) ⇒ <code>Promise</code>
             * [.createTask(projectId, accountId, title, description, assignee, payment)](#module_services.challenges..ChallengesService+createTask) ⇒ <code>Promise</code>
             * [.getChallengeDetails(challengeId)](#module_services.challenges..ChallengesService+getChallengeDetails) ⇒ <code>Promise</code>
-            * [.getChallengeSubtracks()](#module_services.challenges..ChallengesService+getChallengeSubtracks) ⇒ <code>Promise</code>
+            * [.getChallengeTypes()](#module_services.challenges..ChallengesService+getChallengeTypes) ⇒ <code>Promise</code>
             * [.getChallengeTags()](#module_services.challenges..ChallengesService+getChallengeTags) ⇒ <code>Promise</code>
             * [.getChallenges(filters, params)](#module_services.challenges..ChallengesService+getChallenges) ⇒ <code>Promise</code>
             * [.getMarathonMatches(filters, params)](#module_services.challenges..ChallengesService+getMarathonMatches) ⇒ <code>Promise</code>
@@ -119,7 +119,7 @@ Challenge service.
     * [.close(challengeId, winnerId)](#module_services.challenges..ChallengesService+close) ⇒ <code>Promise</code>
     * [.createTask(projectId, accountId, title, description, assignee, payment)](#module_services.challenges..ChallengesService+createTask) ⇒ <code>Promise</code>
     * [.getChallengeDetails(challengeId)](#module_services.challenges..ChallengesService+getChallengeDetails) ⇒ <code>Promise</code>
-    * [.getChallengeSubtracks()](#module_services.challenges..ChallengesService+getChallengeSubtracks) ⇒ <code>Promise</code>
+    * [.getChallengeTypes()](#module_services.challenges..ChallengesService+getChallengeTypes) ⇒ <code>Promise</code>
     * [.getChallengeTags()](#module_services.challenges..ChallengesService+getChallengeTags) ⇒ <code>Promise</code>
     * [.getChallenges(filters, params)](#module_services.challenges..ChallengesService+getChallenges) ⇒ <code>Promise</code>
     * [.getMarathonMatches(filters, params)](#module_services.challenges..ChallengesService+getMarathonMatches) ⇒ <code>Promise</code>
@@ -203,9 +203,9 @@ incorrect in the main v3 endpoint. This may change in the future.
 | --- | --- |
 | challengeId | <code>Number</code> \| <code>String</code> | 
 
-<a name="module_services.challenges..ChallengesService+getChallengeSubtracks"></a>
+<a name="module_services.challenges..ChallengesService+getChallengeTypes"></a>
 
-#### challengesService.getChallengeSubtracks() ⇒ <code>Promise</code>
+#### challengesService.getChallengeTypes() ⇒ <code>Promise</code>
 Gets possible challenge subtracks.
 
 **Kind**: instance method of [<code>ChallengesService</code>](#module_services.challenges..ChallengesService)  
diff --git a/src/actions/member-tasks.js b/src/actions/member-tasks.js
index b82d5bb7..9b9496a7 100644
--- a/src/actions/member-tasks.js
+++ b/src/actions/member-tasks.js
@@ -62,8 +62,8 @@ function getDone(uuid, projectId, pageNum, tokenV3) {
     isTask: 1,
     projectId,
   }, {
-    limit: PAGE_SIZE,
-    offset: pageNum * PAGE_SIZE,
+    perPage: PAGE_SIZE,
+    page: pageNum + 1,
   }).then(({ challenges, totalCount }) => ({
     projectId,
     tasks: challenges,
diff --git a/src/actions/members.js b/src/actions/members.js
index 1a500cb5..45b9606a 100644
--- a/src/actions/members.js
+++ b/src/actions/members.js
@@ -144,7 +144,7 @@ async function getActiveChallengesInit(handle, uuid) {
  * @returns {Object} Payload
  */
 async function getActiveChallengesDone(handle, uuid, tokenV3) {
-  const filter = { status: 'ACTIVE' };
+  const filter = { status: 'Active' };
   const service = getChallengesService(tokenV3);
   /* TODO: Reuse `getAll` from `actions/challenge-listing`
   /* after it moved from `community-app` to here.
@@ -152,8 +152,8 @@ async function getActiveChallengesDone(handle, uuid, tokenV3) {
   function getAll(getter, page = 0, prev = null) {
     const PAGE_SIZE = 50;
     return getter({
-      limit: PAGE_SIZE,
-      offset: page * PAGE_SIZE,
+      perPage: PAGE_SIZE,
+      page: page + 1,
     }).then(({ challenges: chunk }) => {
       if (!chunk.length) return prev || [];
       return getAll(getter, 1 + page, prev ? prev.concat(chunk) : chunk);
@@ -247,7 +247,7 @@ async function getSubtrackChallengesDone(
   refresh,
 ) {
   const filter = {
-    status: 'completed',
+    status: 'Completed',
     hasUserSubmittedForReview: 'true',
     track,
     subTrack,
diff --git a/src/actions/stats.js b/src/actions/stats.js
index 44612dcd..f9048b29 100644
--- a/src/actions/stats.js
+++ b/src/actions/stats.js
@@ -42,7 +42,7 @@ async function getCommunityStatsDone(community, uuid, challenges, token) {
     /* TODO: At the moment, this component loads challenge objects to calculate
     * the number of challenges and the total prize. Probably in future, we'll
     * have a special API to get these data. */
-    let filtered = challenges.filter(x => x.status === 'ACTIVE');
+    let filtered = challenges.filter(x => x.status === 'Active');
     if (community.challengeFilter) {
       const filterFunction = Filter.getFilterFunction(community.challengeFilter);
       filtered = filtered.filter(filterFunction);
diff --git a/src/reducers/challenge.js b/src/reducers/challenge.js
index b2edf441..26cee382 100644
--- a/src/reducers/challenge.js
+++ b/src/reducers/challenge.js
@@ -462,7 +462,7 @@ export function factory(options = {}) {
       const checkpointsPromise = track === 'design' ? (
         redux.resolveAction(actions.challenge.fetchCheckpointsDone(tokens.tokenV2, challengeId))
       ) : null;
-      const resultsPromise = _.get(details, 'payload.status', '') === 'COMPLETED' ? (
+      const resultsPromise = _.get(details, 'payload.status', '') === 'Completed' ? (
         redux.resolveAction(actions.challenge.loadResultsDone(tokens, challengeId, track))
       ) : null;
       return Promise.all([details, checkpointsPromise, resultsPromise]);
diff --git a/src/services/__mocks__/challenges.js b/src/services/__mocks__/challenges.js
index f881884e..0dc59e7c 100644
--- a/src/services/__mocks__/challenges.js
+++ b/src/services/__mocks__/challenges.js
@@ -134,7 +134,7 @@ export function normalizeChallengeDetails(v3, v3Filtered, v3User, v2, username)
   // Fill some derived data
   const registrationOpen = _.some(
     challenge.allPhases,
-    phase => phase.phaseType === 'Registration' && phase.phaseStatus === 'Open',
+    phase => phase.name === 'Registration' && phase.isOpen,
   ) ? 'Yes' : 'No';
   _.defaults(challenge, {
     communities: new Set([COMPETITION_TRACKS[challenge.track]]),
@@ -163,7 +163,7 @@ export function normalizeChallengeDetails(v3, v3Filtered, v3User, v2, username)
  * @return {Object} Normalized challenge.
  */
 export function normalizeChallenge(challenge, username) {
-  const registrationOpen = challenge.allPhases.filter(d => d.phaseType === 'Registration')[0].phaseStatus === 'Open' ? 'Yes' : 'No';
+  const registrationOpen = challenge.allPhases.filter(d => d.name === 'Registration')[0].isOpen ? 'Yes' : 'No';
   const groups = {};
   if (challenge.groupIds) {
     challenge.groupIds.forEach((id) => {
@@ -250,10 +250,10 @@ class ChallengesService {
   }
 
   /**
-   * Gets possible challenge subtracks.
-   * @return {Promise} Resolves to the array of subtrack names.
+   * Gets possible challenge types.
+   * @return {Promise} Resolves to the array of challenge type names.
    */
-  getChallengeSubtracks() {
+  getChallengeTypes() {
     return Promise.all([
       this.private.apiV2.get('/design/challengetypes')
         .then(res => (res.ok ? res.json() : new Error(res.statusText))),
diff --git a/src/services/challenges.js b/src/services/challenges.js
index 53ae2f0a..a7cdaf3f 100644
--- a/src/services/challenges.js
+++ b/src/services/challenges.js
@@ -18,150 +18,6 @@ export const ORDER_BY = {
   SUBMISSION_END_DATE: 'submissionEndDate',
 };
 
-/**
- * Normalizes a regular challenge details object received from the backend APIs.
- * @todo Why this one is exported? It should be only used internally!
- * @param {Object} challenge Challenge object received from the /challenges/{id}
- *  endpoint.
- * @param {Object} filtered Challenge object received from the
- *  /challenges?filter=id={id} endpoint.
- * @param {Object} user Challenge object received from the
- *  /members/{username}/challenges?filter=id={id} endpoint.
- * If action was fired for authenticated visitor, `user` will contain
- * details fetched specifically for the user (thus may include additional
- * data comparing to the standard API response for the challenge details,
- * stored in `filtered`).
- * @param {String} username Optional.
- * @return {Object} Normalized challenge object.
- */
-export function normalizeChallengeDetails(challenge, filtered, user, username) {
-  // Normalize exising data to make it consistent with the rest of the code
-  const finalChallenge = {
-    ...challenge,
-
-    id: challenge.challengeId,
-    reliabilityBonus: _.get(filtered, 'reliabilityBonus', 0),
-    status: (challenge.currentStatus || '').toUpperCase(),
-
-    allPhases: [],
-    currentPhases: [],
-    name: challenge.challengeName || challenge.challengeTitle,
-    projectId: Number(challenge.projectId),
-    forumId: Number(challenge.forumId),
-    introduction: challenge.introduction || '',
-    detailedRequirements: challenge.detailedRequirements === 'null' ? '' : challenge.detailedRequirements,
-    finalSubmissionGuidelines: challenge.finalSubmissionGuidelines === 'null' ? '' : challenge.finalSubmissionGuidelines,
-    screeningScorecardId: Number(challenge.screeningScorecardId),
-    reviewScorecardId: Number(challenge.reviewScorecardId),
-    numberOfCheckpointsPrizes: challenge.numberOfCheckpointsPrizes,
-    topCheckPointPrize: challenge.topCheckPointPrize,
-    submissionsViewable: challenge.submissionsViewable || 'false',
-    reviewType: challenge.reviewType,
-    allowStockArt: challenge.allowStockArt === 'true',
-    fileTypes: challenge.filetypes || [],
-    environment: challenge.environment,
-    codeRepo: challenge.codeRepo,
-    forumLink: challenge.forumLink,
-    submissionLimit: Number(challenge.submissionLimit) || 0,
-    drPoints: challenge.digitalRunPoints,
-    directUrl: challenge.directUrl,
-    technologies: challenge.technologies || challenge.technology || [],
-    platforms: challenge.platforms || [],
-    prizes: challenge.prize || challenge.prizes || [],
-    events: _.map(challenge.event, e => ({
-      eventName: e.eventShortDesc,
-      eventId: e.id,
-      description: e.eventDescription,
-    })),
-    terms: challenge.terms,
-    submissions: challenge.submissions,
-    track: _.toUpper(challenge.challengeCommunity),
-    subTrack: challenge.subTrack,
-    checkpoints: challenge.checkpoints,
-    documents: challenge.documents || [],
-    numRegistrants: challenge.numberOfRegistrants,
-    numberOfCheckpointSubmissions: challenge.numberOfCheckpointSubmissions,
-    registrants: challenge.registrants || [],
-  };
-
-  // Winners have different field names, needs to be normalized to match `filtered` and `challenge`
-  finalChallenge.winners = _.map(
-    challenge.winners,
-    (winner, index) => ({
-      ...winner,
-      handle: winner.submitter,
-      placement: winner.rank || index + 1, // Legacy MMs do not have a rank but are sorted by points
-    }),
-  );
-
-  if (finalChallenge.subTrack === 'MARATHON_MATCH') {
-    finalChallenge.track = 'DATA_SCIENCE';
-  }
-
-  // It's not clear if this will be the main event, will need to be investigated
-  finalChallenge.mainEvent = finalChallenge.events[0] || {};
-
-  /* It's unclear if these normalization steps are still required for `challenge` */
-  // Fill missing data from filtered
-  if (filtered) {
-    const groups = {};
-    if (filtered.groupIds) {
-      filtered.groupIds.forEach((id) => {
-        groups[id] = true;
-      });
-    }
-
-    _.merge(finalChallenge, {
-      componentId: filtered.componentId,
-      contestId: filtered.contestId,
-
-      submissionEndDate: filtered.submissionEndDate, // Dates are not correct in `challenge`
-      submissionEndTimestamp: filtered.submissionEndDate, // Dates are not correct in `challenge`
-
-      /* Taking phases from filtered, because dates are not correct in `challenge` */
-      allPhases: filtered.allPhases || [],
-
-      /* Taking phases from filtered, because dates are not correct in `challenge` */
-      currentPhases: filtered.currentPhases || [],
-
-      /* `challenge` has incorrect value for numberOfSubmissions for some reason */
-      numSubmissions: filtered.numSubmissions,
-      groups,
-    });
-  }
-
-  // Fill missing data from user
-  if (user) {
-    _.defaults(finalChallenge, {
-      userDetails: user.userDetails,
-    });
-  }
-
-  // Fill some derived data
-  const registrationOpen = _.some(
-    finalChallenge.allPhases,
-    phase => phase.phaseType === 'Registration' && phase.phaseStatus === 'Open',
-  ) ? 'Yes' : 'No';
-  _.defaults(finalChallenge, {
-    communities: new Set([COMPETITION_TRACKS[finalChallenge.track]]),
-    registrationOpen,
-    users: username ? { [username]: true } : {},
-  });
-
-  // A hot fix to show submissions for on-going challenges
-  if (!finalChallenge.submissions || !finalChallenge.submissions.length) {
-    finalChallenge.submissions = finalChallenge.registrants
-      .filter(r => r.submissionDate || '')
-      .sort((a, b) => (a.submissionDate || '')
-        .localeCompare(b.submissionDate || ''));
-  }
-
-  if (!finalChallenge.allPhases) finalChallenge.allPhases = [];
-  if (!finalChallenge.track) finalChallenge.track = '';
-
-  return finalChallenge;
-}
-
 /**
  * Normalizes a regular challenge object received from the backend.
  * NOTE: This function is copied from the existing code in the challenge listing
@@ -173,31 +29,38 @@ export function normalizeChallengeDetails(challenge, filtered, user, username) {
  * @param {String} username Optional.
  */
 export function normalizeChallenge(challenge, username) {
-  const registrationOpen = challenge.allPhases.filter(d => d.phaseType === 'Registration')[0].phaseStatus === 'Open' ? 'Yes' : 'No';
+  const phases = challenge.allPhases || challenge.phases || [];
+  let registrationOpen = phases.filter(d => d.name === 'Registration')[0];
+  if (registrationOpen && registrationOpen.isOpen) {
+    registrationOpen = 'Yes';
+  } else {
+    registrationOpen = 'No';
+  }
   const groups = {};
-  if (challenge.groupIds) {
-    challenge.groupIds.forEach((id) => {
+  if (challenge.groups) {
+    challenge.groups.forEach((id) => {
       groups[id] = true;
     });
   }
   /* eslint-disable no-param-reassign */
-  if (!challenge.prizes) challenge.prizes = challenge.prize || [];
-  if (!challenge.totalPrize) {
-    challenge.totalPrize = challenge.prizes.reduce((sum, x) => sum + x, 0);
-  }
-  if (!challenge.technologies) challenge.technologies = [];
+  if (!challenge.prizeSets) challenge.prizeSets = [];
+  if (!challenge.tags) challenge.tags = [];
   if (!challenge.platforms) challenge.platforms = [];
 
-  if (challenge.subTrack === 'DEVELOP_MARATHON_MATCH') {
-    challenge.track = 'DATA_SCIENCE';
+  if (challenge.type === 'Marathon Match') {
+    challenge.legacy.track = 'DATA_SCIENCE';
   }
   /* eslint-enable no-param-reassign */
 
+  let submissionEndTimestamp = phases.filter(d => d.name === 'Submission')[0];
+  if (submissionEndTimestamp) {
+    submissionEndTimestamp = submissionEndTimestamp.scheduledEndDate;
+  }
   _.defaults(challenge, {
-    communities: new Set([COMPETITION_TRACKS[challenge.track]]),
+    communities: new Set([COMPETITION_TRACKS[challenge.legacy.track]]),
     groups,
     registrationOpen,
-    submissionEndTimestamp: challenge.submissionEndDate,
+    submissionEndTimestamp,
     users: username ? { [username]: true } : {},
   });
 }
@@ -220,6 +83,29 @@ async function checkError(res) {
   return jsonRes;
 }
 
+/**
+ * Helper method that checks for HTTP error response v5 and throws Error in this case.
+ * @param {Object} res HTTP response object
+ * @return {Object} API JSON response object
+ * @private
+ */
+async function checkErrorV5(res) {
+  if (!res.ok) {
+    if (res.status >= 500) {
+      setErrorIcon(ERROR_ICON_TYPES.API, '/challenges', res.statusText);
+    }
+    throw new Error(res.statusText);
+  }
+  const jsonRes = (await res.json());
+  if (jsonRes.message) {
+    throw new Error(res.message);
+  }
+  return {
+    result: jsonRes,
+    headers: res.headers,
+  };
+}
+
 /**
  * Challenge service.
  */
@@ -245,22 +131,59 @@ class ChallengesService {
       params = {},
     ) => {
       const query = {
-        filter: qs.stringify(filters, { encode: false }),
+        ...filters,
         ...params,
       };
       const url = `${endpoint}?${qs.stringify(query)}`;
-      const res = await this.private.api.get(url).then(checkError);
+      const res = await this.private.apiV5.get(url).then(checkErrorV5);
       return {
-        challenges: res.content || [],
-        totalCount: res.metadata.totalCount,
-        meta: res.metadata,
+        challenges: res.result || [],
+        totalCount: res.headers.get('x-total'),
+        meta: {
+          allChallengesCount: res.headers.get('x-total'),
+          myChallengesCount: 0,
+          ongoingChallengesCount: 0,
+          openChallengesCount: 0,
+          totalCount: res.headers.get('x-total'),
+        },
+      };
+    };
+    /**
+     * Private function being re-used in all methods related to getting
+     * challenges. It handles query-related arguments in the uniform way:
+     * @param {String} endpoint API endpoint, where the request will be send.
+     * @param {Object} filters Optional. A map of filters to pass as `filter`
+     *  query parameter (this function takes care to stringify it properly).
+     * @param {Object} params Optional. A map of any other parameters beside
+     *  `filter`.
+     */
+    const getMemberChallenges = async (
+      endpoint,
+      filters = {},
+      params = {},
+    ) => {
+      const memberId = decodeToken(this.private.tokenV3).userId;
+      const query = {
+        ...params,
+        ...filters,
+        memberId,
+      };
+      const url = `${endpoint}?${qs.stringify(_.omit(query, ['limit', 'offset', 'technologies']))}`;
+      const res = await this.private.apiV5.get(url).then(checkError);
+      const totalCount = res.length;
+      return {
+        challenges: res || [],
+        totalCount,
       };
     };
 
     this.private = {
       api: getApi('V4', tokenV3),
+      apiV5: getApi('V5', tokenV3),
       apiV2: getApi('V2', tokenV2),
+      apiV3: getApi('V3', tokenV3),
       getChallenges,
+      getMemberChallenges,
       tokenV2,
       tokenV3,
       memberService: getMembersService(),
@@ -274,7 +197,12 @@ class ChallengesService {
    *  is rejected.
    */
   async activate(challengeId) {
-    let res = await this.private.api.post(`/challenges/${challengeId}/activate`);
+    const params = {
+      status: 'Active',
+    };
+
+    let res = await this.private.apiV5.patch(`/challenge/${challengeId}`, params);
+
     if (!res.ok) throw new Error(res.statusText);
     res = (await res.json()).result;
     if (res.status !== 200) throw new Error(res.content);
@@ -284,15 +212,14 @@ class ChallengesService {
   /**
    * Closes the specified challenge.
    * @param {Number} challengeId
-   * @param {Number} winnerId Optional. ID of the assignee to declare the
-   *  winner.
    * @return {Promise} Resolves to null value in case of success; otherwise it
    *  is rejected.
    */
-  async close(challengeId, winnerId) {
-    let url = `/challenges/${challengeId}/close`;
-    if (winnerId) url = `${url}?winnerId=${winnerId}`;
-    let res = await this.private.api.post(url);
+  async close(challengeId) {
+    const params = {
+      status: 'Completed',
+    };
+    let res = await this.private.apiV5.patch(`/challenges/${challengeId}`, params);
     if (!res.ok) throw new Error(res.statusText);
     res = (await res.json()).result;
     if (res.status !== 200) throw new Error(res.content);
@@ -310,7 +237,7 @@ class ChallengesService {
    * @param {String} submissionGuidelines
    * @param {Number} copilotId
    * @param {Number} copilotFee
-   * @param {?} technologies
+   * @param {?} tags
    * @return {Promise} Resolves to the created challenge object (payment task).
    */
   async createTask(
@@ -323,24 +250,41 @@ class ChallengesService {
     submissionGuidelines,
     copilotId,
     copilotFee,
-    technologies,
+    tags,
   ) {
+    const registrationPhase = await this.private.apiV5.get('/challenge-phases?name=Registration');
+
     const payload = {
       param: {
-        assignees: [assignee],
-        billingAccountId: accountId,
-        confidentialityType: 'public',
-        detailedRequirements: description,
-        submissionGuidelines,
-        milestoneId: 1,
         name: title,
-        technologies,
-        prizes: payment ? [payment] : [],
+        typeId: 'e885273d-aeda-42c0-917d-bfbf979afbba',
+        description,
+        legacy: {
+          track: 'FIRST_2_FINISH',
+          reviewType: 'INTERNAL',
+          confidentialityType: 'public',
+          billingAccountId: accountId,
+        },
+        phases: [
+          {
+            phaseId: registrationPhase.id,
+            scheduledEndDate: moment().toISOString(),
+          },
+        ],
+        prizeSets: [
+          {
+            type: 'Challenge Prizes',
+            description: 'Challenge Prize',
+            prizes: [
+              {
+                value: payment,
+                type: 'First Placement',
+              },
+            ],
+          },
+        ],
+        tags,
         projectId,
-        registrationStartsAt: moment().toISOString(),
-        reviewType: 'INTERNAL',
-        subTrack: 'FIRST_2_FINISH',
-        task: true,
       },
     };
     if (copilotId) {
@@ -349,7 +293,7 @@ class ChallengesService {
         copilotFee,
       });
     }
-    let res = await this.private.api.postJson('/challenges', payload);
+    let res = await this.private.apiV5.postJson('/challenges', payload);
     if (!res.ok) throw new Error(res.statusText);
     res = (await res.json()).result;
     if (res.status !== 200) throw new Error(res.content);
@@ -365,26 +309,10 @@ class ChallengesService {
    * @return {Promise} Resolves to the challenge object.
    */
   async getChallengeDetails(challengeId) {
-    const challenge = await this.private.api.get(`/challenges/${challengeId}`)
-      .then(checkError).then(res => res.content);
-
     const challengeFiltered = await this.private.getChallenges('/challenges/', { id: challengeId })
       .then(res => res.challenges[0]);
 
-    const username = this.private.tokenV3 && decodeToken(this.private.tokenV3).handle;
-    const challengeUser = username && await this.getUserChallenges(username, { id: challengeId })
-      .then(res => res.challenges[0]).catch(() => null);
-
-    const finalChallenge = normalizeChallengeDetails(
-      challenge,
-      challengeFiltered,
-      challengeUser,
-      username,
-    );
-
-    finalChallenge.fetchedWithAuth = Boolean(this.private.api.private.token);
-
-    return finalChallenge;
+    return challengeFiltered;
   }
 
   /**
@@ -393,22 +321,22 @@ class ChallengesService {
    * @return {Promise} Resolves to the challenge registrants array.
    */
   async getChallengeRegistrants(challengeId) {
-    const challenge = await this.private.api.get(`/challenges/${challengeId}`)
-      .then(checkError).then(res => res.content);
-    return challenge.registrants;
+    const registrants = await this.private.apiV5.get(`/resources/challengeId=${challengeId}`)
+      .then(checkError).then(res => res);
+    return registrants || [];
   }
 
   /**
-   * Gets possible challenge subtracks.
+   * Gets possible challenge types.
    * @return {Promise} Resolves to the array of subtrack names.
    */
-  getChallengeSubtracks() {
-    return this.private.api.get('/challenge-types')
+  getChallengeTypes() {
+    return this.private.apiV5.get('/challenge-types')
       .then(res => (res.ok ? res.json() : new Error(res.statusText)))
       .then(res => (
-        res.result.status === 200
-          ? res.result.content
-          : new Error(res.result.content)
+        res.message
+          ? new Error(res.message)
+          : res
       ));
   }
 
@@ -443,39 +371,61 @@ class ChallengesService {
   /**
    * Gets SRM matches.
    * @param {Object} params
+   * @param {string} typeId Challenge SRM TypeId
    * @return {Promise}
    */
   async getSrms(params) {
-    const res = await this.private.api.get(`/srms/?${qs.stringify(params)}`);
+    const res = await this.private.apiV5.get(`/challenges/?${qs.stringify(params)}`);
     return getApiResponsePayload(res);
   }
 
+  static updateFiltersParamsForGettingMemberChallenges(filters, params) {
+    if (params && params.perPage) {
+      // eslint-disable-next-line no-param-reassign
+      params.offset = (params.page - 1) * params.perPage;
+      // eslint-disable-next-line no-param-reassign
+      params.limit = params.perPage;
+    }
+  }
+
   /**
    * Gets challenges of the specified user.
-   * @param {String} username User whose challenges we want to fetch.
+   * @param {String} userId User id whose challenges we want to fetch.
    * @param {Object} filters Optional.
    * @param {Number} params Optional.
    * @return {Promise} Resolves to the api response.
    */
-  getUserChallenges(username, filters, params) {
-    const endpoint = `/members/${username.toLowerCase()}/challenges/`;
-    return this.private.getChallenges(endpoint, filters, params)
+  getUserChallenges(userId, filters, params) {
+    const userFilters = _.cloneDeep(filters);
+    ChallengesService.updateFiltersParamsForGettingMemberChallenges(userFilters, params);
+    const query = {
+      ...params,
+      ...userFilters,
+      memberId: userId,
+    };
+    const endpoint = '/challenges';
+    const url = `${endpoint}?${qs.stringify(_.omit(query, ['limit', 'offset', 'technologies']))}`;
+
+    return this.private.apiV5.get(url)
       .then((res) => {
-        res.challenges.forEach(item => normalizeChallenge(item, username));
+        res.challenges.forEach(item => normalizeChallenge(item, userId));
         return res;
       });
   }
 
   /**
    * Gets marathon matches of the specified user.
-   * @param {String} username User whose challenges we want to fetch.
+   * @param {String} userId User whose challenges we want to fetch.
    * @param {Object} filters Optional.
    * @param {Number} params Optional.
    * @return {Promise} Resolves to the api response.
    */
-  getUserMarathonMatches(username, filters, params) {
-    const endpoint = `/members/${username.toLowerCase()}/mms/`;
-    return this.private.getChallenges(endpoint, filters, params);
+  async getUserMarathonMatches(userId) {
+    const marathonTypeId = 'c2579605-e294-4967-b3db-875ef85240cd';
+    const url = `/challenges?typeId=${marathonTypeId}&memberId=${userId}`;
+
+    const res = await this.private.apiV5.get(url);
+    return res;
   }
 
   /**
@@ -485,19 +435,33 @@ class ChallengesService {
    * @return {Promise}
    */
   async getUserSrms(handle, params) {
-    const url = `/members/${handle}/srms/?${qs.stringify(params)}`;
-    const res = await this.private.api.get(url);
+    const challenges = await this.private.apiV5.get(`/resources?memberHandle=${handle}`);
+    let newParams = params;
+    if (challenges) {
+      const { challengeId } = challenges[0];
+      newParams = {
+        ...params,
+        challengeId,
+      };
+    }
+
+    const url = `/challenges/${qs.stringify(newParams)}`;
+    const res = await this.private.apiV5.get(url);
     return getApiResponsePayload(res);
   }
 
   /**
    * Registers user to the specified challenge.
    * @param {String} challengeId
+   * @param {String} memberHandle
+   * @param {String} roleId
    * @return {Promise}
    */
-  async register(challengeId) {
-    const endpoint = `/challenges/${challengeId}/register`;
-    const res = await this.private.api.postJson(endpoint);
+  async register(challengeId, memberHandle, roleId) {
+    const params = {
+      challengeId, memberHandle, roleId,
+    };
+    const res = await this.private.apiV5.post('/resources', params);
     if (!res.ok) throw new Error(res.statusText);
     return res.json();
   }
@@ -505,11 +469,15 @@ class ChallengesService {
   /**
    * Unregisters user from the specified challenge.
    * @param {String} challengeId
+   * @param {String} memberHandle
+   * @param {String} roleId
    * @return {Promise}
    */
-  async unregister(challengeId) {
-    const endpoint = `/challenges/${challengeId}/unregister`;
-    const res = await this.private.api.post(endpoint);
+  async unregister(challengeId, memberHandle, roleId) {
+    const params = {
+      challengeId, memberHandle, roleId,
+    };
+    const res = await this.private.apiV5.delete('/resources', params);
     if (!res.ok) throw new Error(res.statusText);
     return res.json();
   }
@@ -520,7 +488,7 @@ class ChallengesService {
    * @return {Action} Resolves to the api response.
    */
   getActiveChallengesCount(handle) {
-    const filter = { status: 'ACTIVE' };
+    const filter = { status: 'Active' };
     const params = { limit: 1, offset: 0 };
     return this.getUserChallenges(handle, filter, params).then(res => res.totalCount);
   }
@@ -579,9 +547,8 @@ class ChallengesService {
    * @return {Promise}
    */
   async updateChallenge(challenge) {
-    const URL = `/challenges/${challenge.id}`;
-    const body = { param: challenge };
-    let res = await this.private.api.putJson(URL, body);
+    const url = `/challenges/${challenge.id}`;
+    let res = await this.private.apiV5.put(url, challenge);
     if (!res.ok) throw new Error(res.statusText);
     res = (await res.json()).result;
     if (res.status !== 200) throw new Error(res.content);
@@ -602,10 +569,10 @@ class ChallengesService {
    */
   async getUserRolesInChallenge(challengeId) {
     const user = decodeToken(this.private.tokenV3);
-    const username = user.handle || user.payload.handle;
-    const url = `/members/${username.toLowerCase()}/challenges`;
-    const data = await this.private.getChallenges(url, { id: challengeId });
-    return data.challenges[0].userDetails.roles;
+    const url = `/resources?challengeId=${challengeId}?memberHandle=${user.handle}`;
+    const resources = await this.private.apiV5.get(url);
+    if (resources) return _.map(resources, 'roleId');
+    throw new Error(`Failed to fetch user role from challenge #${challengeId}`);
   }
 }
 
diff --git a/src/utils/challenge/filter.js b/src/utils/challenge/filter.js
index 28e00654..30fe6210 100644
--- a/src/utils/challenge/filter.js
+++ b/src/utils/challenge/filter.js
@@ -70,11 +70,6 @@ import { COMPETITION_TRACKS, REVIEW_OPPORTUNITY_TYPES } from '../tc';
  * from the filter state object, and returns true or false depending on it.
  */
 
-function filterByEndDate(challenge, state) {
-  if (!state.endDate) return true;
-  return moment(state.endDate).isAfter(challenge.registrationStartDate);
-}
-
 function filterByGroupIds(challenge, state) {
   if (!state.groupIds) return true;
   return state.groupIds.some(id => challenge.groups[id]);
@@ -86,16 +81,17 @@ function filterByRegistrationOpen(challenge, state) {
     if (challenge.registrationOpen) {
       return challenge.registrationOpen === 'Yes';
     }
-    if (challenge.subTrack === 'MARATHON_MATCH') {
-      return challenge.status !== 'PAST';
+    if (challenge.challengeType && challenge.challengeType.name === 'Marathon Match') {
+      return challenge.status !== 'Past';
     }
-    const registrationPhase = challenge.allPhases.find(item => item.phaseType === 'Registration');
-    if (!registrationPhase || registrationPhase.phaseStatus !== 'Open') {
+    const challengePhases = challenge.allPhases || challenge.phases || [];
+    const registrationPhase = challengePhases.find(item => item.name === 'Registration')[0];
+    if (!registrationPhase || !registrationPhase.isOpen) {
       return false;
     }
     if (challenge.track === 'DESIGN') {
-      const checkpointPhase = challenge.allPhases.find(item => item.phaseType === 'Checkpoint Submission');
-      return !checkpointPhase || checkpointPhase.phaseStatus !== 'Closed';
+      const checkpointPhase = challengePhases.find(item => item.name === 'Checkpoint Submission')[0];
+      return !checkpointPhase || !checkpointPhase.isOpen;
     }
     return true;
   };
@@ -115,12 +111,28 @@ function filterByReviewOpportunityType(opp, state) {
 
 function filterByStartDate(challenge, state) {
   if (!state.startDate) return true;
-  return moment(state.startDate).isBefore(challenge.submissionEndDate);
+  const submissionPhase = challenge.phases.filter(d => d.name === 'Submission')[0];
+  if (submissionPhase) {
+    return moment(state.startDate).isBefore(submissionPhase.scheduledEndDate);
+  }
+  return false;
+}
+
+function filterByEndDate(challenge, state) {
+  if (!state.endDate) return true;
+  const registrationPhase = challenge.phases.filter(d => d.name === 'Registration')[0];
+  if (registrationPhase) {
+    return moment(state.endDate).isAfter(registrationPhase.scheduledStartDate);
+  }
+  return false;
 }
 
 function filterByStarted(challenge, state) {
   if (_.isUndefined(state.started)) return true;
-  return moment(challenge.registrationStartDate).isBefore(Date.now());
+  if (!challenge.phases) {
+    return true;
+  }
+  return _.some(challenge.phases, { isOpen: true, name: 'Registration' });
 }
 
 function filterByStatus(challenge, state) {
@@ -128,28 +140,16 @@ function filterByStatus(challenge, state) {
   return state.status.includes(challenge.status);
 }
 
-function filterBySubtracks(challenge, state) {
-  if (!state.subtracks) return true;
-
-  /* TODO: Although this is taken from the current code in prod,
-   * it probably does not work in all cases. It should be double-checked,
-   * why challenge subtracks in challenge objects are different from those
-   * return from the API as the list of possible subtracks. */
-  const filterSubtracks = state.subtracks.map(item => item.toLowerCase().replace(/[_ ]/g, ''));
-  const challengeSubtrack = challenge.subTrack.toLowerCase().replace(/[_ ]/g, '');
-  return filterSubtracks.includes(challengeSubtrack);
-}
-
 function filterByTags(challenge, state) {
   if (!state.tags) return true;
-  const { platforms, technologies } = challenge;
-  const str = `${platforms} ${technologies}`.toLowerCase();
+  const { platforms, tags } = challenge;
+  const str = `${platforms} ${tags}`.toLowerCase();
   return state.tags.some(tag => str.includes(tag.toLowerCase()));
 }
 
 function filterByText(challenge, state) {
   if (!state.text) return true;
-  const str = `${challenge.name} ${challenge.platforms} ${challenge.technologies}`
+  const str = `${challenge.name} ${challenge.tags} ${challenge.platforms} ${challenge.tags}`
     .toLowerCase();
   return str.includes(state.text.toLowerCase());
 }
@@ -160,13 +160,18 @@ function filterByTrack(challenge, state) {
   /* Development challenges having Data Science tech tag, still should be
    * included into data science track. */
   if (state.tracks[COMPETITION_TRACKS.DATA_SCIENCE]
-    && _.includes(challenge.technologies, 'Data Science')) {
+    && _.includes(challenge.tags, 'Data Science')) {
     return true;
   }
 
   return _.keys(state.tracks).some(track => challenge.communities.has(track));
 }
 
+function filterBySubtracks(challenge, state) {
+  if (!state.subtracks) return true;
+  return state.subtracks.includes(challenge.typeId);
+}
+
 function filterByUpcoming(challenge, state) {
   if (_.isUndefined(state.upcoming)) return true;
   return moment().isBefore(challenge.registrationStartDate);