diff --git a/CHANGELOG.md b/CHANGELOG.md
index c050e7e5..aedfc16a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ Versia Server `0.8.0` is fully backwards compatible with `0.7.0`.
- Added an administration UI for managing the queue.
- Upgraded Bun to `1.1.36`.
- Implemented support for the [Instance Messaging Extension](https://versia.pub/extensions/instance-messaging)
+- Implement [Shared Inboxes](https://versia.pub/federation#inboxes)
- Allowed `
` and `` tags in Markdown.
- Added `--password` flag to the user creation CLI.
diff --git a/api/inbox/index.ts b/api/inbox/index.ts
new file mode 100644
index 00000000..d7be515f
--- /dev/null
+++ b/api/inbox/index.ts
@@ -0,0 +1,73 @@
+import { apiRoute, applyConfig } from "@/api";
+import { createRoute } from "@hono/zod-openapi";
+import type { Entity } from "@versia/federation/types";
+import { z } from "zod";
+import { InboxJobType, inboxQueue } from "~/worker";
+
+export const meta = applyConfig({
+ auth: {
+ required: false,
+ },
+ ratelimits: {
+ duration: 60,
+ max: 500,
+ },
+ route: "/inbox",
+});
+
+export const schemas = {
+ header: z.object({
+ "x-signature": z.string().optional(),
+ "x-nonce": z.string().optional(),
+ "x-signed-by": z
+ .string()
+ .url()
+ .or(z.string().startsWith("instance "))
+ .optional(),
+ authorization: z.string().optional(),
+ }),
+ body: z.any(),
+};
+
+const route = createRoute({
+ method: "post",
+ path: "/inbox",
+ summary: "Instance federation inbox",
+ request: {
+ headers: schemas.header,
+ body: {
+ content: {
+ "application/json": {
+ schema: schemas.body,
+ },
+ },
+ },
+ },
+ responses: {
+ 200: {
+ description: "Request processing initiated",
+ },
+ },
+});
+
+export default apiRoute((app) =>
+ app.openapi(route, async (context) => {
+ const body: Entity = await context.req.valid("json");
+
+ await inboxQueue.add(InboxJobType.ProcessEntity, {
+ data: body,
+ headers: context.req.valid("header"),
+ request: {
+ body: await context.req.text(),
+ method: context.req.method,
+ url: context.req.url,
+ },
+ ip: context.env.ip ?? null,
+ });
+
+ return context.newResponse(
+ "Request processing initiated.\nImplement the Instance Messaging Extension to receive any eventual errors",
+ 200,
+ );
+ }),
+);
diff --git a/api/well-known/versia.ts b/api/well-known/versia.ts
index 002d29d0..2d765354 100644
--- a/api/well-known/versia.ts
+++ b/api/well-known/versia.ts
@@ -63,6 +63,10 @@ export default apiRoute((app) =>
},
banner: urlToContentFormat(config.instance.banner),
logo: urlToContentFormat(config.instance.logo),
+ shared_inbox: new URL(
+ "/inbox",
+ config.http.base_url,
+ ).toString(),
created_at: new Date(
firstUser?.data.createdAt ?? 0,
).toISOString(),