diff --git a/src/Concerns/GuzzleAware.php b/src/Concerns/GuzzleAware.php
new file mode 100644
index 0000000..7626873
--- /dev/null
+++ b/src/Concerns/GuzzleAware.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Cerbero\JsonParser\Concerns;
+
+use Cerbero\JsonParser\Exceptions\SourceException;
+use GuzzleHttp\Client;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * The Guzzle-aware trait.
+ *
+ */
+trait GuzzleAware
+{
+    /**
+     * Abort if Guzzle is not loaded
+     *
+     * @return void
+     * @throws SourceException
+     */
+    protected function requireGuzzle(): void
+    {
+        if (!class_exists(Client::class)) {
+            throw SourceException::requireGuzzle();
+        }
+    }
+
+    /**
+     * Retrieve the JSON response of the given URL
+     *
+     * @param UriInterface|string $url
+     * @return ResponseInterface
+     */
+    protected function getJson(UriInterface|string $url): ResponseInterface
+    {
+        return (new Client())->get($url, [
+            'headers' => [
+                'Accept' => 'application/json',
+                'Content-Type' => 'application/json',
+            ],
+        ]);
+    }
+
+    /**
+     * Retrieve the JSON response of the given request
+     *
+     * @param RequestInterface $request
+     * @return ResponseInterface
+     */
+    protected function sendRequest(RequestInterface $request): ResponseInterface
+    {
+        return (new Client())->sendRequest($request);
+    }
+}
diff --git a/src/Sources/AnySource.php b/src/Sources/AnySource.php
index 4d04d97..aea27eb 100644
--- a/src/Sources/AnySource.php
+++ b/src/Sources/AnySource.php
@@ -26,6 +26,7 @@ class AnySource extends Source
         JsonResource::class,
         LaravelClientResponse::class,
         Psr7Message::class,
+        Psr7Request::class,
         Psr7Stream::class,
     ];
 
diff --git a/src/Sources/Endpoint.php b/src/Sources/Endpoint.php
index 109bbcf..34d7b8e 100644
--- a/src/Sources/Endpoint.php
+++ b/src/Sources/Endpoint.php
@@ -3,19 +3,20 @@
 namespace Cerbero\JsonParser\Sources;
 
 use Cerbero\JsonParser\Concerns\DetectsEndpoints;
-use Cerbero\JsonParser\Exceptions\SourceException;
-use GuzzleHttp\Client;
+use Cerbero\JsonParser\Concerns\GuzzleAware;
 use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
 use Traversable;
 
 /**
  * The endpoint source.
  *
- * @property-read string $source
+ * @property-read UriInterface|string $source
  */
 class Endpoint extends Source
 {
     use DetectsEndpoints;
+    use GuzzleAware;
 
     /**
      * The endpoint response.
@@ -28,33 +29,17 @@ class Endpoint extends Source
      * Retrieve the JSON fragments
      *
      * @return Traversable<int, string>
+     * @throws \Cerbero\JsonParser\Exceptions\SourceException
      */
     public function getIterator(): Traversable
     {
-        if (!$this->guzzleIsLoaded()) {
-            throw SourceException::requireGuzzle();
-        }
+        $this->requireGuzzle();
 
-        $this->response = (new Client())->get($this->source, [
-            'headers' => [
-                'Accept' => 'application/json',
-                'Content-Type' => 'application/json',
-            ],
-        ]);
+        $this->response = $this->getJson($this->source);
 
         return new Psr7Message($this->response, $this->config);
     }
 
-    /**
-     * Determine whether the Guzzle client is loaded
-     *
-     * @return bool
-     */
-    protected function guzzleIsLoaded(): bool
-    {
-        return class_exists(Client::class);
-    }
-
     /**
      * Determine whether the JSON source can be handled
      *
@@ -62,7 +47,8 @@ class Endpoint extends Source
      */
     public function matches(): bool
     {
-        return is_string($this->source) && $this->isEndpoint($this->source);
+        // @phpstan-ignore-next-line
+        return (is_string($this->source) || $this->source instanceof UriInterface) && $this->isEndpoint($this->source);
     }
 
     /**
diff --git a/src/Sources/Psr7Message.php b/src/Sources/Psr7Message.php
index 7707c71..2471240 100644
--- a/src/Sources/Psr7Message.php
+++ b/src/Sources/Psr7Message.php
@@ -3,6 +3,7 @@
 namespace Cerbero\JsonParser\Sources;
 
 use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
 use Traversable;
 
 /**
@@ -29,7 +30,7 @@ class Psr7Message extends Source
      */
     public function matches(): bool
     {
-        return $this->source instanceof MessageInterface;
+        return $this->source instanceof MessageInterface && !$this->source instanceof RequestInterface;
     }
 
     /**
diff --git a/src/Sources/Psr7Request.php b/src/Sources/Psr7Request.php
new file mode 100644
index 0000000..0340b96
--- /dev/null
+++ b/src/Sources/Psr7Request.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Cerbero\JsonParser\Sources;
+
+use Cerbero\JsonParser\Concerns\GuzzleAware;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Traversable;
+
+/**
+ * The PSR-7 request source.
+ *
+ * @property-read RequestInterface $source
+ */
+class Psr7Request extends Source
+{
+    use GuzzleAware;
+
+    /**
+     * The endpoint response.
+     *
+     * @var ResponseInterface|null
+     */
+    protected ?ResponseInterface $response;
+
+    /**
+     * Retrieve the JSON fragments
+     *
+     * @return Traversable<int, string>
+     * @throws \Cerbero\JsonParser\Exceptions\SourceException
+     */
+    public function getIterator(): Traversable
+    {
+        $this->requireGuzzle();
+
+        $this->response = $this->sendRequest($this->source);
+
+        return new Psr7Message($this->response, $this->config);
+    }
+
+    /**
+     * Determine whether the JSON source can be handled
+     *
+     * @return bool
+     */
+    public function matches(): bool
+    {
+        return $this->source instanceof RequestInterface;
+    }
+
+    /**
+     * Retrieve the calculated size of the JSON source
+     *
+     * @return int|null
+     */
+    protected function calculateSize(): ?int
+    {
+        return $this->response?->getBody()->getSize();
+    }
+}