diff --git a/services/opencollective/opencollective-all.service.js b/services/opencollective/opencollective-all.service.js
index b7784bf36b4dbbe74d30d6a7637f95224f697ba9..dac3229f9779114d37e322167158ded01a6ec5c2 100644
--- a/services/opencollective/opencollective-all.service.js
+++ b/services/opencollective/opencollective-all.service.js
@@ -17,11 +17,7 @@ export default class OpencollectiveAll extends OpencollectiveBase {
   }
 
   async handle({ collective }) {
-    const data = await this.fetchCollectiveInfo({
-      collective,
-      accountType: [],
-    })
-    const backersCount = this.getCount(data)
+    const { backersCount } = await this.fetchCollectiveInfo(collective)
     return this.constructor.render(backersCount)
   }
 }
diff --git a/services/opencollective/opencollective-all.tester.js b/services/opencollective/opencollective-all.tester.js
index 61f2ef3e2cabbd56a731a5c5be3e955f0576f2e8..d827313c509ad088cd7c0c6d312fa0edff5f6881 100644
--- a/services/opencollective/opencollective-all.tester.js
+++ b/services/opencollective/opencollective-all.tester.js
@@ -2,6 +2,25 @@ import { nonNegativeInteger } from '../validators.js'
 import { createServiceTester } from '../tester.js'
 export const t = await createServiceTester()
 
+t.create('renders correctly')
+  .get('/shields.json')
+  .intercept(nock =>
+    nock('https://opencollective.com/').get('/shields.json').reply(200, {
+      slug: 'shields',
+      currency: 'USD',
+      image:
+        'https://opencollective-production.s3-us-west-1.amazonaws.com/44dcbb90-1ee9-11e8-a4c3-7bb1885c0b6e.png',
+      balance: 105494,
+      yearlyIncome: 157371,
+      backersCount: 35,
+      contributorsCount: 276,
+    })
+  )
+  .expectBadge({
+    label: 'backers and sponsors',
+    message: '35',
+    color: 'brightgreen',
+  })
 t.create('gets amount of backers and sponsors')
   .get('/shields.json')
   .expectBadge({
@@ -9,10 +28,23 @@ t.create('gets amount of backers and sponsors')
     message: nonNegativeInteger,
   })
 
+t.create('renders not found correctly')
+  .get('/nonexistent-collective.json')
+  .intercept(nock =>
+    nock('https://opencollective.com/')
+      .get('/nonexistent-collective.json')
+      .reply(404, 'Not found')
+  )
+  .expectBadge({
+    label: 'backers and sponsors',
+    message: 'collective not found',
+    color: 'red',
+  })
+
 t.create('handles not found correctly')
   .get('/nonexistent-collective.json')
   .expectBadge({
     label: 'backers and sponsors',
-    message: 'No collective found with slug nonexistent-collective',
-    color: 'lightgrey',
+    message: 'collective not found',
+    color: 'red',
   })
diff --git a/services/opencollective/opencollective-backers.service.js b/services/opencollective/opencollective-backers.service.js
index 8afdd56784e392f55b51afdd2d3b5d5d7bb8c66f..3f2b7da4d7541fbd77095d101e7b7190ab973bb4 100644
--- a/services/opencollective/opencollective-backers.service.js
+++ b/services/opencollective/opencollective-backers.service.js
@@ -17,12 +17,10 @@ export default class OpencollectiveBackers extends OpencollectiveBase {
   }
 
   async handle({ collective }) {
-    const data = await this.fetchCollectiveInfo({
+    const { backersCount } = await this.fetchCollectiveBackersCount(
       collective,
-      accountType: ['INDIVIDUAL'],
-    })
-    const backersCount = this.getCount(data)
-
+      { userType: 'users' }
+    )
     return this.constructor.render(backersCount)
   }
 }
diff --git a/services/opencollective/opencollective-backers.tester.js b/services/opencollective/opencollective-backers.tester.js
index 29855ae57d07c0a3cb889d38e7347d14c6742c14..7163f9a5da4ceb37bf838d0e6767d755eb53a0d3 100644
--- a/services/opencollective/opencollective-backers.tester.js
+++ b/services/opencollective/opencollective-backers.tester.js
@@ -2,6 +2,80 @@ import { nonNegativeInteger } from '../validators.js'
 import { createServiceTester } from '../tester.js'
 export const t = await createServiceTester()
 
