diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h
index 693097ee9a26..7715077b3f7c 100644
--- a/include/libcamera/internal/request.h
+++ b/include/libcamera/internal/request.h
@@ -30,7 +30,7 @@ class Request::Private : public Extensible::Private
 	LIBCAMERA_DECLARE_PUBLIC(Request)
 
 public:
-	Private(Camera *camera);
+	Private(Camera *camera, uint64_t cookie);
 	~Private();
 
 	Camera *camera() const { return camera_; }
@@ -41,7 +41,7 @@ public:
 	bool completeBuffer(FrameBuffer *buffer);
 	void complete();
 	void cancel();
-	void reset();
+	void reset(Request::ReuseFlag flags);
 
 	void prepare(std::chrono::milliseconds timeout = 0ms);
 	Signal<> prepared;
@@ -56,14 +56,20 @@ private:
 	void timeout();
 
 	Camera *camera_;
+	const uint64_t cookie_;
+
+	Status status_;
 	bool cancelled_;
 	uint32_t sequence_ = 0;
 	bool prepared_ = false;
 
+	ControlList controls_;
+	ControlList metadata_;
+	BufferMap bufferMap_;
+
 	std::unordered_set<FrameBuffer *> pending_;
 	std::map<FrameBuffer *, EventNotifier> notifiers_;
 	std::unique_ptr<Timer> timer_;
-	ControlList metadata_;
 };
 
 } /* namespace libcamera */
diff --git a/include/libcamera/request.h b/include/libcamera/request.h
index 290983f61352..08ac6e8daba7 100644
--- a/include/libcamera/request.h
+++ b/include/libcamera/request.h
@@ -22,7 +22,6 @@
 namespace libcamera {
 
 class Camera;
-class CameraControlValidator;
 class FrameBuffer;
 class Stream;
 
@@ -49,16 +48,16 @@ public:
 
 	void reuse(ReuseFlag flags = Default);
 
-	ControlList &controls() { return controls_; }
+	ControlList &controls();
 	const ControlList &metadata() const;
-	const BufferMap &buffers() const { return bufferMap_; }
+	const BufferMap &buffers() const;
 	int addBuffer(const Stream *stream, FrameBuffer *buffer,
 		      std::unique_ptr<Fence> &&fence = {});
 	FrameBuffer *findBuffer(const Stream *stream) const;
 
 	uint32_t sequence() const;
-	uint64_t cookie() const { return cookie_; }
-	Status status() const { return status_; }
+	uint64_t cookie() const;
+	Status status() const;
 
 	bool hasPendingBuffers() const;
 
@@ -66,12 +65,6 @@ public:
 
 private:
 	LIBCAMERA_DISABLE_COPY(Request)
-
-	ControlList controls_;
-	BufferMap bufferMap_;
-
-	const uint64_t cookie_;
-	Status status_;
 };
 
 std::ostream &operator<<(std::ostream &out, const Request &r);
diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp
index b50a64205283..719e27aac763 100644
--- a/src/libcamera/request.cpp
+++ b/src/libcamera/request.cpp
@@ -52,12 +52,16 @@ LOG_DEFINE_CATEGORY(Request)
 
 /**
  * \brief Create a Request::Private
- * \param camera The Camera that creates the request
+ * \param[in] camera The Camera that creates the request
+ * \param[in] cookie Opaque cookie for application use
  *
  * \todo Add a validator for metadata controls.
  */
-Request::Private::Private(Camera *camera)
-	: camera_(camera), cancelled_(false), metadata_(controls::controls)
+Request::Private::Private(Camera *camera, uint64_t cookie)
+	: camera_(camera), cookie_(cookie), status_(RequestPending),
+	  cancelled_(false),
+	  controls_(camera->controls(), camera->_d()->validator()),
+	  metadata_(controls::controls)
 {
 }
 
@@ -132,7 +136,7 @@ void Request::Private::complete()
 	ASSERT(request->status() == RequestPending);
 	ASSERT(!hasPendingBuffers());
 
-	request->status_ = cancelled_ ? RequestCancelled : RequestComplete;
+	status_ = cancelled_ ? RequestCancelled : RequestComplete;
 
 	LOG(Request, Debug) << request->toString();
 
@@ -174,18 +178,37 @@ void Request::Private::cancel()
 
 /**
  * \brief Reset the request internal data to default values
+ * \param[in] flags Indicate whether or not to reuse the buffers
  *
  * After calling this function, all request internal data will have default
- * values as if the Request::Private instance had just been constructed.
+ * values as if the Request::Private instance had just been constructed, with
+ * the exception of bufferMap_ if the Request::ReuseFlag::ReuseBuffers flag is
+ * set in \a flags.
  */
