diff --git a/.kamal/secrets b/.kamal/secrets
index 5663118..a5dbb56 100644
--- a/.kamal/secrets
+++ b/.kamal/secrets
@@ -2,10 +2,13 @@
 # and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
 # password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
 
-SECRETS=$(kamal secrets fetch --adapter 1password --account Perrault --from Private/sloanelybutsurely.com KAMAL_REGISTRY_PASSWORD POSTGRES_PASSWORD SECRET_KEY_BASE)
+SECRETS=$(kamal secrets fetch --adapter 1password --account Perrault --from Private/sloanelybutsurely.com KAMAL_REGISTRY_PASSWORD POSTGRES_PASSWORD SECRET_KEY_BASE MASTODON_CLIENT_ID MASTODON_CLIENT_SECRET)
 
 KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD $SECRETS)
 POSTGRES_PASSWORD=$(kamal secrets extract POSTGRES_PASSWORD $SECRETS)
 SECRET_KEY_BASE=$(kamal secrets extract SECRET_KEY_BASE $SECRETS)
 
 DATABASE_URL="postgresql://sloanely_but_surely_prod:$POSTGRES_PASSWORD@sloanelybutsurely-db:5432/sloanely_but_surely_prod"
+
+MASTODON_CLIENT_ID=$(kamal secrets extract MASTODON_CLIENT_ID $SECRETS)
+MASTODON_CLIENT_SECRET=$(kamal secrets extract MASTODON_CLIENT_SECRET $SECRETS)
diff --git a/config/config.exs b/config/config.exs
index e3b35dc..d8d5fa0 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -59,4 +59,18 @@ config :tailwind,
 
 config :flop, repo: Core.Repo
 
+config :tesla, adapter: Tesla.Adapter.Mint
+
+config :ueberauth, Ueberauth,
+  providers: [
+    mastodon:
+      {Ueberauth.Strategy.Mastodon,
+       [
+         instance: "https://tech.lgbt",
+         client_id: {System, :get_env, ["MASTODON_CLIENT_ID"]},
+         client_secret: {System, :get_env, ["MASTODON_CLIENT_SECRET"]},
+         scope: "read write push"
+       ]}
+  ]
+
 import_config "#{config_env()}.exs"
diff --git a/config/deploy.yml b/config/deploy.yml
index ffbb3a3..1f7f472 100644
--- a/config/deploy.yml
+++ b/config/deploy.yml
@@ -12,6 +12,8 @@ env:
   secret:
     - DATABASE_URL
     - SECRET_KEY_BASE
+    - MASTODON_CLIENT_ID
+    - MASTODON_CLIENT_SECRET
 
 # Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server.
 # Remove this section when using multiple web servers and ensure you terminate SSL at your load balancer.
diff --git a/lib/core.ex b/lib/core.ex
index 73576ec..80fb3a5 100644
--- a/lib/core.ex
+++ b/lib/core.ex
@@ -1,4 +1,4 @@
 defmodule Core do
   @moduledoc false
-  use Boundary, deps: [Schema], exports: [Accounts, Posts, Author, DateTime, Release]
+  use Boundary, deps: [Schema], exports: [Accounts, Posts, Author, DateTime, Release, Syndication]
 end
diff --git a/lib/core/syndication.ex b/lib/core/syndication.ex
new file mode 100644
index 0000000..fcf06d4
--- /dev/null
+++ b/lib/core/syndication.ex
@@ -0,0 +1,14 @@
+defmodule Core.Syndication do
+  alias __MODULE__
+
+  def get_mastodon_account(user) do
+    Core.Repo.get_by(Schema.MastodonAccount, user_id: user.id)
+  end
+
+  def save_mastodon_account(user, attrs) do
+    user
+    |> Ecto.build_assoc(:mastodon_account)
+    |> Syndication.MastodonAccount.changeset(attrs)
+    |> Core.Repo.insert()
+  end
+end
diff --git a/lib/core/syndication/mastodon_account.ex b/lib/core/syndication/mastodon_account.ex
new file mode 100644
index 0000000..c5dd548
--- /dev/null
+++ b/lib/core/syndication/mastodon_account.ex
@@ -0,0 +1,11 @@
+defmodule Core.Syndication.MastodonAccount do
+  import Ecto.Changeset
+
+  def changeset(%Schema.MastodonAccount{} = mastodon_account, attrs) do
+    mastodon_account
+    |> cast(attrs, [:uid, :access_token])
+    |> validate_required([:uid, :access_token])
+    |> unique_constraint(:user_id)
+    |> unique_constraint(:uid)
+  end
+end
diff --git a/lib/schema.ex b/lib/schema.ex
index a886b6d..bd4adfc 100644
--- a/lib/schema.ex
+++ b/lib/schema.ex
@@ -1,6 +1,6 @@
 defmodule Schema do
   @moduledoc false
