diff --git a/lib/federation/activity_stream/converter/event.ex b/lib/federation/activity_stream/converter/event.ex
index fcb5e31fa..b415b4e8a 100644
--- a/lib/federation/activity_stream/converter/event.ex
+++ b/lib/federation/activity_stream/converter/event.ex
@@ -10,7 +10,6 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
   alias Mobilizon.Addresses
   alias Mobilizon.Addresses.Address
   alias Mobilizon.Events.Event, as: EventModel
-  alias Mobilizon.Medias.Media
 
   alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
   alias Mobilizon.Federation.ActivityStream.Converter.Address, as: AddressConverter
@@ -21,7 +20,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
       fetch_tags: 1,
       fetch_mentions: 1,
       build_tags: 1,
-      maybe_fetch_actor_and_attributed_to_id: 1
+      maybe_fetch_actor_and_attributed_to_id: 1,
+      process_pictures: 2
     ]
 
   require Logger
@@ -34,6 +34,9 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
     defdelegate model_to_as(event), to: EventConverter
   end
 
+  @online_address_name "Website"
+  @banner_picture_name "Banner"
+
   @doc """
   Converts an AP object data to our internal data structure.
   """
@@ -47,30 +50,16 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
          {:tags, tags} <- {:tags, fetch_tags(object["tag"])},
          {:mentions, mentions} <- {:mentions, fetch_mentions(object["tag"])},
          {:visibility, visibility} <- {:visibility, get_visibility(object)},
-         {:options, options} <- {:options, get_options(object)} do
-      attachments =
-        object
-        |> Map.get("attachment", [])
-        |> Enum.filter(fn attachment -> Map.get(attachment, "type", "Document") == "Document" end)
-
-      picture_id =
-        with true <- length(attachments) > 0,
-             {:ok, %Media{id: picture_id}} <-
-               attachments
-               |> hd()
-               |> MediaConverter.find_or_create_media(actor_id) do
-          picture_id
-        else
-          _err ->
-            nil
-        end
-
+         {:options, options} <- {:options, get_options(object)},
+         [description: description, picture_id: picture_id, medias: medias] <-
+           process_pictures(object, actor_id) do
       %{
         title: object["name"],
-        description: object["content"],
+        description: description,
         organizer_actor_id: actor_id,
         attributed_to_id: if(is_nil(attributed_to), do: nil, else: attributed_to.id),
         picture_id: picture_id,
+        medias: medias,
         begins_on: object["startTime"],
         ends_on: object["endTime"],
         category: object["category"],
@@ -143,6 +132,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
     |> maybe_add_physical_address(event)
     |> maybe_add_event_picture(event)
     |> maybe_add_online_address(event)
+    |> maybe_add_inline_media(event)
   end
 
   # Get only elements that we have in EventOptions
@@ -213,7 +203,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
           "type" => "Link",
           "href" => url,
           "mediaType" => "text/html",
-          "name" => "Website"
+          "name" => @online_address_name
         } ->
           url
 
@@ -239,7 +229,12 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
           res,
           "attachment",
           [],
-          &(&1 ++ [MediaConverter.model_to_as(event.picture)])
+          &(&1 ++
+              [
+                event.picture
+                |> MediaConverter.model_to_as()
+                |> Map.put("name", @banner_picture_name)
+              ])
         )
   end
 
@@ -258,9 +253,21 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
                   "type" => "Link",
                   "href" => event.online_address,
                   "mediaType" => "text/html",
-                  "name" => "Website"
+                  "name" => @online_address_name
                 }
               ])
         )
   end
+
+  @spec maybe_add_inline_media(map(), Event.t()) :: map()
+  defp maybe_add_inline_media(res, event) do
+    medias = Enum.map(event.media, &MediaConverter.model_to_as/1)
+
+    Map.update(
+      res,
+      "attachment",
+      [],
+      &(&1 ++ medias)
+    )
+  end
 end
