public function execute($method, $apiCall, array $parameters = array(), $headers = array())
    {
        // Check if the access token needs to be added
        if ($this->access_token != null) {
            $headers = array_merge($headers, array(
                "Authorization: Bearer " . $this->access_token,
            ));
        }

        // Force cURL to not send Expect header to workaround bug with Akamai CDN not handling
        // this type of requests correctly
        $headers = array_merge($headers, array(
            "Expect:",
        ));

        // Setup CURL
        $ch = $this->curlbuilder->create();

        // Set default options
        $ch->setOptions(array(
            CURLOPT_URL             => $apiCall,
            CURLOPT_HTTPHEADER      => $headers,
            CURLOPT_CONNECTTIMEOUT  => 20,
            CURLOPT_TIMEOUT         => 90,
            CURLOPT_RETURNTRANSFER  => true,
            CURLOPT_SSL_VERIFYPEER  => false,
            CURLOPT_SSL_VERIFYHOST  => false,
            CURLOPT_HEADER          => false,
            CURLINFO_HEADER_OUT     => true
        ));

        switch ($method) {
            case 'POST':
                $ch->setOptions(array(
                    CURLOPT_CUSTOMREQUEST   => "POST",
                    CURLOPT_POST            => count($parameters),
                    CURLOPT_POSTFIELDS      => $parameters
                ));

                if (!class_exists('\CURLFile') && defined('CURLOPT_SAFE_UPLOAD')) {
                    $ch->setOption(CURLOPT_SAFE_UPLOAD, false);
                }
                elseif (class_exists('\CURLFile') && defined('CURLOPT_SAFE_UPLOAD')) {
                    $ch->setOption(CURLOPT_SAFE_UPLOAD, true);
                }

                break;
            case 'DELETE':
                $ch->setOption(CURLOPT_CUSTOMREQUEST, "DELETE");
                break;
            case 'PATCH':
                $ch->setOptions(array(
                    CURLOPT_CUSTOMREQUEST   => "PATCH",
                    CURLOPT_POST            => count($parameters),
                    CURLOPT_POSTFIELDS      => $parameters
                ));
                break;
            default:
                $ch->setOption(CURLOPT_CUSTOMREQUEST, "GET");
                break;
        }

        // Execute request and catch response
        $response_data = $ch->execute();

        if ($response_data === false && !$ch->hasErrors()) {
            throw new CurlException("Error: Curl request failed");
        }
        else if($ch->hasErrors()) {
            throw new PinterestException('Error: execute() - cURL error: ' . $ch->getErrors(), $ch->getErrorNumber());
        }

        // Initiate the response
        $response = new Response($response_data, $ch);

        // Check the response code
        if ($response->getResponseCode() >= 400) {
            throw new PinterestException('Pinterest error (code: ' . $response->getResponseCode() . ') with message: ' . $response->getMessage(), $response->getResponseCode());
        }

        // Get headers from last request
        $this->headers = $ch->getHeaders();

        // Close curl resource
        $ch->close();

        // Return the response
        return $response;
    }