+t.create('renders correctly')
+  .get('/shields.json')
+  .intercept(nock =>
+    nock('https://opencollective.com/')
+      .get('/shields/members/users.json')
+      .reply(200, [
+        { MemberId: 8685, type: 'USER', role: 'ADMIN' },
+        { MemberId: 8686, type: 'USER', role: 'ADMIN' },
+        { MemberId: 8682, type: 'USER', role: 'ADMIN' },
+        { MemberId: 10305, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 10396, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 10733, type: 'USER', role: 'BACKER' },
+        { MemberId: 8684, type: 'USER', role: 'ADMIN' },
+        { MemberId: 10741, type: 'USER', role: 'BACKER' },
+        {
+          MemberId: 10756,
+          type: 'USER',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        { MemberId: 11578, type: 'USER', role: 'CONTRIBUTOR' },
+        { MemberId: 13459, type: 'USER', role: 'CONTRIBUTOR' },
+        {
+          MemberId: 13507,
+          type: 'USER',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        { MemberId: 13512, type: 'USER', role: 'BACKER' },
+        { MemberId: 13513, type: 'USER', role: 'FUNDRAISER' },
+        { MemberId: 13984, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 14916, type: 'USER', role: 'BACKER' },
+        {
+          MemberId: 16326,
+          type: 'USER',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        { MemberId: 18252, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 17631, type: 'USER', role: 'BACKER', tier: 'backer' },
+        {
+          MemberId: 16420,
+          type: 'USER',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        { MemberId: 17186, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 18791, type: 'USER', role: 'BACKER', tier: 'backer' },
+        {
+          MemberId: 19279,
+          type: 'USER',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        { MemberId: 19863, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 21451, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 22718, type: 'USER', role: 'BACKER' },
+        { MemberId: 23561, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 25092, type: 'USER', role: 'CONTRIBUTOR' },
+        { MemberId: 24473, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 25439, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 24483, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 25090, type: 'USER', role: 'CONTRIBUTOR' },
+        { MemberId: 26404, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 27026, type: 'USER', role: 'BACKER', tier: 'backer' },
+        { MemberId: 27132, type: 'USER', role: 'CONTRIBUTOR' },
+      ])
+  )
+  .expectBadge({
+    label: 'backers',
+    message: '25',
+    color: 'brightgreen',
+  })
+
 t.create('gets amount of backers').get('/shields.json').expectBadge({
   label: 'backers',
   message: nonNegativeInteger,
@@ -11,6 +85,6 @@ t.create('handles not found correctly')
   .get('/nonexistent-collective.json')
   .expectBadge({
     label: 'backers',
-    message: 'No collective found with slug nonexistent-collective',
-    color: 'lightgrey',
+    message: 'collective not found',
+    color: 'red',
   })
diff --git a/services/opencollective/opencollective-base.js b/services/opencollective/opencollective-base.js
index 2b4cc50340506c1bc4fdcdd071b473cc439bd43e..203cfabf0327444ce8d542b370ad933075625354 100644
--- a/services/opencollective/opencollective-base.js
+++ b/services/opencollective/opencollective-base.js
@@ -1,30 +1,26 @@
-import gql from 'graphql-tag'
 import Joi from 'joi'
-import { BaseGraphqlService } from '../index.js'
 import { nonNegativeInteger } from '../validators.js'
+import { BaseJsonService } from '../index.js'
 import { metric } from '../text-formatters.js'
 
-const schema = Joi.object({
-  data: Joi.object({
-    account: Joi.object({
-      name: Joi.string(),
-      slug: Joi.string(),
-      members: Joi.object({
-        totalCount: nonNegativeInteger,
-        nodes: Joi.array().items(
-          Joi.object({
-            tier: Joi.object({
-              legacyId: Joi.number(),
-              name: Joi.string(),
-            }).allow(null),
-          })
-        ),
-      }).required(),
-    }).required(),
-  }).required(),
-}).required()
+// https://developer.opencollective.com/#/api/collectives?id=get-info
+const collectiveDetailsSchema = Joi.object().keys({
+  slug: Joi.string().required(),
+  backersCount: nonNegativeInteger,
+})
 
-export default class OpencollectiveBase extends BaseGraphqlService {
+// https://developer.opencollective.com/#/api/collectives?id=get-members
+function buildMembersArraySchema({ userType, tierRequired }) {
+  const keys = {
+    MemberId: Joi.number().required(),
+    type: userType || Joi.string().required(),
+    role: Joi.string().required(),
+  }
+  if (tierRequired) keys.tier = Joi.string().required()
+  return Joi.array().items(Joi.object().keys(keys))
+}
+
+export default class OpencollectiveBase extends BaseJsonService {
   static category = 'funding'
 
   static buildRoute(base, withTierId) {
@@ -42,46 +38,45 @@ export default class OpencollectiveBase extends BaseGraphqlService {
     }
   }
 
-  async fetchCollectiveInfo({ collective, accountType }) {
-    return this._requestGraphql({
-      schema,
-      url: 'https://api.opencollective.com/graphql/v2',
-      query: gql`
-        query account($slug: String, $accountType: [AccountType]) {
-          account(slug: $slug) {
-            name
-            slug
-            members(accountType: $accountType, role: BACKER) {
-              totalCount
-              nodes {
-                tier {
-                  legacyId
-                  name
-                }
-              }
-            }
-          }
-        }
-      `,
-      variables: {
-        slug: collective,
-        accountType,
-      },
-      options: {
-        headers: { 'content-type': 'application/json' },
+  async fetchCollectiveInfo(collective) {
+    return this._requestJson({
+      schema: collectiveDetailsSchema,
+      // https://developer.opencollective.com/#/api/collectives?id=get-info
+      url: `https://opencollective.com/${collective}.json`,
+      httpErrors: {
+        404: 'collective not found',
       },
     })
   }
 
-  getCount(data) {
-    const {
-      data: {
-        account: {
-          members: { totalCount },
-        },
+  async fetchCollectiveBackersCount(collective, { userType, tierId }) {
+    const schema = buildMembersArraySchema({
+      userType:
+        userType === 'users'
+          ? 'USER'
+          : userType === 'organizations'
+          ? 'ORGANIZATION'
+          : undefined,
+      tierRequired: tierId,
+    })
+    const members = await this._requestJson({
+      schema,
+      // https://developer.opencollective.com/#/api/collectives?id=get-members
+      // https://developer.opencollective.com/#/api/collectives?id=get-members-per-tier
+      url: `https://opencollective.com/${collective}/members/${
+        userType || 'all'
+      }.json${tierId ? `?TierId=${tierId}` : ''}`,
+      httpErrors: {
+        404: 'collective not found',
       },
-    } = data
+    })
 
-    return totalCount
+    const result = {
+      backersCount: members.filter(member => member.role === 'BACKER').length,
+    }
+    // Find the title of the tier
+    if (tierId && members.length > 0)
+      result.tier = members.map(member => member.tier)[0]
+    return result
   }
 }
diff --git a/services/opencollective/opencollective-by-tier.service.js b/services/opencollective/opencollective-by-tier.service.js
index 673597df41d2f7af07adb868ca99d342c583e35b..98acc383f509d56da6d22df439cde12df85411ef 100644
--- a/services/opencollective/opencollective-by-tier.service.js
+++ b/services/opencollective/opencollective-by-tier.service.js
@@ -1,91 +1,9 @@
-import Joi from 'joi'
-import { nonNegativeInteger } from '../validators.js'
-import { BaseJsonService } from '../index.js'
-import { metric } from '../text-formatters.js'
+import OpencollectiveBase from './opencollective-base.js'
 
 const documentation = `<h3>How to get the tierId</h3>
 <p>According to <a target="_blank" href="https://developer.opencollective.com/#/api/collectives?id=get-members-per-tier">open collectives documentation</a>, you can find the tierId by looking at the URL after clicking on a Tier Card on the collective page. (e.g. tierId for https://opencollective.com/shields/order/2988 is 2988)</p>`
 
-// https://developer.opencollective.com/#/api/collectives?id=get-info
-const collectiveDetailsSchema = Joi.object().keys({
-  slug: Joi.string().required(),
-  backersCount: nonNegativeInteger,
-})
-
-// https://developer.opencollective.com/#/api/collectives?id=get-members
-function buildMembersArraySchema({ userType, tierRequired }) {
-  const keys = {
-    MemberId: Joi.number().required(),
-    type: userType || Joi.string().required(),
-    role: Joi.string().required(),
-  }
-  if (tierRequired) keys.tier = Joi.string().required()
-  return Joi.array().items(Joi.object().keys(keys))
-}
-
-class OpencollectiveBaseJson extends BaseJsonService {
-  static category = 'funding'
-
-  static buildRoute(base, withTierId) {
-    return {
-      base: `opencollective${base ? `/${base}` : ''}`,
-      pattern: `:collective${withTierId ? '/:tierId' : ''}`,
-    }
-  }
-
-  static render(backersCount, label) {
-    return {
-      label,
-      message: metric(backersCount),
-      color: backersCount > 0 ? 'brightgreen' : 'lightgrey',
-    }
-  }
-
-  async fetchCollectiveInfo(collective) {
-    return this._requestJson({
-      schema: collectiveDetailsSchema,
-      // https://developer.opencollective.com/#/api/collectives?id=get-info
-      url: `https://opencollective.com/${collective}.json`,
-      httpErrors: {
-        404: 'collective not found',
-      },
-    })
-  }
-
-  async fetchCollectiveBackersCount(collective, { userType, tierId }) {
-    const schema = buildMembersArraySchema({
-      userType:
-        userType === 'users'
-          ? 'USER'
-          : userType === 'organizations'
-          ? 'ORGANIZATION'
-          : undefined,
-      tierRequired: tierId,
-    })
-    const members = await this._requestJson({
-      schema,
-      // https://developer.opencollective.com/#/api/collectives?id=get-members
-      // https://developer.opencollective.com/#/api/collectives?id=get-members-per-tier
-      url: `https://opencollective.com/${collective}/members/${
-        userType || 'all'
-      }.json${tierId ? `?TierId=${tierId}` : ''}`,
-      httpErrors: {
-        404: 'collective not found',
-      },
-    })
-
-    const result = {
-      backersCount: members.filter(member => member.role === 'BACKER').length,
-    }
-    // Find the title of the tier
-    if (tierId && members.length > 0)
-      result.tier = members.map(member => member.tier)[0]
-    return result
-  }
-}
-
-// TODO: 1. pagination is needed. 2. use new graphql api instead of legacy rest api
-export default class OpencollectiveByTier extends OpencollectiveBaseJson {
+export default class OpencollectiveByTier extends OpencollectiveBase {
   static route = this.buildRoute('tier', true)
 
   static examples = [
diff --git a/services/opencollective/opencollective-sponsors.service.js b/services/opencollective/opencollective-sponsors.service.js
index c6015ce40db5eca01fbd2db2a58ef90a11a592e9..0f41df6f036577ae7f9a241f387faaaf9302aae1 100644
--- a/services/opencollective/opencollective-sponsors.service.js
+++ b/services/opencollective/opencollective-sponsors.service.js
@@ -17,11 +17,10 @@ export default class OpencollectiveSponsors extends OpencollectiveBase {
   }
 
   async handle({ collective }) {
-    const data = await this.fetchCollectiveInfo({
+    const { backersCount } = await this.fetchCollectiveBackersCount(
       collective,
-      accountType: ['ORGANIZATION'],
-    })
-    const backersCount = this.getCount(data)
+      { userType: 'organizations' }
+    )
     return this.constructor.render(backersCount)
   }
 }
diff --git a/services/opencollective/opencollective-sponsors.tester.js b/services/opencollective/opencollective-sponsors.tester.js
index d563744a49ae3bef05120b77f89d8b2b93565daa..300af584c42ce190d3aae33a33e045c36c0fe25f 100644
--- a/services/opencollective/opencollective-sponsors.tester.js
+++ b/services/opencollective/opencollective-sponsors.tester.js
@@ -2,16 +2,80 @@ import { nonNegativeInteger } from '../validators.js'
 import { createServiceTester } from '../tester.js'
 export const t = await createServiceTester()
 
+t.create('renders correctly')
+  .get('/shields.json')
+  .intercept(nock =>
+    nock('https://opencollective.com/')
+      .get('/shields/members/organizations.json')
+      .reply(200, [
+        { MemberId: 8683, type: 'ORGANIZATION', role: 'HOST' },
+        {
+          MemberId: 13484,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'backer',
+        },
+        { MemberId: 13508, type: 'ORGANIZATION', role: 'FUNDRAISER' },
+        { MemberId: 15987, type: 'ORGANIZATION', role: 'BACKER' },
+        {
+          MemberId: 16561,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'sponsor',
+        },
+        {
+          MemberId: 16469,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'sponsor',
+        },
+        {
+          MemberId: 18162,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'sponsor',
+        },
+        {
+          MemberId: 21023,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'sponsor',
+        },
+        {
+          MemberId: 21482,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        {
+          MemberId: 26367,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+        { MemberId: 27531, type: 'ORGANIZATION', role: 'BACKER' },
+        {
+          MemberId: 29443,
+          type: 'ORGANIZATION',
+          role: 'BACKER',
+          tier: 'monthly backer',
+        },
+      ])
+  )
+  .expectBadge({
+    label: 'sponsors',
+    message: '10',
+    color: 'brightgreen',
+  })
 t.create('gets amount of sponsors').get('/shields.json').expectBadge({
   label: 'sponsors',
   message: nonNegativeInteger,
-  color: 'brightgreen',
 })
 
 t.create('handles not found correctly')
   .get('/nonexistent-collective.json')
   .expectBadge({
     label: 'sponsors',
-    message: 'No collective found with slug nonexistent-collective',
-    color: 'lightgrey',
+    message: 'collective not found',
+    color: 'red',
   })