-  use Boundary, deps: [], exports: [Post, User, UserToken]
+  use Boundary, deps: [], exports: [Post, User, UserToken, MastodonAccount]
 
   defmacro __using__(_) do
     quote do
diff --git a/lib/schema/mastodon_account.ex b/lib/schema/mastodon_account.ex
new file mode 100644
index 0000000..2f16c73
--- /dev/null
+++ b/lib/schema/mastodon_account.ex
@@ -0,0 +1,12 @@
+defmodule Schema.MastodonAccount do
+  use Schema
+
+  schema "mastodon_accounts" do
+    field :uid, :string
+    field :access_token, :string, redact: true
+
+    belongs_to :user, Schema.User
+
+    timestamps()
+  end
+end
diff --git a/lib/schema/user.ex b/lib/schema/user.ex
index 900262a..21c4e49 100644
--- a/lib/schema/user.ex
+++ b/lib/schema/user.ex
@@ -8,6 +8,8 @@ defmodule Schema.User do
     field :hashed_password, :string, redact: true
     field :current_password, :string, virtual: true, redact: true
 
+    has_one :mastodon_account, Schema.MastodonAccount
+
     timestamps(type: :utc_datetime_usec)
   end
 end
diff --git a/lib/web/controllers/auth_controller.ex b/lib/web/controllers/auth_controller.ex
new file mode 100644
index 0000000..f664c11
--- /dev/null
+++ b/lib/web/controllers/auth_controller.ex
@@ -0,0 +1,26 @@
+defmodule Web.AuthController do
+  use Web, :controller
+
+  plug Ueberauth
+
+  def callback(
+        %{assigns: %{ueberauth_auth: %{provider: :mastodon} = auth, current_user: user}} = conn,
+        _params
+      ) do
+    {:ok, _mastodon_account} =
+      Core.Syndication.save_mastodon_account(user, %{
+        uid: auth.uid,
+        access_token: auth.credentials.token
+      })
+
+    conn
+    |> put_flash(:info, "Mastodon account registered")
+    |> redirect(to: ~p"/admin/syndication")
+  end
+
+  def callback(conn, _params) do
+    conn
+    |> put_flash(:error, "Mastodon auth failure")
+    |> redirect(to: ~p"/admin/syndication")
+  end
+end
diff --git a/lib/web/live/admin_dashboard_live.html.heex b/lib/web/live/admin_dashboard_live.html.heex
index e07c2df..62e64a3 100644
--- a/lib/web/live/admin_dashboard_live.html.heex
+++ b/lib/web/live/admin_dashboard_live.html.heex
@@ -12,6 +12,11 @@
             microblog
           </.link>
         </li>
+        <li>
+          <.link navigate={~p"/admin/syndication"}>
+            syndication
+          </.link>
+        </li>
       </ul>
     </nav>
   </header>
