diff --git a/app/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rb b/app/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rb
new file mode 100644
index 000000000..ac1d0a712
--- /dev/null
+++ b/app/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rb
@@ -0,0 +1,20 @@
+class Api::V1::Accounts::AssignmentPolicies::InboxesController < Api::V1::Accounts::BaseController
+  before_action :fetch_assignment_policy
+  before_action -> { check_authorization(AssignmentPolicy) }
+
+  def index
+    @inboxes = @assignment_policy.inboxes
+  end
+
+  private
+
+  def fetch_assignment_policy
+    @assignment_policy = Current.account.assignment_policies.find(
+      params[:assignment_policy_id]
+    )
+  end
+
+  def permitted_params
+    params.permit(:assignment_policy_id)
+  end
+end
diff --git a/app/controllers/api/v1/accounts/assignment_policies_controller.rb b/app/controllers/api/v1/accounts/assignment_policies_controller.rb
new file mode 100644
index 000000000..1807d6afb
--- /dev/null
+++ b/app/controllers/api/v1/accounts/assignment_policies_controller.rb
@@ -0,0 +1,36 @@
+class Api::V1::Accounts::AssignmentPoliciesController < Api::V1::Accounts::BaseController
+  before_action :fetch_assignment_policy, only: [:show, :update, :destroy]
+  before_action :check_authorization
+
+  def index
+    @assignment_policies = Current.account.assignment_policies
+  end
+
+  def show; end
+
+  def create
+    @assignment_policy = Current.account.assignment_policies.create!(assignment_policy_params)
+  end
+
+  def update
+    @assignment_policy.update!(assignment_policy_params)
+  end
+
+  def destroy
+    @assignment_policy.destroy!
+    head :ok
+  end
+
+  private
+
+  def fetch_assignment_policy
+    @assignment_policy = Current.account.assignment_policies.find(params[:id])
+  end
+
+  def assignment_policy_params
+    params.require(:assignment_policy).permit(
+      :name, :description, :assignment_order, :conversation_priority,
+      :fair_distribution_limit, :fair_distribution_window, :enabled
+    )
+  end
+end
diff --git a/app/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rb b/app/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rb
new file mode 100644
index 000000000..cf52951a5
--- /dev/null
+++ b/app/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rb
@@ -0,0 +1,46 @@
+class Api::V1::Accounts::Inboxes::AssignmentPoliciesController < Api::V1::Accounts::BaseController
+  before_action :fetch_inbox
+  before_action :fetch_assignment_policy, only: [:create]
+  before_action -> { check_authorization(AssignmentPolicy) }
+  before_action :validate_assignment_policy, only: [:show, :destroy]
+
+  def show
+    @assignment_policy = @inbox.assignment_policy
+  end
+
+  def create
+    # There should be only one assignment policy for an inbox.
+    # If there is a new request to add an assignment policy, we will
+    # delete the old one and attach the new policy
+    remove_inbox_assignment_policy
+    @inbox_assignment_policy = @inbox.create_inbox_assignment_policy!(assignment_policy: @assignment_policy)
+    @assignment_policy = @inbox.assignment_policy
+  end
+
+  def destroy
+    remove_inbox_assignment_policy
+    head :ok
+  end
+
+  private
+
+  def remove_inbox_assignment_policy
+    @inbox.inbox_assignment_policy&.destroy
+  end
+
+  def fetch_inbox
+    @inbox = Current.account.inboxes.find(permitted_params[:inbox_id])
+  end
+
+  def fetch_assignment_policy
+    @assignment_policy = Current.account.assignment_policies.find(permitted_params[:assignment_policy_id])
+  end
+
+  def permitted_params
+    params.permit(:assignment_policy_id, :inbox_id)
+  end
+
+  def validate_assignment_policy
+    return render_not_found_error(I18n.t('errors.assignment_policy.not_found')) unless @inbox.assignment_policy
+  end
+end
diff --git a/app/javascript/dashboard/components-next/Contacts/ContactsDetailsLayout.vue b/app/javascript/dashboard/components-next/Contacts/ContactsDetailsLayout.vue
index 51d306311..4c7b9249e 100644
--- a/app/javascript/dashboard/components-next/Contacts/ContactsDetailsLayout.vue
+++ b/app/javascript/dashboard/components-next/Contacts/ContactsDetailsLayout.vue
@@ -7,6 +7,7 @@ import { vOnClickOutside } from '@vueuse/components';
 import Button from 'dashboard/components-next/button/Button.vue';
 import Breadcrumb from 'dashboard/components-next/breadcrumb/Breadcrumb.vue';
 import ComposeConversation from 'dashboard/components-next/NewConversation/ComposeConversation.vue';
