diff --git a/lib/platform/bitbucket/bb-got-wrapper.ts b/lib/platform/bitbucket/bb-got-wrapper.ts
deleted file mode 100644
index c8c702a7a5a3f1f1a9bce51f601920ac6df80d7c..0000000000000000000000000000000000000000
--- a/lib/platform/bitbucket/bb-got-wrapper.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { GotJSONOptions } from 'got';
-import { PLATFORM_TYPE_BITBUCKET } from '../../constants/platforms';
-import got from '../../util/got';
-import { GotApi, GotApiOptions, GotResponse } from '../common';
-
-let baseUrl = 'https://api.bitbucket.org/';
-async function get(
-  path: string,
-  options: GotApiOptions & GotJSONOptions
-): Promise<GotResponse> {
-  const opts: GotApiOptions & GotJSONOptions = {
-    json: true,
-    hostType: PLATFORM_TYPE_BITBUCKET,
-    baseUrl,
-    ...options,
-  };
-  const res = await got(path, opts);
-  return res;
-}
-
-const helpers = ['get', 'post', 'put', 'patch', 'head', 'delete'];
-
-export const api: GotApi = {} as any;
-
-for (const x of helpers) {
-  (api as any)[x] = (url: string, opts: any): Promise<GotResponse> =>
-    get(url, { ...opts, method: x.toUpperCase() });
-}
-
-// eslint-disable-next-line @typescript-eslint/unbound-method
-api.setBaseUrl = (newBaseUrl: string): void => {
-  baseUrl = newBaseUrl;
-};
-
-export default api;
diff --git a/lib/platform/bitbucket/comments.spec.ts b/lib/platform/bitbucket/comments.spec.ts
index be923fe3b0c2f92c259253f6bce964f5720b0997..7299f9eb58ba3aae91bfdb559e634412e8c8d890 100644
--- a/lib/platform/bitbucket/comments.spec.ts
+++ b/lib/platform/bitbucket/comments.spec.ts
@@ -1,5 +1,5 @@
 import * as httpMock from '../../../test/httpMock';
-import { api } from './bb-got-wrapper';
+import { setBaseUrl } from '../../util/http/bitbucket';
 import * as comments from './comments';
 
 const baseUrl = 'https://api.bitbucket.org';
