diff --git a/mastodon.go b/mastodon.go
index 30a0516..a91da4d 100644
--- a/mastodon.go
+++ b/mastodon.go
@@ -16,6 +16,7 @@ import (
 	"path/filepath"
 	"strconv"
 	"strings"
+	"time"
 
 	"github.com/tomnomnom/linkheader"
 )
@@ -118,11 +119,32 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in
 		req.Header.Set("Content-Type", ct)
 	}
 
-	resp, err := c.Do(req)
-	if err != nil {
-		return err
+	var resp *http.Response
+	backoff := 1000 * time.Millisecond
+	for {
+		resp, err = c.Do(req)
+		if err != nil {
+			return err
+		}
+		defer resp.Body.Close()
+
+		// handle status code 429, which indicates the server is throttling
+		// our requests. Do an exponential backoff and retry the request.
+		if resp.StatusCode == 429 {
+			if backoff > time.Hour {
+				break
+			}
+			backoff *= 2
+
+			select {
+			case <-time.After(backoff):
+			case <-ctx.Done():
+				return ctx.Err()
+			}
+			continue
+		}
+		break
 	}
-	defer resp.Body.Close()
 
 	if resp.StatusCode != http.StatusOK {
 		return parseAPIError("bad request", resp)