diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb
new file mode 100644
index 000000000..f781f0089
--- /dev/null
+++ b/app/controllers/api/v1/profiles_controller.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class Api::V1::ProfilesController < Api::BaseController
+  before_action -> { doorkeeper_authorize! :write, :'write:accounts' }
+  before_action :require_user!
+  before_action :set_image
+  before_action :validate_image_param
+
+  def destroy
+    @account = current_account
+    UpdateAccountService.new.call(@account, { @image => nil }, raise_error: true)
+    ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
+    render json: @account, serializer: REST::CredentialAccountSerializer
+  end
+
+  private
+
+  def set_image
+    @image = params[:image]
+  end
+
+  def validate_image_param
+    raise(Mastodon::InvalidParameterError, 'Image must be either "avatar" or "header"') unless valid_image?
+  end
+
+  def valid_image?
+    %w(avatar header).include?(@image)
+  end
+end
diff --git a/config/routes/api.rb b/config/routes/api.rb
index 48c4c6522..dc6aea7f7 100644
--- a/config/routes/api.rb
+++ b/config/routes/api.rb
@@ -95,6 +95,7 @@ namespace :api, format: false do
     resources :filters, only: [:index, :create, :show, :update, :destroy]
     resources :endorsements, only: [:index]
     resources :markers, only: [:index, :create]
+    resources :profile, only: :destroy, param: :image, controller: 'profiles'
 
     namespace :apps do
       get :verify_credentials, to: 'credentials#show'
diff --git a/spec/requests/api/v1/profiles_spec.rb b/spec/requests/api/v1/profiles_spec.rb
new file mode 100644
index 000000000..9fa5fd329
--- /dev/null
+++ b/spec/requests/api/v1/profiles_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Deleting profile images' do
+  let(:account) do
+    Fabricate(
+      :account,
+      avatar: fixture_file_upload('avatar.gif', 'image/gif'),
+      header: fixture_file_upload('attachment.jpg', 'image/jpeg')
+    )
+  end
+  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: account.user.id, scopes: scopes) }
+  let(:scopes)  { 'write:accounts' }
+  let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
+
+  describe 'DELETE /api/v1/profile' do
+    before do
+      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
+    end
+
+    context 'when deleting an avatar' do
+      context 'with wrong scope' do
+        before do
+          delete '/api/v1/profile/avatar', headers: headers
+        end
+
+        it_behaves_like 'forbidden for wrong scope', 'read'
+      end
+
+      it 'returns http success' do
+        delete '/api/v1/profile/avatar', headers: headers
+
+        expect(response).to have_http_status(200)
+      end
+
+      it 'deletes the avatar' do
+        delete '/api/v1/profile/avatar', headers: headers
+
+        account.reload
+
+        expect(account.avatar).to_not exist
+      end
+
+      it 'does not delete the header' do
+        delete '/api/v1/profile/avatar', headers: headers
+
+        account.reload
+
+        expect(account.header).to exist
+      end
+
+      it 'queues up an account update distribution' do
+        delete '/api/v1/profile/avatar', headers: headers
+
+        expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
+      end
+    end
+
+    context 'when deleting a header' do
+      context 'with wrong scope' do
+        before do
+          delete '/api/v1/profile/header', headers: headers
+        end
+
+        it_behaves_like 'forbidden for wrong scope', 'read'
+      end
+
+      it 'returns http success' do
+        delete '/api/v1/profile/header', headers: headers
+
+        expect(response).to have_http_status(200)
+      end
+
+      it 'does not delete the avatar' do
+        delete '/api/v1/profile/header', headers: headers
+
+        account.reload
+
+        expect(account.avatar).to exist
+      end
+
+      it 'deletes the header' do
+        delete '/api/v1/profile/header', headers: headers
+
+        account.reload
+
+        expect(account.header).to_not exist
+      end
+
+      it 'queues up an account update distribution' do
+        delete '/api/v1/profile/header', headers: headers
+
+        expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
+      end
+    end
+
+    context 'when provided picture value is invalid' do
+      it 'returns http bad request' do
+        delete '/api/v1/profile/invalid', headers: headers
+
+        expect(response).to have_http_status(400)
+      end
+
+      it 'does not queue up an account update distribution' do
+        delete '/api/v1/profile/invalid', headers: headers
+
+        expect(ActivityPub::UpdateDistributionWorker).to_not have_received(:perform_async).with(account.id)
+      end
+    end
+  end
+end