@@ -13,7 +13,7 @@ describe('platform/comments', () => {
     httpMock.reset();
     httpMock.setup();
 
-    api.setBaseUrl(baseUrl);
+    setBaseUrl(baseUrl);
   });
 
   describe('ensureComment()', () => {
diff --git a/lib/platform/bitbucket/comments.ts b/lib/platform/bitbucket/comments.ts
index 86a1c40086d6effa52796a84b7830e8fb433b603..8f2bc5d455bcf02a17580789b0d537c66223b74d 100644
--- a/lib/platform/bitbucket/comments.ts
+++ b/lib/platform/bitbucket/comments.ts
@@ -1,8 +1,10 @@
 import { logger } from '../../logger';
+import { BitbucketHttp } from '../../util/http/bitbucket';
 import { EnsureCommentConfig } from '../common';
-import { api } from './bb-got-wrapper';
 import { Config, accumulateValues } from './utils';
 
+const bitbucketHttp = new BitbucketHttp();
+
 interface Comment {
   content: { raw: string };
   id: number;
@@ -31,7 +33,7 @@ async function addComment(
   prNo: number,
   raw: string
 ): Promise<void> {
-  await api.post(
+  await bitbucketHttp.postJson(
     `/2.0/repositories/${config.repository}/pullrequests/${prNo}/comments`,
     {
       body: { content: { raw } },
@@ -45,7 +47,7 @@ async function editComment(
   commentId: number,
   raw: string
 ): Promise<void> {
-  await api.put(
+  await bitbucketHttp.putJson(
     `/2.0/repositories/${config.repository}/pullrequests/${prNo}/comments/${commentId}`,
     {
       body: { content: { raw } },
@@ -58,7 +60,7 @@ async function deleteComment(
   prNo: number,
   commentId: number
 ): Promise<void> {
-  await api.delete(
+  await bitbucketHttp.deleteJson(
     `/2.0/repositories/${config.repository}/pullrequests/${prNo}/comments/${commentId}`
   );
 }
diff --git a/lib/platform/bitbucket/index.spec.ts b/lib/platform/bitbucket/index.spec.ts
index 41e5f1ef9500c7d8902413e62cc52634c70fa23f..55effefbe7e5110e34c2a7c89f42f7eb3f18aa6d 100644
--- a/lib/platform/bitbucket/index.spec.ts
+++ b/lib/platform/bitbucket/index.spec.ts
@@ -3,6 +3,7 @@ import * as httpMock from '../../../test/httpMock';
 import { REPOSITORY_DISABLED } from '../../constants/error-messages';
 import { logger as _logger } from '../../logger';
 import { BranchStatus } from '../../types';
+import { setBaseUrl } from '../../util/http/bitbucket';
 import { Platform, RepoParams } from '../common';
 
 const baseUrl = 'https://api.bitbucket.org';
@@ -83,6 +84,8 @@ describe('platform/bitbucket', () => {
       username: 'abc',
       password: '123',
     });
+
+    setBaseUrl(baseUrl);
   });
 
   afterEach(async () => {
diff --git a/lib/platform/bitbucket/index.ts b/lib/platform/bitbucket/index.ts
index d774134d78bd229a6fcd0e9f39056aaaad2f61a8..bd85cf7916ff59f90df9947a247115ee0fd7416e 100644
--- a/lib/platform/bitbucket/index.ts
+++ b/lib/platform/bitbucket/index.ts
@@ -11,6 +11,7 @@ import { PR_STATE_ALL, PR_STATE_OPEN } from '../../constants/pull-requests';
 import { logger } from '../../logger';
 import { BranchStatus } from '../../types';
 import * as hostRules from '../../util/host-rules';
+import { BitbucketHttp, setBaseUrl } from '../../util/http/bitbucket';
 import { sanitize } from '../../util/sanitize';
 import {
   BranchStatusConfig,
@@ -31,10 +32,11 @@ import {
 import GitStorage, { StatusResult } from '../git/storage';
 import { smartTruncate } from '../utils/pr-body';
 import { readOnlyIssueBody } from '../utils/read-only-issue-body';
-import { api } from './bb-got-wrapper';
 import * as comments from './comments';
 import * as utils from './utils';
 
+const bitbucketHttp = new BitbucketHttp();
+
 const BITBUCKET_PROD_ENDPOINT = 'https://api.bitbucket.org/';
 
 let config: utils.Config = {} as any;
@@ -88,7 +90,7 @@ export async function initRepo({
     hostType: PLATFORM_TYPE_BITBUCKET,
     url: endpoint,
   });
-  api.setBaseUrl(endpoint);
+  setBaseUrl(endpoint);
   config = {
     repository,
     username: opts.username,
@@ -97,7 +99,7 @@ export async function initRepo({
   let info: utils.RepoInfo;
   try {
     info = utils.repoInfoTransformer(
-      (await api.get(`/2.0/repositories/${repository}`)).body
+      (await bitbucketHttp.getJson(`/2.0/repositories/${repository}`)).body
     );
 
     if (optimizeForDisabled) {
@@ -108,7 +110,7 @@ export async function initRepo({
       let renovateConfig: RenovateConfig;
       try {
         renovateConfig = (
-          await api.get<RenovateConfig>(
+          await bitbucketHttp.getJson<RenovateConfig>(
             `/2.0/repositories/${repository}/src/${info.mainbranch}/renovate.json`
           )
         ).body;
@@ -272,7 +274,7 @@ export async function deleteBranch(
   if (closePr) {
     const pr = await findPr({ branchName, state: PR_STATE_OPEN });
     if (pr) {
-      await api.post(
+      await bitbucketHttp.postJson(
         `/2.0/repositories/${config.repository}/pullrequests/${pr.number}/decline`
       );
     }
@@ -311,7 +313,7 @@ export function getCommitMessages(): Promise<string[]> {
 
 async function isPrConflicted(prNo: number): Promise<boolean> {
   const diff = (
-    await api.get(
+    await bitbucketHttp.get(
       `/2.0/repositories/${config.repository}/pullrequests/${prNo}/diff`,
       { json: false } as any
     )
@@ -320,10 +322,27 @@ async function isPrConflicted(prNo: number): Promise<boolean> {
   return utils.isConflicted(parseDiff(diff));
 }
 
+interface PrResponse {
+  id: string;
+  state: string;
+  links: {
+    commits: {
+      href: string;
+    };
+  };
+  source: {
+    branch: {
+      name: string;
+    };
+  };
+}
+
 // Gets details for a PR
 export async function getPr(prNo: number): Promise<Pr | null> {
   const pr = (
-    await api.get(`/2.0/repositories/${config.repository}/pullrequests/${prNo}`)
+    await bitbucketHttp.getJson<PrResponse>(
+      `/2.0/repositories/${config.repository}/pullrequests/${prNo}`
+    )
   ).body;
 
   // istanbul ignore if
@@ -345,7 +364,9 @@ export async function getPr(prNo: number): Promise<Pr | null> {
 
     // we only want the first two commits, because size tells us the overall number
     const url = pr.links.commits.href + '?pagelen=2';
-    const { body } = await api.get<utils.PagedResult<Commit>>(url);
+    const { body } = await bitbucketHttp.getJson<utils.PagedResult<Commit>>(
+      url
+    );
     const size = body.size || body.values.length;
 
     // istanbul ignore if
@@ -379,11 +400,17 @@ export async function getPr(prNo: number): Promise<Pr | null> {
 const escapeHash = (input: string): string =>
   input ? input.replace(/#/g, '%23') : input;
 
+interface BranchResponse {
+  target: {
+    hash: string;
+  };
+}
+
 // Return the commit SHA for a branch
 async function getBranchCommit(branchName: string): Promise<string | null> {
   try {
     const branch = (
-      await api.get(
+      await bitbucketHttp.getJson<BranchResponse>(
         `/2.0/repositories/${config.repository}/refs/branches/${escapeHash(
           branchName
         )}`
@@ -491,7 +518,7 @@ export async function setBranchStatus({
     url,
   };
 
-  await api.post(
+  await bitbucketHttp.postJson(
     `/2.0/repositories/${config.repository}/commit/${sha}/statuses/build`,
     { body }
   );
@@ -512,7 +539,7 @@ async function findOpenIssues(title: string): Promise<BbIssue[]> {
     );
     return (
       (
-        await api.get(
+        await bitbucketHttp.getJson<{ values: BbIssue[] }>(
           `/2.0/repositories/${config.repository}/issues?q=${filter}`
         )
       ).body.values || /* istanbul ignore next */ []
@@ -543,7 +570,7 @@ export async function findIssue(title: string): Promise<Issue> {
 }
 
 async function closeIssue(issueNumber: number): Promise<void> {
-  await api.put(
+  await bitbucketHttp.putJson(
     `/2.0/repositories/${config.repository}/issues/${issueNumber}`,
     {
       body: { state: 'closed' },
@@ -587,7 +614,7 @@ export async function ensureIssue({
       const [issue] = issues;
       if (String(issue.content.raw).trim() !== description.trim()) {
         logger.debug('Issue updated');
-        await api.put(
+        await bitbucketHttp.putJson(
           `/2.0/repositories/${config.repository}/issues/${issue.id}`,
           {
             body: {
@@ -602,12 +629,18 @@ export async function ensureIssue({
       }
     } else {
       logger.info('Issue created');
-      await api.post(`/2.0/repositories/${config.repository}/issues`, {
-        body: {
-          title,
-          content: { raw: readOnlyIssueBody(description), markup: 'markdown' },
-        },
-      });
+      await bitbucketHttp.postJson(
+        `/2.0/repositories/${config.repository}/issues`,
+        {
+          body: {
+            title,
+            content: {
+              raw: readOnlyIssueBody(description),
+              markup: 'markdown',
+            },
+          },
+        }
+      );
       return 'created';
     }
   } catch (err) /* istanbul ignore next */ {
@@ -641,7 +674,7 @@ export /* istanbul ignore next */ async function getIssueList(): Promise<
     );
     return (
       (
-        await api.get(
+        await bitbucketHttp.getJson<{ values: Issue[] }>(
           `/2.0/repositories/${config.repository}/issues?q=${filter}`
         )
       ).body.values || /* istanbul ignore next */ []
@@ -687,9 +720,12 @@ export async function addReviewers(
     reviewers: reviewers.map((username: string) => ({ username })),
   };
 
-  await api.put(`/2.0/repositories/${config.repository}/pullrequests/${prId}`, {
-    body,
-  });
+  await bitbucketHttp.putJson(
+    `/2.0/repositories/${config.repository}/pullrequests/${prId}`,
+    {
+      body,
+    }
+  );
 }
 
 export /* istanbul ignore next */ function deleteLabel(): never {
@@ -737,7 +773,7 @@ export async function createPr({
 
   if (config.bbUseDefaultReviewers) {
     const reviewersResponse = (
-      await api.get<utils.PagedResult<Reviewer>>(
+      await bitbucketHttp.getJson<utils.PagedResult<Reviewer>>(
         `/2.0/repositories/${config.repository}/default-reviewers`
       )
     ).body;
@@ -765,9 +801,12 @@ export async function createPr({
 
   try {
     const prInfo = (
-      await api.post(`/2.0/repositories/${config.repository}/pullrequests`, {
-        body,
-      })
+      await bitbucketHttp.postJson<PrResponse>(
+        `/2.0/repositories/${config.repository}/pullrequests`,
+        {
+          body,
+        }
+      )
     ).body;
     // TODO: fix types
     const pr: Pr = {
@@ -800,9 +839,12 @@ export async function updatePr(
   description: string
 ): Promise<void> {
   logger.debug(`updatePr(${prNo}, ${title}, body)`);
-  await api.put(`/2.0/repositories/${config.repository}/pullrequests/${prNo}`, {
-    body: { title, description: sanitize(description) },
-  });
+  await bitbucketHttp.putJson(
+    `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,
+    {
+      body: { title, description: sanitize(description) },
+    }
+  );
 }
 
 export async function mergePr(
@@ -812,7 +854,7 @@ export async function mergePr(
   logger.debug(`mergePr(${prNo}, ${branchName})`);
 
   try {
-    await api.post(
+    await bitbucketHttp.postJson(
       `/2.0/repositories/${config.repository}/pullrequests/${prNo}/merge`,
       {
         body: {
diff --git a/lib/platform/bitbucket/utils.spec.ts b/lib/platform/bitbucket/utils.spec.ts
index de9374737f060569bd299c95f26a6266359a46fe..7900bcca9ea00a4f33ca16d36ed27b4d36cc37ce 100644
--- a/lib/platform/bitbucket/utils.spec.ts
+++ b/lib/platform/bitbucket/utils.spec.ts
@@ -1,15 +1,19 @@
 import * as httpMock from '../../../test/httpMock';
+import { setBaseUrl } from '../../util/http/bitbucket';
 import * as utils from './utils';
 
 const range = (count: number) => [...Array(count).keys()];
 
+const baseUrl = 'https://api.bitbucket.org';
+
 describe('accumulateValues()', () => {
   it('paginates', async () => {
     httpMock.reset();
     httpMock.setup();
+    setBaseUrl(baseUrl);
 
     httpMock
-      .scope('https://api.bitbucket.org')
+      .scope(baseUrl)
       .get('/some-url?pagelen=10')
       .reply(200, {
         values: range(10),
diff --git a/lib/platform/bitbucket/utils.ts b/lib/platform/bitbucket/utils.ts
index c4721cbbeeedfbc04c282ff9fed7af7776868fdb..8e3185d90a06d6e6a56570f8a818806b81f5c5ba 100644
--- a/lib/platform/bitbucket/utils.ts
+++ b/lib/platform/bitbucket/utils.ts
@@ -1,9 +1,12 @@
 import url from 'url';
 import { PR_STATE_CLOSED } from '../../constants/pull-requests';
 import { BranchStatus } from '../../types';
-import { GotResponse, Pr } from '../common';
+import { HttpResponse } from '../../util/http';
+import { BitbucketHttp } from '../../util/http/bitbucket';
+import { Pr } from '../common';
 import { Storage } from '../git/storage';
-import { api } from './bb-got-wrapper';
+
+const bitbucketHttp = new BitbucketHttp();
 
 export interface Config {
   baseBranch: string;
@@ -74,6 +77,29 @@ const addMaxLength = (inputUrl: string, pagelen = 100): string => {
   return maxedUrl;
 };
 
+async function callApi<T>(
+  apiUrl: string,
+  method: string,
+  options?: any
+): Promise<HttpResponse<T>> {
+  /* istanbul ignore next */
+  switch (method.toLowerCase()) {
+    case 'post':
+      return bitbucketHttp.postJson<T>(apiUrl, options);
+    case 'put':
+      return bitbucketHttp.putJson<T>(apiUrl, options);
+    case 'patch':
+      return bitbucketHttp.patchJson<T>(apiUrl, options);
+    case 'head':
+      return bitbucketHttp.headJson<T>(apiUrl, options);
+    case 'delete':
+      return bitbucketHttp.deleteJson<T>(apiUrl, options);
+    case 'get':
+    default:
+      return bitbucketHttp.getJson<T>(apiUrl, options);
+  }
+}
+
 export async function accumulateValues<T = any>(
   reqUrl: string,
   method = 'get',
@@ -82,13 +108,13 @@ export async function accumulateValues<T = any>(
 ): Promise<T[]> {
   let accumulator: T[] = [];
   let nextUrl = addMaxLength(reqUrl, pagelen);
-  const lowerCaseMethod = method.toLocaleLowerCase();
 
   while (typeof nextUrl !== 'undefined') {
-    const { body } = (await api[lowerCaseMethod](
+    const { body } = await callApi<{ values: T[]; next: string }>(
       nextUrl,
+      method,
       options
-    )) as GotResponse<PagedResult<T>>;
+    );
     accumulator = [...accumulator, ...body.values];
     nextUrl = body.next;
   }
diff --git a/lib/platform/bitbucket/__snapshots__/bb-got-wrapper.spec.ts.snap b/lib/util/http/__snapshots__/bitbucket.spec.ts.snap
similarity index 85%
rename from lib/platform/bitbucket/__snapshots__/bb-got-wrapper.spec.ts.snap
rename to lib/util/http/__snapshots__/bitbucket.spec.ts.snap
index 895899be6e74009964ee3ce9178ee0ed5a00c838..8a145e14ea1b6ec5bc9d7cb1e51685e374bd1ebe 100644
--- a/lib/platform/bitbucket/__snapshots__/bb-got-wrapper.spec.ts.snap
+++ b/lib/util/http/__snapshots__/bitbucket.spec.ts.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`platform/gl-got-wrapper accepts custom baseUrl 1`] = `
+exports[`util/http/bitbucket accepts custom baseUrl 1`] = `
 Array [
   Object {
     "headers": Object {
@@ -26,7 +26,7 @@ Array [
 ]
 `;
 
-exports[`platform/gl-got-wrapper posts 1`] = `
+exports[`util/http/bitbucket posts 1`] = `
 Array [
   Object {
     "headers": Object {
@@ -42,9 +42,9 @@ Array [
 ]
 `;
 
-exports[`platform/gl-got-wrapper returns cached 1`] = `Object {}`;
+exports[`util/http/bitbucket returns cached 1`] = `Object {}`;
 
-exports[`platform/gl-got-wrapper returns cached 2`] = `
+exports[`util/http/bitbucket returns cached 2`] = `
 Array [
   Object {
     "headers": Object {
diff --git a/lib/platform/bitbucket/bb-got-wrapper.spec.ts b/lib/util/http/bitbucket.spec.ts
similarity index 70%
rename from lib/platform/bitbucket/bb-got-wrapper.spec.ts
rename to lib/util/http/bitbucket.spec.ts
index 89bb7a9acc55ac6a52173af6c1ff2a1b9e6e1b87..d99bd8dbe44270505538f20d8c7817ae39867463 100644
--- a/lib/platform/bitbucket/bb-got-wrapper.spec.ts
+++ b/lib/util/http/bitbucket.spec.ts
@@ -1,12 +1,16 @@
 import * as httpMock from '../../../test/httpMock';
+import { getName } from '../../../test/util';
 import { PLATFORM_TYPE_BITBUCKET } from '../../constants/platforms';
-import * as hostRules from '../../util/host-rules';
-import { api } from './bb-got-wrapper';
+import * as hostRules from '../host-rules';
+import { BitbucketHttp, setBaseUrl } from './bitbucket';
 
 const baseUrl = 'https://api.bitbucket.org';
 
-describe('platform/gl-got-wrapper', () => {
+describe(getName(__filename), () => {
+  let api: BitbucketHttp;
   beforeEach(() => {
+    api = new BitbucketHttp();
+
     // reset module
     jest.resetAllMocks();
 
@@ -21,12 +25,12 @@ describe('platform/gl-got-wrapper', () => {
     httpMock.reset();
     httpMock.setup();
 
-    api.setBaseUrl(baseUrl);
+    setBaseUrl(baseUrl);
   });
   it('posts', async () => {
     const body = ['a', 'b'];
     httpMock.scope(baseUrl).post('/some-url').reply(200, body);
-    const res = await api.post('some-url');
+    const res = await api.postJson('some-url');
     expect(res.body).toEqual(body);
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
@@ -35,16 +39,16 @@ describe('platform/gl-got-wrapper', () => {
     httpMock.scope(baseUrl).post('/some-url').reply(200, {});
     httpMock.scope(customBaseUrl).post('/some-url').reply(200, {});
 
-    await api.post('some-url');
+    await api.postJson('some-url');
 
-    api.setBaseUrl(customBaseUrl);
-    await api.post('some-url');
+    setBaseUrl(customBaseUrl);
+    await api.postJson('some-url');
 
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
   it('returns cached', async () => {
     httpMock.scope(baseUrl).get('/projects/foo').reply(200, {});
-    const { body } = await api.get('projects/foo');
+    const { body } = await api.getJson('projects/foo');
     expect(body).toMatchSnapshot();
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
diff --git a/lib/util/http/bitbucket.ts b/lib/util/http/bitbucket.ts
new file mode 100644
index 0000000000000000000000000000000000000000..428c541a421a1ba3026735015fd99799e5f09693
--- /dev/null
+++ b/lib/util/http/bitbucket.ts
@@ -0,0 +1,25 @@
+import { URL } from 'url';
+import { PLATFORM_TYPE_BITBUCKET } from '../../constants/platforms';
+import { Http, HttpOptions, HttpResponse, InternalHttpOptions } from '.';
+
+let baseUrl = 'https://api.bitbucket.org/';
+export const setBaseUrl = (url: string): void => {
+  baseUrl = url;
+};
+
+export class BitbucketHttp extends Http {
+  constructor(options?: HttpOptions) {
+    super(PLATFORM_TYPE_BITBUCKET, options);
+  }
+
+  protected async request<T>(
+    url: string | URL,
+    options?: InternalHttpOptions
+  ): Promise<HttpResponse<T> | null> {
+    const opts = {
+      baseUrl,
+      ...options,
+    };
+    return super.request<T>(url, opts);
+  }
+}