+import VoiceCallButton from 'dashboard/components-next/Contacts/VoiceCallButton.vue';
 
 const props = defineProps({
   selectedContact: {
@@ -99,6 +100,11 @@ const closeMobileSidebar = () => {
                 :disabled="isUpdating"
                 @click="toggleBlock"
               />
+              
               
                 
                   
         
+        
         
+import { mapActions } from 'vuex';
 import PreChatForm from '../components/PreChat/Form.vue';
 import configMixin from '../mixins/configMixin';
 import routerMixin from '../mixins/routerMixin';
@@ -19,6 +20,8 @@ export default {
     emitter.off(ON_CONVERSATION_CREATED, this.handleConversationCreated);
   },
   methods: {
+    ...mapActions('conversation', ['clearConversations']),
+    ...mapActions('conversationAttributes', ['clearConversationAttributes']),
     handleConversationCreated() {
       // Redirect to messages page after conversation is created
       this.replaceRoute('messages');
@@ -48,6 +51,8 @@ export default {
           },
         });
       } else {
+        this.clearConversations();
+        this.clearConversationAttributes();
         this.$store.dispatch('conversation/createConversation', {
           fullName: fullName,
           emailAddress: emailAddress,
diff --git a/app/models/account.rb b/app/models/account.rb
index f8eb998f0..b84d7f526 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -61,6 +61,7 @@ class Account < ApplicationRecord
   has_many :agent_bots, dependent: :destroy_async
   has_many :api_channels, dependent: :destroy_async, class_name: '::Channel::Api'
   has_many :articles, dependent: :destroy_async, class_name: '::Article'
+  has_many :assignment_policies, dependent: :destroy_async
   has_many :automation_rules, dependent: :destroy_async
   has_many :macros, dependent: :destroy_async
   has_many :campaigns, dependent: :destroy_async
diff --git a/app/models/assignment_policy.rb b/app/models/assignment_policy.rb
new file mode 100644
index 000000000..c01ab91c4
--- /dev/null
+++ b/app/models/assignment_policy.rb
@@ -0,0 +1,37 @@
+# == Schema Information
+#
+# Table name: assignment_policies
+#
+#  id                       :bigint           not null, primary key
+#  assignment_order         :integer          default(0), not null
+#  conversation_priority    :integer          default("earliest_created"), not null
+#  description              :text
+#  enabled                  :boolean          default(TRUE), not null
+#  fair_distribution_limit  :integer          default(100), not null
+#  fair_distribution_window :integer          default(3600), not null
+#  name                     :string(255)      not null
+#  created_at               :datetime         not null
+#  updated_at               :datetime         not null
+#  account_id               :bigint           not null
+#
+# Indexes
+#
+#  index_assignment_policies_on_account_id           (account_id)
+#  index_assignment_policies_on_account_id_and_name  (account_id,name) UNIQUE
+#  index_assignment_policies_on_enabled              (enabled)
+#
+class AssignmentPolicy < ApplicationRecord
+  belongs_to :account
+  has_many :inbox_assignment_policies, dependent: :destroy
+  has_many :inboxes, through: :inbox_assignment_policies
+
+  validates :name, presence: true, uniqueness: { scope: :account_id }
+  validates :fair_distribution_limit, numericality: { greater_than: 0 }
+  validates :fair_distribution_window, numericality: { greater_than: 0 }
+
+  enum conversation_priority: { earliest_created: 0, longest_waiting: 1 }
+
+  enum assignment_order: { round_robin: 0 } unless ChatwootApp.enterprise?
+end
+
+AssignmentPolicy.include_mod_with('Concerns::AssignmentPolicy')
diff --git a/app/models/inbox.rb b/app/models/inbox.rb
index 1c898ba7f..27f096bfa 100644
--- a/app/models/inbox.rb
+++ b/app/models/inbox.rb
@@ -67,6 +67,8 @@ class Inbox < ApplicationRecord
   has_many :conversations, dependent: :destroy_async
   has_many :messages, dependent: :destroy_async
 
+  has_one :inbox_assignment_policy, dependent: :destroy
+  has_one :assignment_policy, through: :inbox_assignment_policy
   has_one :agent_bot_inbox, dependent: :destroy_async
   has_one :agent_bot, through: :agent_bot_inbox
   has_many :webhooks, dependent: :destroy_async
diff --git a/app/models/inbox_assignment_policy.rb b/app/models/inbox_assignment_policy.rb
new file mode 100644
index 000000000..c263ab40e
--- /dev/null
+++ b/app/models/inbox_assignment_policy.rb
@@ -0,0 +1,21 @@
+# == Schema Information
+#
+# Table name: inbox_assignment_policies
+#
+#  id                   :bigint           not null, primary key
+#  created_at           :datetime         not null
+#  updated_at           :datetime         not null
+#  assignment_policy_id :bigint           not null
+#  inbox_id             :bigint           not null
+#
+# Indexes
+#
+#  index_inbox_assignment_policies_on_assignment_policy_id  (assignment_policy_id)
+#  index_inbox_assignment_policies_on_inbox_id              (inbox_id) UNIQUE
+#
+class InboxAssignmentPolicy < ApplicationRecord
+  belongs_to :inbox
+  belongs_to :assignment_policy
+
+  validates :inbox_id, uniqueness: true
+end
diff --git a/app/policies/assignment_policy_policy.rb b/app/policies/assignment_policy_policy.rb
new file mode 100644
index 000000000..fcd0ee9bc
--- /dev/null
+++ b/app/policies/assignment_policy_policy.rb
@@ -0,0 +1,21 @@
+class AssignmentPolicyPolicy < ApplicationPolicy
+  def index?
+    @account_user.administrator?
+  end
+
+  def show?
+    @account_user.administrator?
+  end
+
+  def create?
+    @account_user.administrator?
+  end
+
+  def update?
+    @account_user.administrator?
+  end
+
+  def destroy?
+    @account_user.administrator?
+  end
+end
diff --git a/app/views/api/v1/accounts/assignment_policies/_assignment_policy.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/_assignment_policy.json.jbuilder
new file mode 100644
index 000000000..b48307a94
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/_assignment_policy.json.jbuilder
@@ -0,0 +1,10 @@
+json.id assignment_policy.id
+json.name assignment_policy.name
+json.description assignment_policy.description
+json.assignment_order assignment_policy.assignment_order
+json.conversation_priority assignment_policy.conversation_priority
+json.fair_distribution_limit assignment_policy.fair_distribution_limit
+json.fair_distribution_window assignment_policy.fair_distribution_window
+json.enabled assignment_policy.enabled
+json.created_at assignment_policy.created_at.to_i
+json.updated_at assignment_policy.updated_at.to_i
diff --git a/app/views/api/v1/accounts/assignment_policies/create.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/create.json.jbuilder
new file mode 100644
index 000000000..8fd9543c3
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/create.json.jbuilder
@@ -0,0 +1 @@
+json.partial! 'assignment_policy', assignment_policy: @assignment_policy
diff --git a/app/views/api/v1/accounts/assignment_policies/inboxes/create.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/inboxes/create.json.jbuilder
new file mode 100644
index 000000000..c5aede050
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/inboxes/create.json.jbuilder
@@ -0,0 +1,5 @@
+json.id @inbox_assignment_policy.id
+json.inbox_id @inbox_assignment_policy.inbox_id
+json.assignment_policy_id @inbox_assignment_policy.assignment_policy_id
+json.created_at @inbox_assignment_policy.created_at.to_i
+json.updated_at @inbox_assignment_policy.updated_at.to_i
diff --git a/app/views/api/v1/accounts/assignment_policies/inboxes/index.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/inboxes/index.json.jbuilder
new file mode 100644
index 000000000..5a22aa917
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/inboxes/index.json.jbuilder
@@ -0,0 +1,3 @@
+json.inboxes @inboxes do |inbox|
+  json.partial! 'api/v1/models/inbox', formats: [:json], resource: inbox
+end
diff --git a/app/views/api/v1/accounts/assignment_policies/index.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/index.json.jbuilder
new file mode 100644
index 000000000..0be431f87
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/index.json.jbuilder
@@ -0,0 +1,3 @@
+json.array! @assignment_policies do |assignment_policy|
+  json.partial! 'assignment_policy', assignment_policy: assignment_policy
+end
diff --git a/app/views/api/v1/accounts/assignment_policies/show.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/show.json.jbuilder
new file mode 100644
index 000000000..8fd9543c3
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/show.json.jbuilder
@@ -0,0 +1 @@
+json.partial! 'assignment_policy', assignment_policy: @assignment_policy
diff --git a/app/views/api/v1/accounts/assignment_policies/update.json.jbuilder b/app/views/api/v1/accounts/assignment_policies/update.json.jbuilder
new file mode 100644
index 000000000..8fd9543c3
--- /dev/null
+++ b/app/views/api/v1/accounts/assignment_policies/update.json.jbuilder
@@ -0,0 +1 @@
+json.partial! 'assignment_policy', assignment_policy: @assignment_policy
diff --git a/app/views/api/v1/accounts/inboxes/assignment_policies/create.json.jbuilder b/app/views/api/v1/accounts/inboxes/assignment_policies/create.json.jbuilder
new file mode 100644
index 000000000..105658704
--- /dev/null
+++ b/app/views/api/v1/accounts/inboxes/assignment_policies/create.json.jbuilder
@@ -0,0 +1 @@
+json.partial! 'api/v1/accounts/assignment_policies/assignment_policy', formats: [:json], assignment_policy: @assignment_policy
diff --git a/app/views/api/v1/accounts/inboxes/assignment_policies/show.json.jbuilder b/app/views/api/v1/accounts/inboxes/assignment_policies/show.json.jbuilder
new file mode 100644
index 000000000..105658704
--- /dev/null
+++ b/app/views/api/v1/accounts/inboxes/assignment_policies/show.json.jbuilder
@@ -0,0 +1 @@
+json.partial! 'api/v1/accounts/assignment_policies/assignment_policy', formats: [:json], assignment_policy: @assignment_policy
diff --git a/config/app.yml b/config/app.yml
index c9b08cd07..cc7233c18 100644
--- a/config/app.yml
+++ b/config/app.yml
@@ -1,5 +1,5 @@
 shared: &shared
-  version: '4.5.0'
+  version: '4.5.1'
 
 development:
   <<: *shared
diff --git a/config/features.yml b/config/features.yml
index db2d46700..d6f2d24a3 100644
--- a/config/features.yml
+++ b/config/features.yml
@@ -191,3 +191,7 @@
   display_name: CRM V2
   enabled: false
   chatwoot_internal: true
+- name: assignment_v2
+  display_name: Assignment V2
+  enabled: false
+  chatwoot_internal: true
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 1d8347679..e55132709 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -53,6 +53,8 @@ en:
       email_already_exists: 'You have already signed up for an account with %{email}'
       invalid_params: 'Invalid, please check the signup paramters and try again'
       failed: Signup failed
+    assignment_policy:
+      not_found: Assignment policy not found
     data_import:
       data_type:
         invalid: Invalid data type
diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml
index 7ddc6d31f..71ab85e3a 100644
--- a/config/locales/pt_BR.yml
+++ b/config/locales/pt_BR.yml
@@ -20,9 +20,9 @@ pt_BR:
   hello: 'Olá, mundo'
   inbox:
     reauthorization:
-      success: 'Channel reauthorized successfully'
-      not_required: 'Reauthorization is not required for this inbox'
-      invalid_channel: 'Invalid channel type for reauthorization'
+      success: 'Canal reautenticado com sucesso'
+      not_required: 'Reautenticação não é necessária para esta caixa de entrada'
+      invalid_channel: 'Tipo de canal inválido para reautenticar'
   messages:
     reset_password_success: Legal! A solicitação de alteração de senha foi bem sucedida. Verifique seu e-mail para obter instruções.
     reset_password_failure: Uh ho! Não conseguimos encontrar nenhum usuário com o e-mail especificado.
@@ -59,12 +59,12 @@ pt_BR:
     slack:
       invalid_channel_id: 'Canal de slack inválido. Por favor, tente novamente'
     whatsapp:
-      token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
-      invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
-      phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+      token_exchange_failed: 'Falha ao trocar o código por um token de acesso. Por favor, tente novamente.'
+      invalid_token_permissions: 'O token de acesso não tem as permissões necessárias para o WhatsApp.'
+      phone_info_fetch_failed: 'Falha ao obter a informação do número de telefone. Por favor, tente novamente.'
       reauthorization:
-        generic: 'Failed to reauthorize WhatsApp. Please try again.'
-        not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
+        generic: 'Falha ao reautenticar o WhatsApp. Por favor, tente novamente.'
+        not_supported: 'Reautenticação não é suportado por este tipo de canal WhatsApp.'
     inboxes:
       imap:
         socket_error: Por favor, verifique a conexão de rede, endereço IMAP e tente novamente.
@@ -257,8 +257,8 @@ pt_BR:
       description: 'Crie issues em Linear diretamente da sua janela de conversa. Alternativamente, vincule as issues lineares existentes para um processo de rastreamento de problemas mais simples e eficiente.'
     notion:
       name: 'Notion'
-      short_description: 'Integrate databases, documents and pages directly with Captain.'
-      description: 'Connect your Notion workspace to enable Captain to access and generate intelligent responses using content from your databases, documents, and pages to provide more contextual customer support.'
+      short_description: 'Integre banco de dados, documentos e páginas diretamente com o Capitão.'
+      description: 'Conecte o seu espaço de trabalho Notion para permitir que o Capitão acesse e gere respostas inteligentes usando o conteúdo de seus bancos de dados, documentos e páginas para fornecer suporte ao cliente mais contextual.'
     shopify:
       name: 'Shopify'
       short_description: 'Acessar detalhes do pedido e dados de clientes da sua loja Shopify.'
@@ -359,9 +359,9 @@ pt_BR:
   portals:
     send_instructions:
       email_required: 'E-mail é obrigatório'
-      invalid_email_format: 'Invalid email format'
-      custom_domain_not_configured: 'Custom domain is not configured'
-      instructions_sent_successfully: 'Instructions sent successfully'
-      subject: 'Finish setting up %{custom_domain}'
+      invalid_email_format: 'Formato inválido de e-mail'
+      custom_domain_not_configured: 'Domínio personalizado não está configurado'
+      instructions_sent_successfully: 'Instruções enviadas com sucesso'
+      subject: 'Termine de configurar %{custom_domain}'
     ssl_status:
-      custom_domain_not_configured: 'Custom domain is not configured'
+      custom_domain_not_configured: 'Domínio personalizado não está configurado'
diff --git a/config/routes.rb b/config/routes.rb
index 10749062e..1409b11fd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -217,6 +217,15 @@ Rails.application.routes.draw do
             end
           end
 
+          # Assignment V2 Routes
+          resources :assignment_policies do
+            resources :inboxes, only: [:index, :create, :destroy], module: :assignment_policies
+          end
+
+          resources :inboxes, only: [] do
+            resource :assignment_policy, only: [:show, :create, :destroy], module: :inboxes
+          end
+
           namespace :twitter do
             resource :authorization, only: [:create]
           end
diff --git a/db/migrate/20250808123008_add_feature_citation_to_assistant_config.rb b/db/migrate/20250808123008_add_feature_citation_to_assistant_config.rb
index e1f5c3f03..d5b037ec6 100644
--- a/db/migrate/20250808123008_add_feature_citation_to_assistant_config.rb
+++ b/db/migrate/20250808123008_add_feature_citation_to_assistant_config.rb
@@ -1,5 +1,7 @@
 class AddFeatureCitationToAssistantConfig < ActiveRecord::Migration[7.1]
   def up
+    return unless ChatwootApp.enterprise?
+
     Captain::Assistant.find_each do |assistant|
       assistant.update!(
         config: assistant.config.merge('feature_citation' => true)
@@ -8,6 +10,8 @@ class AddFeatureCitationToAssistantConfig < ActiveRecord::Migration[7.1]
   end
 
   def down
+    return unless ChatwootApp.enterprise?
+
     Captain::Assistant.find_each do |assistant|
       config = assistant.config.dup
       config.delete('feature_citation')
diff --git a/enterprise/app/models/enterprise/concerns/assignment_policy.rb b/enterprise/app/models/enterprise/concerns/assignment_policy.rb
new file mode 100644
index 000000000..bddcc5e75
--- /dev/null
+++ b/enterprise/app/models/enterprise/concerns/assignment_policy.rb
@@ -0,0 +1,7 @@
+module Enterprise::Concerns::AssignmentPolicy
+  extend ActiveSupport::Concern
+
+  included do
+    enum assignment_order: { round_robin: 0, balanced: 1 } if ChatwootApp.enterprise?
+  end
+end
diff --git a/package.json b/package.json
index 441dcbd90..8dc6b2565 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@chatwoot/chatwoot",
-  "version": "4.5.0",
+  "version": "4.5.1",
   "license": "MIT",
   "scripts": {
     "eslint": "eslint app/**/*.{js,vue}",
diff --git a/spec/controllers/api/v1/accounts/assignment_policies/inboxes_controller_spec.rb b/spec/controllers/api/v1/accounts/assignment_policies/inboxes_controller_spec.rb
new file mode 100644
index 000000000..6b3c677c5
--- /dev/null
+++ b/spec/controllers/api/v1/accounts/assignment_policies/inboxes_controller_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+RSpec.describe 'Assignment Policy Inboxes API', type: :request do
+  let(:account) { create(:account) }
+  let(:assignment_policy) { create(:assignment_policy, account: account) }
+
+  describe 'GET /api/v1/accounts/{account_id}/assignment_policies/{assignment_policy_id}/inboxes' do
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}/inboxes"
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      context 'when assignment policy has associated inboxes' do
+        before do
+          inbox1 = create(:inbox, account: account)
+          inbox2 = create(:inbox, account: account)
+          create(:inbox_assignment_policy, inbox: inbox1, assignment_policy: assignment_policy)
+          create(:inbox_assignment_policy, inbox: inbox2, assignment_policy: assignment_policy)
+        end
+
+        it 'returns all inboxes associated with the assignment policy' do
+          get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}/inboxes",
+              headers: admin.create_new_auth_token,
+              as: :json
+
+          expect(response).to have_http_status(:success)
+          json_response = response.parsed_body
+          expect(json_response['inboxes']).to be_an(Array)
+          expect(json_response['inboxes'].length).to eq(2)
+        end
+      end
+
+      context 'when assignment policy has no associated inboxes' do
+        it 'returns empty array' do
+          get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}/inboxes",
+              headers: admin.create_new_auth_token,
+              as: :json
+
+          expect(response).to have_http_status(:success)
+          json_response = response.parsed_body
+          expect(json_response['inboxes']).to eq([])
+        end
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}/inboxes",
+            headers: agent.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/accounts/assignment_policies_controller_spec.rb b/spec/controllers/api/v1/accounts/assignment_policies_controller_spec.rb
new file mode 100644
index 000000000..f882ec992
--- /dev/null
+++ b/spec/controllers/api/v1/accounts/assignment_policies_controller_spec.rb
@@ -0,0 +1,326 @@
+require 'rails_helper'
+
+RSpec.describe 'Assignment Policies API', type: :request do
+  let(:account) { create(:account) }
+
+  describe 'GET /api/v1/accounts/{account.id}/assignment_policies' do
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies"
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      before do
+        create_list(:assignment_policy, 3, account: account)
+      end
+
+      it 'returns all assignment policies for the account' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies",
+            headers: admin.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:success)
+        json_response = response.parsed_body
+        expect(json_response.length).to eq(3)
+        expect(json_response.first.keys).to include('id', 'name', 'description')
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies",
+            headers: agent.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+
+  describe 'GET /api/v1/accounts/{account.id}/assignment_policies/:id' do
+    let(:assignment_policy) { create(:assignment_policy, account: account) }
+
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}"
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      it 'returns the assignment policy' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            headers: admin.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:success)
+        json_response = response.parsed_body
+        expect(json_response['id']).to eq(assignment_policy.id)
+        expect(json_response['name']).to eq(assignment_policy.name)
+      end
+
+      it 'returns not found for non-existent policy' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies/999999",
+            headers: admin.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:not_found)
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            headers: agent.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+
+  describe 'POST /api/v1/accounts/{account.id}/assignment_policies' do
+    let(:valid_params) do
+      {
+        assignment_policy: {
+          name: 'New Assignment Policy',
+          description: 'Policy for new team',
+          conversation_priority: 'longest_waiting',
+          fair_distribution_limit: 15,
+          enabled: true
+        }
+      }
+    end
+
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        post "/api/v1/accounts/#{account.id}/assignment_policies", params: valid_params
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      it 'creates a new assignment policy' do
+        expect do
+          post "/api/v1/accounts/#{account.id}/assignment_policies",
+               headers: admin.create_new_auth_token,
+               params: valid_params,
+               as: :json
+        end.to change(AssignmentPolicy, :count).by(1)
+
+        expect(response).to have_http_status(:success)
+        json_response = response.parsed_body
+        expect(json_response['name']).to eq('New Assignment Policy')
+        expect(json_response['conversation_priority']).to eq('longest_waiting')
+      end
+
+      it 'creates policy with minimal required params' do
+        minimal_params = { assignment_policy: { name: 'Minimal Policy' } }
+
+        expect do
+          post "/api/v1/accounts/#{account.id}/assignment_policies",
+               headers: admin.create_new_auth_token,
+               params: minimal_params,
+               as: :json
+        end.to change(AssignmentPolicy, :count).by(1)
+
+        expect(response).to have_http_status(:success)
+      end
+
+      it 'prevents duplicate policy names within account' do
+        create(:assignment_policy, account: account, name: 'Duplicate Policy')
+        duplicate_params = { assignment_policy: { name: 'Duplicate Policy' } }
+
+        expect do
+          post "/api/v1/accounts/#{account.id}/assignment_policies",
+               headers: admin.create_new_auth_token,
+               params: duplicate_params,
+               as: :json
+        end.not_to change(AssignmentPolicy, :count)
+
+        expect(response).to have_http_status(:unprocessable_entity)
+      end
+
+      it 'validates required fields' do
+        invalid_params = { assignment_policy: { name: '' } }
+
+        post "/api/v1/accounts/#{account.id}/assignment_policies",
+             headers: admin.create_new_auth_token,
+             params: invalid_params,
+             as: :json
+
+        expect(response).to have_http_status(:unprocessable_entity)
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        post "/api/v1/accounts/#{account.id}/assignment_policies",
+             headers: agent.create_new_auth_token,
+             params: valid_params,
+             as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+
+  describe 'PUT /api/v1/accounts/{account.id}/assignment_policies/:id' do
+    let(:assignment_policy) { create(:assignment_policy, account: account, name: 'Original Policy') }
+    let(:update_params) do
+      {
+        assignment_policy: {
+          name: 'Updated Policy',
+          description: 'Updated description',
+          fair_distribution_limit: 20
+        }
+      }
+    end
+
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        put "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            params: update_params
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      it 'updates the assignment policy' do
+        put "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            headers: admin.create_new_auth_token,
+            params: update_params,
+            as: :json
+
+        expect(response).to have_http_status(:success)
+        assignment_policy.reload
+        expect(assignment_policy.name).to eq('Updated Policy')
+        expect(assignment_policy.fair_distribution_limit).to eq(20)
+      end
+
+      it 'allows partial updates' do
+        partial_params = { assignment_policy: { enabled: false } }
+
+        put "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            headers: admin.create_new_auth_token,
+            params: partial_params,
+            as: :json
+
+        expect(response).to have_http_status(:success)
+        expect(assignment_policy.reload.enabled).to be(false)
+        expect(assignment_policy.name).to eq('Original Policy') # unchanged
+      end
+
+      it 'prevents duplicate names during update' do
+        create(:assignment_policy, account: account, name: 'Existing Policy')
+        duplicate_params = { assignment_policy: { name: 'Existing Policy' } }
+
+        put "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            headers: admin.create_new_auth_token,
+            params: duplicate_params,
+            as: :json
+
+        expect(response).to have_http_status(:unprocessable_entity)
+      end
+
+      it 'returns not found for non-existent policy' do
+        put "/api/v1/accounts/#{account.id}/assignment_policies/999999",
+            headers: admin.create_new_auth_token,
+            params: update_params,
+            as: :json
+
+        expect(response).to have_http_status(:not_found)
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        put "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+            headers: agent.create_new_auth_token,
+            params: update_params,
+            as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+
+  describe 'DELETE /api/v1/accounts/{account.id}/assignment_policies/:id' do
+    let(:assignment_policy) { create(:assignment_policy, account: account) }
+
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        delete "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}"
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      it 'deletes the assignment policy' do
+        assignment_policy # create it first
+
+        expect do
+          delete "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+                 headers: admin.create_new_auth_token,
+                 as: :json
+        end.to change(AssignmentPolicy, :count).by(-1)
+
+        expect(response).to have_http_status(:ok)
+      end
+
+      it 'cascades deletion to associated inbox assignment policies' do
+        inbox = create(:inbox, account: account)
+        create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy)
+
+        expect do
+          delete "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+                 headers: admin.create_new_auth_token,
+                 as: :json
+        end.to change(InboxAssignmentPolicy, :count).by(-1)
+
+        expect(response).to have_http_status(:ok)
+      end
+
+      it 'returns not found for non-existent policy' do
+        delete "/api/v1/accounts/#{account.id}/assignment_policies/999999",
+               headers: admin.create_new_auth_token,
+               as: :json
+
+        expect(response).to have_http_status(:not_found)
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        delete "/api/v1/accounts/#{account.id}/assignment_policies/#{assignment_policy.id}",
+               headers: agent.create_new_auth_token,
+               as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/accounts/inboxes/assignment_policies_controller_spec.rb b/spec/controllers/api/v1/accounts/inboxes/assignment_policies_controller_spec.rb
new file mode 100644
index 000000000..71ff464f8
--- /dev/null
+++ b/spec/controllers/api/v1/accounts/inboxes/assignment_policies_controller_spec.rb
@@ -0,0 +1,195 @@
+require 'rails_helper'
+
+RSpec.describe 'Inbox Assignment Policies API', type: :request do
+  let(:account) { create(:account) }
+  let(:inbox) { create(:inbox, account: account) }
+  let(:assignment_policy) { create(:assignment_policy, account: account) }
+
+  describe 'GET /api/v1/accounts/{account_id}/inboxes/{inbox_id}/assignment_policy' do
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy"
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      context 'when inbox has an assignment policy' do
+        before do
+          create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy)
+        end
+
+        it 'returns the assignment policy for the inbox' do
+          get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+              headers: admin.create_new_auth_token,
+              as: :json
+
+          expect(response).to have_http_status(:success)
+          json_response = response.parsed_body
+          expect(json_response['id']).to eq(assignment_policy.id)
+          expect(json_response['name']).to eq(assignment_policy.name)
+        end
+      end
+
+      context 'when inbox has no assignment policy' do
+        it 'returns not found' do
+          get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+              headers: admin.create_new_auth_token,
+              as: :json
+
+          expect(response).to have_http_status(:not_found)
+        end
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+            headers: agent.create_new_auth_token,
+            as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+
+  describe 'POST /api/v1/accounts/{account_id}/inboxes/{inbox_id}/assignment_policy' do
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+             params: { assignment_policy_id: assignment_policy.id }
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      it 'assigns a policy to the inbox' do
+        expect do
+          post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+               params: { assignment_policy_id: assignment_policy.id },
+               headers: admin.create_new_auth_token,
+               as: :json
+        end.to change(InboxAssignmentPolicy, :count).by(1)
+
+        expect(response).to have_http_status(:success)
+        json_response = response.parsed_body
+        expect(json_response['id']).to eq(assignment_policy.id)
+      end
+
+      it 'replaces existing assignment policy for inbox' do
+        other_policy = create(:assignment_policy, account: account)
+        create(:inbox_assignment_policy, inbox: inbox, assignment_policy: other_policy)
+
+        expect do
+          post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+               params: { assignment_policy_id: assignment_policy.id },
+               headers: admin.create_new_auth_token,
+               as: :json
+        end.not_to change(InboxAssignmentPolicy, :count)
+
+        expect(response).to have_http_status(:success)
+        expect(inbox.reload.inbox_assignment_policy.assignment_policy).to eq(assignment_policy)
+      end
+
+      it 'returns not found for invalid assignment policy' do
+        post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+             params: { assignment_policy_id: 999_999 },
+             headers: admin.create_new_auth_token,
+             as: :json
+
+        expect(response).to have_http_status(:not_found)
+      end
+
+      it 'returns not found for invalid inbox' do
+        post "/api/v1/accounts/#{account.id}/inboxes/999999/assignment_policy",
+             params: { assignment_policy_id: assignment_policy.id },
+             headers: admin.create_new_auth_token,
+             as: :json
+
+        expect(response).to have_http_status(:not_found)
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+             params: { assignment_policy_id: assignment_policy.id },
+             headers: agent.create_new_auth_token,
+             as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+
+  describe 'DELETE /api/v1/accounts/{account_id}/inboxes/{inbox_id}/assignment_policy' do
+    context 'when it is an unauthenticated user' do
+      it 'returns unauthorized' do
+        delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy"
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+
+    context 'when it is an authenticated admin' do
+      let(:admin) { create(:user, account: account, role: :administrator) }
+
+      context 'when inbox has an assignment policy' do
+        before do
+          create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy)
+        end
+
+        it 'removes the assignment policy from inbox' do
+          expect do
+            delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+                   headers: admin.create_new_auth_token,
+                   as: :json
+          end.to change(InboxAssignmentPolicy, :count).by(-1)
+
+          expect(response).to have_http_status(:success)
+          expect(inbox.reload.inbox_assignment_policy).to be_nil
+        end
+      end
+
+      context 'when inbox has no assignment policy' do
+        it 'returns error' do
+          expect do
+            delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+                   headers: admin.create_new_auth_token,
+                   as: :json
+          end.not_to change(InboxAssignmentPolicy, :count)
+
+          expect(response).to have_http_status(:not_found)
+        end
+      end
+
+      it 'returns not found for invalid inbox' do
+        delete "/api/v1/accounts/#{account.id}/inboxes/999999/assignment_policy",
+               headers: admin.create_new_auth_token,
+               as: :json
+
+        expect(response).to have_http_status(:not_found)
+      end
+    end
+
+    context 'when it is an agent' do
+      let(:agent) { create(:user, account: account, role: :agent) }
+
+      it 'returns unauthorized' do
+        delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignment_policy",
+               headers: agent.create_new_auth_token,
+               as: :json
+
+        expect(response).to have_http_status(:unauthorized)
+      end
+    end
+  end
+end
diff --git a/spec/enterprise/models/assignment_policy_spec.rb b/spec/enterprise/models/assignment_policy_spec.rb
new file mode 100644
index 000000000..0d21cc3c4
--- /dev/null
+++ b/spec/enterprise/models/assignment_policy_spec.rb
@@ -0,0 +1,18 @@
+require 'rails_helper'
+
+RSpec.describe AssignmentPolicy do
+  let(:account) { create(:account) }
+
+  describe 'enum values' do
+    let(:assignment_policy) { create(:assignment_policy, account: account) }
+
+    describe 'assignment_order' do
+      it 'can be set to balanced' do
+        assignment_policy.update!(assignment_order: :balanced)
+        expect(assignment_policy.assignment_order).to eq('balanced')
+        expect(assignment_policy.round_robin?).to be false
+        expect(assignment_policy.balanced?).to be true
+      end
+    end
+  end
+end
diff --git a/spec/factories/assignment_policies.rb b/spec/factories/assignment_policies.rb
new file mode 100644
index 000000000..6a696caa4
--- /dev/null
+++ b/spec/factories/assignment_policies.rb
@@ -0,0 +1,12 @@
+FactoryBot.define do
+  factory :assignment_policy do
+    account
+    sequence(:name) { |n| "Assignment Policy #{n}" }
+    description { 'Test assignment policy description' }
+    assignment_order { 0 }
+    conversation_priority { 0 }
+    fair_distribution_limit { 10 }
+    fair_distribution_window { 3600 }
+    enabled { true }
+  end
+end
diff --git a/spec/factories/inbox_assignment_policies.rb b/spec/factories/inbox_assignment_policies.rb
new file mode 100644
index 000000000..80bcae223
--- /dev/null
+++ b/spec/factories/inbox_assignment_policies.rb
@@ -0,0 +1,6 @@
+FactoryBot.define do
+  factory :inbox_assignment_policy do
+    inbox
+    assignment_policy
+  end
+end
diff --git a/spec/models/assignment_policy_spec.rb b/spec/models/assignment_policy_spec.rb
new file mode 100644
index 000000000..1a97bbda0
--- /dev/null
+++ b/spec/models/assignment_policy_spec.rb
@@ -0,0 +1,56 @@
+require 'rails_helper'
+
+RSpec.describe AssignmentPolicy do
+  describe 'associations' do
+    it { is_expected.to belong_to(:account) }
+    it { is_expected.to have_many(:inbox_assignment_policies).dependent(:destroy) }
+    it { is_expected.to have_many(:inboxes).through(:inbox_assignment_policies) }
+  end
+
+  describe 'validations' do
+    subject { build(:assignment_policy) }
+
+    it { is_expected.to validate_presence_of(:name) }
+    it { is_expected.to validate_uniqueness_of(:name).scoped_to(:account_id) }
+  end
+
+  describe 'fair distribution validations' do
+    it 'requires fair_distribution_limit to be greater than 0' do
+      policy = build(:assignment_policy, fair_distribution_limit: 0)
+      expect(policy).not_to be_valid
+      expect(policy.errors[:fair_distribution_limit]).to include('must be greater than 0')
+    end
+
+    it 'requires fair_distribution_window to be greater than 0' do
+      policy = build(:assignment_policy, fair_distribution_window: -1)
+      expect(policy).not_to be_valid
+      expect(policy.errors[:fair_distribution_window]).to include('must be greater than 0')
+    end
+  end
+
+  describe 'enum values' do
+    let(:assignment_policy) { create(:assignment_policy) }
+
+    describe 'conversation_priority' do
+      it 'can be set to earliest_created' do
+        assignment_policy.update!(conversation_priority: :earliest_created)
+        expect(assignment_policy.conversation_priority).to eq('earliest_created')
+        expect(assignment_policy.earliest_created?).to be true
+      end
+
+      it 'can be set to longest_waiting' do
+        assignment_policy.update!(conversation_priority: :longest_waiting)
+        expect(assignment_policy.conversation_priority).to eq('longest_waiting')
+        expect(assignment_policy.longest_waiting?).to be true
+      end
+    end
+
+    describe 'assignment_order' do
+      it 'can be set to round_robin' do
+        assignment_policy.update!(assignment_order: :round_robin)
+        expect(assignment_policy.assignment_order).to eq('round_robin')
+        expect(assignment_policy.round_robin?).to be true
+      end
+    end
+  end
+end