diff --git a/lib/federation/activity_stream/converter/post.ex b/lib/federation/activity_stream/converter/post.ex
index 823c471e0..7798a3a8c 100644
--- a/lib/federation/activity_stream/converter/post.ex
+++ b/lib/federation/activity_stream/converter/post.ex
@@ -9,9 +9,15 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
   alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Federation.ActivityPub.Utils
   alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.Converter.Media, as: MediaConverter
   alias Mobilizon.Posts.Post
   require Logger
 
+  import Mobilizon.Federation.ActivityStream.Converter.Utils,
+    only: [
+      process_pictures: 2
+    ]
+
   @behaviour Converter
 
   defimpl Convertible, for: Post do
@@ -20,6 +26,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
     defdelegate model_to_as(post), to: PostConverter
   end
 
+  @banner_picture_name "Banner"
+
   @doc """
   Convert an post struct to an ActivityStream representation
   """
@@ -35,8 +43,11 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
       "name" => post.title,
       "content" => post.body,
       "attributedTo" => creator_url,
-      "published" => (post.publish_at || post.inserted_at) |> to_date()
+      "published" => (post.publish_at || post.inserted_at) |> to_date(),
+      "attachment" => []
     }
+    |> maybe_add_post_picture(post)
+    |> maybe_add_inline_media(post)
   end
 
   @doc """
@@ -48,15 +59,19 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
         %{"type" => "Article", "actor" => creator, "attributedTo" => group} = object
       ) do
     with {:ok, %Actor{id: attributed_to_id}} <- get_actor(group),
-         {:ok, %Actor{id: author_id}} <- get_actor(creator) do
+         {:ok, %Actor{id: author_id}} <- get_actor(creator),
+         [description: description, picture_id: picture_id, medias: medias] <-
+           process_pictures(object, attributed_to_id) do
       %{
         title: object["name"],
-        body: object["content"],
+        body: description,
         url: object["id"],
         attributed_to_id: attributed_to_id,
         author_id: author_id,
         local: false,
-        publish_at: object["published"]
+        publish_at: object["published"],
+        picture_id: picture_id,
+        medias: medias
       }
     else
       {:error, err} -> {:error, err}
@@ -70,4 +85,34 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
 
   defp to_date(%DateTime{} = date), do: DateTime.to_iso8601(date)
   defp to_date(%NaiveDateTime{} = date), do: NaiveDateTime.to_iso8601(date)
+
+  @spec maybe_add_post_picture(map(), Post.t()) :: map()
+  defp maybe_add_post_picture(res, post) do
+    if is_nil(post.picture),
+      do: res,
+      else:
+        Map.update(
+          res,
+          "attachment",
+          [],
+          &(&1 ++
+              [
+                post.picture
+                |> MediaConverter.model_to_as()
+                |> Map.put("name", @banner_picture_name)
+              ])
+        )
+  end
+
+  @spec maybe_add_inline_media(map(), Post.t()) :: map()
+  defp maybe_add_inline_media(res, post) do
+    medias = Enum.map(post.media, &MediaConverter.model_to_as/1)
+
+    Map.update(
+      res,
+      "attachment",
+      [],
+      &(&1 ++ medias)
+    )
+  end
 end
diff --git a/lib/federation/activity_stream/converter/utils.ex b/lib/federation/activity_stream/converter/utils.ex
index b06c9fa3f..beb08fe03 100644
--- a/lib/federation/activity_stream/converter/utils.ex
+++ b/lib/federation/activity_stream/converter/utils.ex
@@ -6,15 +6,19 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
   alias Mobilizon.{Actors, Events}
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.Tag
+  alias Mobilizon.Medias.Media
   alias Mobilizon.Mention
   alias Mobilizon.Storage.Repo
 
   alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityStream.Converter.Media, as: MediaConverter
 
   alias Mobilizon.Web.Endpoint
 
   require Logger
 
+  @banner_picture_name "Banner"
+
   @spec fetch_tags([String.t()]) :: [Tag.t()]
   def fetch_tags(tags) when is_list(tags) do
     Logger.debug("fetching tags")
@@ -169,4 +173,62 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
       actor
     end
   end
+
+  @spec process_pictures(map(), integer()) :: Keyword.t()
+  def process_pictures(object, actor_id) do
+    attachements = Map.get(object, "attachment", [])
+
+    media_attachements = get_medias(attachements)
+
+    media_attachements_map =
+      media_attachements
+      |> Enum.map(fn media_attachement ->
+        {media_attachement["url"],
+         MediaConverter.find_or_create_media(media_attachement, actor_id)}
+      end)
+      |> Enum.reduce(%{}, fn {old_url, media}, acc ->
+        case media do
+          {:ok, %Media{} = media} ->
+            Map.put(acc, old_url, media)
+
+          _ ->
+            acc
+        end
+      end)
+
+    media_attachements_map_urls =
+      media_attachements_map
+      |> Enum.map(fn {old_url, new_media} -> {old_url, new_media.file.url} end)
+      |> Map.new()
+
+    picture_id =
+      with banner when is_map(banner) <- get_banner_picture(attachements),
+           {:ok, %Media{id: picture_id}} <-
+             MediaConverter.find_or_create_media(banner, actor_id) do
+        picture_id
+      else
+        _err ->
+          nil
+      end
+
+    description = replace_media_urls_in_body(object["content"], media_attachements_map_urls)
+    [description: description, picture_id: picture_id, medias: Map.values(media_attachements_map)]
+  end
+
+  defp replace_media_urls_in_body(body, media_urls),
+    do:
+      Enum.reduce(media_urls, body, fn media_url, body ->
+        replace_media_url_in_body(body, media_url)
+      end)
+
+  defp replace_media_url_in_body(body, {old_url, new_url}),
+    do: String.replace(body, old_url, new_url)
+
+  defp get_medias(attachments) do
+    Enum.filter(attachments, &(&1["type"] == "Document" && &1["name"] != @banner_picture_name))
+  end
+
+  defp get_banner_picture(attachments) do
+    Enum.find(attachments, &(&1["type"] == "Document" && &1["name"] == @banner_picture_name))
+  end
 end
diff --git a/lib/mobilizon/posts/posts.ex b/lib/mobilizon/posts/posts.ex
index d8da3e4a4..b75e835c5 100644
--- a/lib/mobilizon/posts/posts.ex
+++ b/lib/mobilizon/posts/posts.ex
@@ -10,7 +10,7 @@ defmodule Mobilizon.Posts do
   import Ecto.Query
   require Logger
 
-  @post_preloads [:author, :attributed_to, :picture]
+  @post_preloads [:author, :attributed_to, :picture, :media]
 
   import EctoEnum
 
diff --git a/lib/web/views/page_view.ex b/lib/web/views/page_view.ex
index b70a4ff43..92e625d3f 100644
--- a/lib/web/views/page_view.ex
+++ b/lib/web/views/page_view.ex
@@ -8,6 +8,7 @@ defmodule Mobilizon.Web.PageView do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Discussions.{Comment, Discussion}
   alias Mobilizon.Events.Event
+  alias Mobilizon.Posts.Post
   alias Mobilizon.Resources.Resource
   alias Mobilizon.Tombstone
 
@@ -54,6 +55,12 @@ defmodule Mobilizon.Web.PageView do
     |> Map.merge(Utils.make_json_ld_header())
   end
 
+  def render("post.activity-json", %{conn: %{assigns: %{object: %Post{} = post}}}) do
+    post
+    |> Convertible.model_to_as()
+    |> Map.merge(Utils.make_json_ld_header())
+  end
+
   def render(page, %{object: object, conn: conn} = _assigns)
       when page in ["actor.html", "event.html", "comment.html", "post.html"] do
     locale = get_locale(conn)