-void Request::Private::reset()
+void Request::Private::reset(Request::ReuseFlag flags)
 {
-	sequence_ = 0;
+	status_ = RequestPending;
 	cancelled_ = false;
+	sequence_ = 0;
 	prepared_ = false;
+
+	controls_.clear();
+	metadata_.clear();
+
 	pending_.clear();
 	notifiers_.clear();
 	timer_.reset();
+
+	if (flags & ReuseBuffers) {
+		Request *request = _o<Request>();
+
+		for (const auto &[stream, buffer] : bufferMap_) {
+			buffer->_d()->setRequest(request);
+			pending_.insert(buffer);
+		}
+	} else {
+		bufferMap_.clear();
+	}
 }
 
 /*
@@ -286,9 +309,8 @@ void Request::Private::notifierActivated(FrameBuffer *buffer)
 	ASSERT(it != notifiers_.end());
 	notifiers_.erase(it);
 
-	Request *request = _o<Request>();
 	LOG(Request, Debug)
-		<< "Request " << request->cookie() << " buffer " << buffer
+		<< "Request " << cookie_ << " buffer " << buffer
 		<< " fence signalled";
 
 	if (!notifiers_.empty())
@@ -305,8 +327,7 @@ void Request::Private::timeout()
 	ASSERT(!notifiers_.empty());
 	notifiers_.clear();
 
-	Request *request = _o<Request>();
-	LOG(Request, Debug) << "Request prepare timeout: " << request->cookie();
+	LOG(Request, Debug) << "Request prepare timeout: " << cookie_;
 
 	cancel();
 
@@ -361,13 +382,11 @@ void Request::Private::timeout()
  * completely opaque to libcamera.
  */
 Request::Request(Camera *camera, uint64_t cookie)
-	: Extensible(std::make_unique<Private>(camera)),
-	  controls_(camera->controls(), camera->_d()->validator()),
-	  cookie_(cookie), status_(RequestPending)
+	: Extensible(std::make_unique<Private>(camera, cookie))
 {
 	LIBCAMERA_TRACEPOINT(request_construct, this);
 
-	LOG(Request, Debug) << "Created request - cookie: " << cookie_;
+	LOG(Request, Debug) << "Created request - cookie: " << cookie;
 }
 
 Request::~Request()
@@ -389,25 +408,10 @@ void Request::reuse(ReuseFlag flags)
 {
 	LIBCAMERA_TRACEPOINT(request_reuse, this);
 
-	_d()->reset();
-
-	if (flags & ReuseBuffers) {
-		for (const auto &[stream, buffer] : bufferMap_) {
-			buffer->_d()->setRequest(this);
-			_d()->pending_.insert(buffer);
-		}
-	} else {
-		bufferMap_.clear();
-	}
-
-	status_ = RequestPending;
-
-	controls_.clear();
-	_d()->metadata_.clear();
+	_d()->reset(flags);
 }
 
 /**
- * \fn Request::controls()
  * \brief Retrieve the request's ControlList
  *
  * Requests store a list of controls to be applied to all frames captured for
@@ -421,6 +425,10 @@ void Request::reuse(ReuseFlag flags)
  *
  * \return A reference to the ControlList in this request
  */
+ControlList &Request::controls()
+{
+	return _d()->controls_;
+}
 
 /**
  * \brief Retrieve the request's metadata
@@ -432,14 +440,19 @@ const ControlList &Request::metadata() const
 }
 
 /**
- * \fn Request::buffers()
  * \brief Retrieve the request's streams to buffers map
  *
  * Return a reference to the map that associates each Stream part of the
- * request to the FrameBuffer the Stream output should be directed to.
+ * request to the FrameBuffer the Stream output should be directed to. If a
+ * stream is not utilised in this request there will be no buffer for that
+ * stream in the map.
  *
  * \return The map of Stream to FrameBuffer
  */
+const Request::BufferMap &Request::buffers() const
+{
+	return _d()->bufferMap_;
+}
 
 /**
  * \brief Add a FrameBuffer with its associated Stream to the Request
@@ -492,7 +505,7 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer,
 		return -EEXIST;
 	}
 
-	auto [it, inserted] = bufferMap_.try_emplace(stream, buffer);
+	auto [it, inserted] = _d()->bufferMap_.try_emplace(stream, buffer);
 	if (!inserted) {
 		LOG(Request, Error) << "FrameBuffer already set for stream";
 		return -EEXIST;
@@ -507,15 +520,6 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer,
 	return 0;
 }
 
-/**
- * \var Request::bufferMap_
- * \brief Mapping of streams to buffers for this request
- *
- * The bufferMap_ tracks the buffers associated with each stream. If a stream is
- * not utilised in this request there will be no buffer for that stream in the
- * map.
- */
-
 /**
  * \brief Return the buffer associated with a stream
  * \param[in] stream The stream the buffer is associated to
@@ -524,8 +528,8 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer,
  */
 FrameBuffer *Request::findBuffer(const Stream *stream) const
 {
-	const auto it = bufferMap_.find(stream);
-	if (it == bufferMap_.end())
+	const auto it = _d()->bufferMap_.find(stream);
+	if (it == _d()->bufferMap_.end())
 		return nullptr;
 
 	return it->second;
@@ -552,13 +556,15 @@ uint32_t Request::sequence() const
 }
 
 /**
- * \fn Request::cookie()
  * \brief Retrieve the cookie set when the request was created
  * \return The request cookie
  */
+uint64_t Request::cookie() const
+{
+	return _d()->cookie_;
+}
 
 /**
- * \fn Request::status()
  * \brief Retrieve the request completion status
  *
  * The request status indicates whether the request has completed successfully
@@ -569,6 +575,10 @@ uint32_t Request::sequence() const
  *
  * \return The request completion status
  */
+Request::Status Request::status() const
+{
+	return _d()->status_;
+}
 
 /**
  * \brief Check if a request has buffers yet to be completed
