diff --git a/src/Utils/request/README.md b/src/Utils/request/README.md
new file mode 100644
index 00000000000..a9948d48f41
--- /dev/null
+++ b/src/Utils/request/README.md
@@ -0,0 +1,142 @@
+# CARE's data fetching utilities: `useQuery` and `request`
+
+There are two main ways to fetch data in CARE: `useQuery` and `request`. Both of these utilities are built on top of [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch).
+
+## `useQuery`
+
+`useQuery` is a React hook that allows you to fetch data and automatically update the UI when the data changes. It is
+a wrapper around `request` that is designed to be used in React components. Only "GET" requests are supported with `useQuery`. For other request methods (mutations), use `request`.
+
+### Usage
+
+```jsx
+import { useQuery } from "@care/request";
+import FooRoutes from "@foo/routes";
+
+export default function FooDetails({ children, id }) {
+ const { res, data, loading, error } = useQuery(FooRoutes.getFoo, {
+ pathParams: { id },
+ });
+
+ /* 🪄 Here typeof data is automatically inferred from the specified route. */
+
+ if (loading) return ;
+
+ if (res.status === 403) {
+ navigate("/forbidden");
+ return null;
+ }
+
+ if (error) {
+ return ;
+ }
+
+ return (
+
+ {data.id}
+ {data.name}
+
+ );
+}
+```
+
+### API
+
+```ts
+useQuery(route: Route, options?: QueryOptions): ReturnType;
+```
+
+#### `route`
+
+A route object that specifies the endpoint to fetch data from.
+
+```ts
+const FooRoutes = {
+ getFoo: {
+ path: "/api/v1/foo/{id}/", // 👈 The path to the endpoint. Slug parameters can be specified using curly braces.
+
+ method: "GET", // 👈 The HTTP method to use. Optional; defaults to "GET".
+ TRes: Res, // 👈 The type of the response body (for type inference).
+ noAuth: true, // 👈 Whether to skip adding the Authorization header to the request.
+ },
+} as const; // 👈 This is important for type inference to work properly.
+```
+
+#### `options`
+
+An object that specifies options for the request.
+
+```ts
+const options = {
+ prefetch: true, // 👈 Whether to prefetch the data when the component mounts.
+ refetchOnWindowFocus: true, // 👈 Whether to refetch the data when the window regains focus.
+
+ // The following options are passed directly to the underlying `request` function.
+
+ pathParams: { id: "123" }, // 👈 The slug parameters to use in the path.
+ // If you accidentally forget to specify a slug parameter an error will be
+ // thrown before the request is made.
+
+ query: { limit: 10 }, // 👈 The query parameters to be added to the request URL.
+ body: { name: "foo" }, // 👈 The body to be sent with the request.
+ headers: { "X-Foo": "bar" }, // 👈 Additional headers to be sent with the request. (Coming soon...)
+
+ silent: true, // 👈 Whether to suppress notifications for this request.
+ // This is useful for requests that are made in the background.
+
+ reattempts: 3, // 👈 The number of times to retry the request if it fails.
+ // Reattempts are only made if the request fails due to a network error. Responses with
+ // status codes in the 400s and 500s are not retried.
+
+ onResponse: (res) => { // 👈 An optional callback that is called after the response is received.
+ if (res.status === 403) {
+ navigate("/forbidden");
+ }
+ },
+ // This is useful for handling responses with status codes in the 400s and 500s for a specific request.
+};
+```
+
+#### `ReturnType`
+
+The `useQuery` hook returns an object with the following properties:
+
+```ts
+{
+ res: Res | undefined; // 👈 The response object. `undefined` if the request has not been made yet.
+
+ data: TRes | null; // 👈 The response body. `null` if the request has not been made yet.
+
+ error: any; // 👈 The error that occurred while making the request if any.
+
+ loading: boolean; // 👈 Whether the request is currently in progress.
+
+ refetch: () => void; // 👈 A function that can be called to refetch the data.
+ // Ideal for revalidating stale data after a mutation.
+}
+```
+
+## `request`
+
+`request` is a function that allows you to fetch data. It is a wrapper around `fetch` that adds some useful features. It can be used in both React components and non-React code. For fetching data in React components, prefer using `useQuery`. For mutations, use `request`.
+
+### `request` usage
+
+```ts
+import { request } from "@care/request";
+import FooRoutes from "@foo/routes";
+
+export default async function updateFoo(id: string, object: Foo) {
+ const { res, data } = await request(FooRoutes.updateFoo, {
+ pathParams: { id },
+ body: object, // 👈 The body is automatically serialized to JSON.
+ });
+
+ if (res.status === 403) {
+ navigate("/forbidden");
+ return null;
+ }
+
+ return data;
+}
+```