public function request($method, $resource, $parameters = array(), $headers = array(), $body = NULL) {
    $handle = curl_init();

    $headers[] = 'Content-Type: application/json; charset=utf-8';
    $headers[] = 'App-Key: ' . $this->api_key;
    if (!empty($this->account_email)) {
      $headers[] = 'Account-Email: '.$this->account_email;
    }
    if (!empty($body)) {
      if (!is_string($body)) {
        $body = json_encode($body);
      }
      curl_setopt($handle, CURLOPT_POSTFIELDS, $body);
      $headers[] = 'Content-Length: ' . strlen($body);
    }
    if (!empty($headers)) {
      curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
    }
    curl_setopt($handle, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($handle, CURLOPT_URL, $this->buildRequestUrl($resource, $parameters));
    curl_setopt($handle, CURLOPT_USERPWD, $this->getAuth());
    curl_setopt($handle, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($handle, CURLOPT_MAXREDIRS, 10);
    curl_setopt($handle, CURLOPT_USERAGENT, 'PingdomApi/1.0');
    curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($handle, CURLOPT_TIMEOUT, 10);
    $gzip = !empty($this->gzip) ? 'gzip' : '';
    curl_setopt($handle, CURLOPT_ENCODING, $gzip);

    $response = curl_exec($handle);
    if (curl_errno($handle) > 0) {
      $curl_error = sprintf('Curl error: %s', curl_error($handle));
      curl_close($handle);
      throw new CurlErrorException($curl_error, $curl_errno);
    }

    $data = json_decode($response);
    $status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
    curl_close($handle);

    $status_class = (int) floor($status / 100);
    if ($status_class === 4 || $status_class === 5) {
      $message = $this->getError($data, $status);
      switch ($status_class) {
        case 4:
          throw new ClientErrorException(sprintf('Client error: %s', $message), $status);
        case 5:
          throw new ServerErrorException(sprintf('Server error: %s', $message), $status);
      }
    }

    return $data;
  }