diff --git a/lib/web/live/admin_syndication_live.ex b/lib/web/live/admin_syndication_live.ex
new file mode 100644
index 0000000..d2eb034
--- /dev/null
+++ b/lib/web/live/admin_syndication_live.ex
@@ -0,0 +1,13 @@
+defmodule Web.AdminSyndicationLive do
+  use Web, :live_view
+
+  def mount(_params, _session, socket) do
+    mastodon_account = Core.Syndication.get_mastodon_account(socket.assigns.current_user)
+
+    socket =
+      socket
+      |> assign(:mastodon_account, mastodon_account)
+
+    {:ok, socket}
+  end
+end
diff --git a/lib/web/live/admin_syndication_live.html.heex b/lib/web/live/admin_syndication_live.html.heex
new file mode 100644
index 0000000..9522e66
--- /dev/null
+++ b/lib/web/live/admin_syndication_live.html.heex
@@ -0,0 +1,37 @@
+<div class="flex flex-col py-4 px-6">
+  <header class="mb-4">
+    <nav>
+      <ul class="flex flex-row gap-x-4">
+        <li>
+          <.link navigate={~p"/admin/writing"}>
+            writing
+          </.link>
+        </li>
+        <li>
+          <.link navigate={~p"/admin/microblog"}>
+            microblog
+          </.link>
+        </li>
+        <li>
+          <.link class="underline" patch={~p"/admin/syndication"}>
+            syndication
+          </.link>
+        </li>
+      </ul>
+    </nav>
+  </header>
+
+  <main class="flex flex-col">
+    <div>
+      <strong>Mastodon: </strong>
+      <%= if @mastodon_account do %>
+        <.link href={@mastodon_account.uid} target="_blank">{@mastodon_account.uid}</.link>
+      <% else %>
+        <.link href={~p"/auth/mastodon"}>Connect account</.link>
+      <% end %>
+    </div>
+    <div>
+      <strong>Bluesky: </strong>Coming soon!
+    </div>
+  </main>
+</div>
diff --git a/lib/web/router.ex b/lib/web/router.ex
index d418ae0..6c540e4 100644
--- a/lib/web/router.ex
+++ b/lib/web/router.ex
@@ -25,6 +25,13 @@ defmodule Web.Router do
     post "/admin/users/log_in", UserSessionController, :create
   end
 
+  scope "/auth", Web do
+    pipe_through [:browser, :require_authenticated_user]
+
+    get "/mastodon", AuthController, :request
+    get "/mastodon/callback", AuthController, :callback
+  end
+
   scope "/admin", Web do
     pipe_through [:browser, :require_authenticated_user]
 
@@ -36,6 +43,8 @@ defmodule Web.Router do
 
       live "/posts/new", AdminPostLive, :new
       live "/posts/:post_id", AdminPostLive, :edit
+
+      live "/syndication", AdminSyndicationLive, :index
     end
   end
 
diff --git a/mix.exs b/mix.exs
index e2add4f..2c11260 100644
--- a/mix.exs
+++ b/mix.exs
@@ -66,6 +66,10 @@ defmodule SlaonelyButSurely.MixProject do
       {:flop_phoenix, "~> 0.24.1"},
       {:oban, "~> 2.19"},
       {:igniter, "~> 0.5", only: [:dev]},
+      {:ueberauth, "~> 0.10"},
+      {:ueberauth_mastodon, "~> 0.3.0"},
+      {:tesla, "~> 1.14"},
+      {:mint, "~> 1.7"},
 
       # Added dev and/or test dependencies
       {:credo, "~> 1.7", only: [:dev, :test], runtime: false},
diff --git a/mix.lock b/mix.lock
index 6595e57..3b392d2 100644
--- a/mix.lock
+++ b/mix.lock
@@ -31,6 +31,7 @@
   "igniter": {:hex, :igniter, "0.5.47", "7a1041d5e38303e526fa6b6de37c9e78013f5cb573833ed51183d18e3a152f10", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "53a900909e20f217a25d15a34fef629c562b4822c1fb39cfa5d6999bc72992ed"},
   "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
   "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
