diff --git a/package.json b/package.json
index f3ef3791e0407f4af32f10553a0178027b51f68e..284d9ed4a21b3c3e73bac0af6af0f3c731b4e116 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,7 @@
     "detect-node": "^2.0.3",
     "ecurve": "^1.0.5",
     "lodash": "^4.16.4",
+    "retry": "^0.12.0",
     "secure-random": "^1.1.1",
     "ws": "^3.3.2"
   },
diff --git a/src/api/transports/base.js b/src/api/transports/base.js
index 860c2e9a43537247eb496c5df553c356971bff24..15bb7afb5d9b79c7be6a02360bcad1db3adb093a 100644
--- a/src/api/transports/base.js
+++ b/src/api/transports/base.js
@@ -27,7 +27,6 @@ export default class Transport extends EventEmitter {
   send() {}
   start() {}
   stop() {}
-
 }
 
 Promise.promisifyAll(Transport.prototype);
diff --git a/src/api/transports/http.js b/src/api/transports/http.js
index 70c9139daec4b1331696f4ffa28ae80ecd05b0a9..5d5bce3ca7f877dc5c26c5c42b7f839d7a24d965 100644
--- a/src/api/transports/http.js
+++ b/src/api/transports/http.js
@@ -1,5 +1,6 @@
 import fetch from 'cross-fetch';
 import newDebug from 'debug';
+import retry from 'retry';
 import Transport from './base';
 
 const debug = newDebug('steem:http');
@@ -13,9 +14,9 @@ class RPCError extends Error {
   }
 }
 