+  "mastodon_client": {:hex, :mastodon_client, "0.1.0", "7f1a9e54367d0e126c76d0bb1097de346fb9c6da6d682a6b57bc936c92d643eb", [:mix], [{:hackney, "~> 1.18", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:tesla, "~> 1.4", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "3daa37fc7a95430eb0b77cdb168af58b8db84efea6e0f3244d15d45f39a87160"},
   "mdex": {:hex, :mdex, "0.5.0", "252c83cebc6a089801dfc1e142b4d98c9c358378ec7096a94796bce8bd13b0fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:rustler, "~> 0.32", [hex: :rustler, repo: "hexpm", optional: false]}, {:rustler_precompiled, "~> 0.7", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "73e3ddee03130267e3be6aaf47a7f423c6f86add4bb5c62b352465cd9fb87d95"},
   "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
   "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
@@ -65,12 +66,15 @@
   "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
   "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"},
   "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
+  "tesla": {:hex, :tesla, "1.14.1", "71c5b031b4e089c0fbfb2b362e24b4478465773ae4ef569760a8c2899ad1e73c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:mox, "~> 1.0", [hex: :mox, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "c1dde8140a49a3bef5bb622356e77ac5a24ad0c8091f12c3b7fc1077ce797155"},
   "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"},
   "thousand_island": {:hex, :thousand_island, "1.3.10", "a9971ebab1dfb36e2710a86b37c3f54973fbc9470d892035334415521fb53328", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17ab1f1b13aadb1f4b4c8e5b59c06874d701119fed082884c9c6d38addad254f"},
   "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
   "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},
   "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"},
   "tzdata": {:hex, :tzdata, "1.1.2", "45e5f1fcf8729525ec27c65e163be5b3d247ab1702581a94674e008413eef50b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cec7b286e608371602318c414f344941d5eb0375e14cfdab605cca2fe66cba8b"},
+  "ueberauth": {:hex, :ueberauth, "0.10.8", "ba78fbcbb27d811a6cd06ad851793aaf7d27c3b30c9e95349c2c362b344cd8f0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f2d3172e52821375bccb8460e5fa5cb91cfd60b19b636b6e57e9759b6f8c10c1"},
+  "ueberauth_mastodon": {:hex, :ueberauth_mastodon, "0.3.0", "e0b80adc29d8734f74cac908d25e2113739112ea84b95f3c9f27ef3161128426", [:mix], [{:hackney, "~> 1.20", [hex: :hackney, repo: "hexpm", optional: true]}, {:mastodon_client, "~> 0.1", [hex: :mastodon_client, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.10.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "28a049497b3b708a232c8d6da1c7fb80c92ae4a6961f2c9274dfe9333a1aa7d0"},
   "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
   "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
   "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"},
diff --git a/priv/repo/migrations/20250429161028_create_mastodon_auth_tables.exs b/priv/repo/migrations/20250429161028_create_mastodon_auth_tables.exs
new file mode 100644
index 0000000..8057d33
--- /dev/null
+++ b/priv/repo/migrations/20250429161028_create_mastodon_auth_tables.exs
@@ -0,0 +1,17 @@
+defmodule Core.Repo.Migrations.CreateMastodonAuthTables do
+  use Ecto.Migration
+
+  def change do
+    create table(:mastodon_accounts, primary_key: false) do
+      add :id, :uuid, primary_key: true
+      add :user_id, references(:users, type: :binary_id, on_delete: :delete_all), null: false
+      add :uid, :text, null: false
+      add :access_token, :text, null: false
+
+      timestamps(type: :utc_datetime_usec)
+    end
+
+    create unique_index(:mastodon_accounts, [:user_id])
+    create unique_index(:mastodon_accounts, [:uid])
+  end
+end
diff --git a/scripts/register_mastodon_application.exs b/scripts/register_mastodon_application.exs
new file mode 100755
index 0000000..673333d
--- /dev/null
+++ b/scripts/register_mastodon_application.exs
@@ -0,0 +1,39 @@
+#!/usr/bin/env elixir
+
+Mix.install([
+  {:req, "~> 0.5.10"}
+])
+
+{opts, []} =
+  OptionParser.parse!(System.argv(),
+    strict: [
+      instance: :string,
+      client_name: :string,
+      redirect_uri: :string,
+      scopes: :string,
+      website: :string
+    ]
+  )
+
+instance = Keyword.fetch!(opts, :instance)
+client_name = Keyword.get(opts, :client_name, "sloanelybutsurely.com")
+
+redirect_uri =
+  Keyword.get(opts, :redirect_uri, "https://sloanelybutsurely.com/auth/mastodon/callback")
+
+scopes = Keyword.get(opts, :scopes, "read write push")
+website = Keyword.get(opts, :website, "https://sloanelybutsurely.com")
+
+%{status: 200, body: resp} =
+  Req.post!(
+    base_url: instance,
+    url: "/api/v1/apps",
+    json: %{
+      client_name: client_name,
+      redirect_uris: [redirect_uri],
+      scopes: scopes,
+      website: website
+    }
+  )
+
+IO.inspect(resp)