-export function jsonRpc(uri, {method, id, params}) {
+export function jsonRpc(uri, {method, id, params, fetchMethod}) {
   const payload = {id, jsonrpc: '2.0', method, params};
-  return fetch(uri, {
+  return (fetchMethod || fetch)(uri, {
     body: JSON.stringify(payload),
     method: 'post',
     mode: 'cors',
@@ -42,12 +43,47 @@ export function jsonRpc(uri, {method, id, params}) {
 export default class HttpTransport extends Transport {
   send(api, data, callback) {
     if (this.options.useAppbaseApi) {
-        api = 'condenser_api';
+      api = 'condenser_api';
     }
     debug('Steem::send', api, data);
     const id = data.id || this.id++;
     const params = [api, data.method, data.params];
-    jsonRpc(this.options.uri, {method: 'call', id, params})
-      .then(res => { callback(null, res) }, err => { callback(err) })
+    const retriable = this.retriable(api, data);
+    const fetchMethod = this.options.fetchMethod;
+    retriable.attempt((currentAttempt) => {
+      jsonRpc(this.options.uri, { method: 'call', id, params, fetchMethod }).then(
+        res => { callback(null, res); },
+        err => {
+          if (retriable.retry(err)) return;
+          callback(retriable.mainError());
+        }
+      );
+    });
+  }
+
+  get nonRetriableOperations() {
+    return this.options.nonRetriableOperations || [
+      'broadcast_transaction',
+      'broadcast_transaction_with_callback',
+      'broadcast_transaction_synchronous',
+      'broadcast_block',
+    ];
+  }
+
+  // An object which can be used to track retries.
+  retriable(api, data) {
+    if (this.nonRetriableOperations.some((o) => o === data.method)) {
+      // Do not retry if the operation is non-retriable.
+      return retry.operation({ retries: 0 });
+    } else if (this.options.retry) {
+      // If `this.options.retry` is a map of options, use it. If
+      // `this.options.retry` is `true`, use default options.
+      return (Object(this.options.retry) === this.options.retry) ?
+        retry.operation(this.options.retry) :
+        retry.operation();
+    } else {
+      // Otherwise, don't retry.
+      return retry.operation({ retries: 0 });
+    }
   }
 }
diff --git a/test/api.test.js b/test/api.test.js
index 833d9df7a7ebf6b1af53b2dd5e2c8dbd80fc3f2e..6c1b9c0f9b1b466dfb652f5e7fa7645e0bcdbdbb 100644
--- a/test/api.test.js
+++ b/test/api.test.js
@@ -150,4 +150,180 @@ describe('steem.api:', function () {
     });
   });
 
+  describe('with retry', () => {
+    afterEach(() => {
+      // NOTE: We should reset `steem.api.options` after *every* test.
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        retry: null,
+        fetchMethod: null,
+      });
+    });
+
+    it('works by default', async function() {
+      let attempts = 0;
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        fetchMethod: (uri, req) => new Promise((res, rej) => {
+          const data = JSON.parse(req.body);
+          res({
+            ok: true,
+            json: () => Promise.resolve({
+              jsonrpc: '2.0',
+              id: data.id,
+              result: ['ned'],
+            }),
+          });
+          attempts++;
+        }),
+      });
+      const result = await steem.api.getFollowersAsync('ned', 0, 'blog', 5)
+      assert.equal(attempts, 1);
+      assert.deepEqual(result, ['ned']);
+    });
+
+    it('does not retry by default', async() => {
+      let attempts = 0;
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        fetchMethod: (uri, req) => new Promise((res, rej) => {
+          rej(new Error('Bad request'));
+          attempts++;
+        }),
+      });
+
+      let result;
+      let errored = false;
+      try {
+        result = await steem.api.getFollowersAsync('ned', 0, 'blog', 5)
+      } catch (e) {
+        errored = true;
+      }
+      assert.equal(attempts, 1);
+      assert.equal(errored, true);
+    });
+
+    it('works with retry passed as a boolean', async() => {
+      let attempts = 0;
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        fetchMethod: (uri, req) => new Promise((res, rej) => {
+          const data = JSON.parse(req.body);
+          res({
+            ok: true,
+            json: () => Promise.resolve({
+              jsonrpc: '2.0',
+              id: data.id,
+              result: ['ned'],
+            }),
+          });
+          attempts++;
+        }),
+      });
+
+      const result = await steem.api.getFollowersAsync('ned', 0, 'blog', 5)
+      assert.equal(attempts, 1);
+      assert.deepEqual(result, ['ned']);
+    });
+
+    it('retries with retry passed as a boolean', async() => {
+      let attempts = 0;
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        retry: true,
+        fetchMethod: (uri, req) => new Promise((res, rej) => {
+          if (attempts < 1) {
+            rej(new Error('Bad request'));
+          } else {
+            const data = JSON.parse(req.body);
+            res({
+              ok: true,
+              json: () => Promise.resolve({
+                jsonrpc: '2.0',
+                id: data.id,
+                result: ['ned'],
+              }),
+            });
+          }
+          attempts++;
+        }),
+      });
+
+      let result;
+      let errored = false;
+      try {
+        result = await steem.api.getFollowersAsync('ned', 0, 'blog', 5);
+      } catch (e) {
+        errored = true;
+      }
+      assert.equal(attempts, 2);
+      assert.equal(errored, false);
+      assert.deepEqual(result, ['ned']);
+    });
+
+    it('works with retry passed as an object', async() => {
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        retry: {
+          retries: 3,
+          minTimeout: 1, // 1ms
+        },
+        fetchMethod: (uri, req) => new Promise((res, rej) => {
+          const data = JSON.parse(req.body);
+          res({
+            ok: 'true',
+            json: () => Promise.resolve({
+              jsonrpc: '2.0',
+              id: data.id,
+              result: ['ned'],
+            }),
+          });
+        }),
+      });
+
+      const result = await steem.api.getFollowersAsync('ned', 0, 'blog', 5);
+      assert.deepEqual(result, ['ned']);
+    });
+
+    it('retries with retry passed as an object', async() => {
+      let attempts = 0;
+      steem.api.setOptions({
+        url: 'https://api.steemit.com',
+        retry: {
+          retries: 3,
+          minTimeout: 1,
+        },
+        fetchMethod: (uri, req) => new Promise((res, rej) => {
+          if (attempts < 1) {
+            rej(new Error('Bad request'));
+          } else {
+            const data = JSON.parse(req.body);
+            res({
+              ok: true,
+              json: () => Promise.resolve({
+                jsonrpc: '2.0',
+                id: data.id,
+                result: ['ned'],
+              }),
+            });
+          }
+          attempts++;
+        }),
+      });
+
+      let result;
+      let errored = false;
+      try {
+        result = await steem.api.getFollowersAsync('ned', 0, 'blog', 5);
+      } catch (e) {
+        errored = true;
+      }
+      assert.equal(attempts, 2);
+      assert.equal(errored, false);
+      assert.deepEqual(result, ['ned']);
+    });
+
+    it('does not retry non-retriable operations');
+  });
+
 });