diff --git a/app/javascript/dashboard/composables/spec/useAutomation.spec.js b/app/javascript/dashboard/composables/spec/useAutomation.spec.js
index a66f0c7b4..6cce15996 100644
--- a/app/javascript/dashboard/composables/spec/useAutomation.spec.js
+++ b/app/javascript/dashboard/composables/spec/useAutomation.spec.js
@@ -38,7 +38,7 @@ describe('useAutomation', () => {
});
useMapGetter.mockImplementation(getter => {
const getterMap = {
- 'agents/getAgents': agents,
+ 'agents/getVerifiedAgents': agents,
'campaigns/getAllCampaigns': campaigns,
'contacts/getContacts': contacts,
'inboxes/getInboxes': inboxes,
diff --git a/app/javascript/dashboard/composables/spec/useMacros.spec.js b/app/javascript/dashboard/composables/spec/useMacros.spec.js
index 7666e4afa..e7f6aa495 100644
--- a/app/javascript/dashboard/composables/spec/useMacros.spec.js
+++ b/app/javascript/dashboard/composables/spec/useMacros.spec.js
@@ -111,7 +111,7 @@ describe('useMacros', () => {
useStoreGetters.mockReturnValue({
'labels/getLabels': { value: mockLabels },
'teams/getTeams': { value: mockTeams },
- 'agents/getAgents': { value: mockAgents },
+ 'agents/getVerifiedAgents': { value: mockAgents },
});
});
@@ -167,7 +167,7 @@ describe('useMacros', () => {
useStoreGetters.mockReturnValue({
'labels/getLabels': { value: [] },
'teams/getTeams': { value: [] },
- 'agents/getAgents': { value: [] },
+ 'agents/getVerifiedAgents': { value: [] },
});
const { getMacroDropdownValues } = useMacros();
diff --git a/app/javascript/dashboard/composables/useAutomationValues.js b/app/javascript/dashboard/composables/useAutomationValues.js
index 6a6b507c8..709aba20b 100644
--- a/app/javascript/dashboard/composables/useAutomationValues.js
+++ b/app/javascript/dashboard/composables/useAutomationValues.js
@@ -20,7 +20,7 @@ import {
export default function useAutomationValues() {
const getters = useStoreGetters();
const { t } = useI18n();
- const agents = useMapGetter('agents/getAgents');
+ const agents = useMapGetter('agents/getVerifiedAgents');
const campaigns = useMapGetter('campaigns/getAllCampaigns');
const contacts = useMapGetter('contacts/getContacts');
const inboxes = useMapGetter('inboxes/getInboxes');
diff --git a/app/javascript/dashboard/composables/useMacros.js b/app/javascript/dashboard/composables/useMacros.js
index 8f0227fa3..437690eff 100644
--- a/app/javascript/dashboard/composables/useMacros.js
+++ b/app/javascript/dashboard/composables/useMacros.js
@@ -13,7 +13,7 @@ export const useMacros = () => {
const labels = computed(() => getters['labels/getLabels'].value);
const teams = computed(() => getters['teams/getTeams'].value);
- const agents = computed(() => getters['agents/getAgents'].value);
+ const agents = computed(() => getters['agents/getVerifiedAgents'].value);
/**
* Get dropdown values based on the specified type
diff --git a/app/javascript/dashboard/routes/dashboard/captain/assistants/scenarios/Index.vue b/app/javascript/dashboard/routes/dashboard/captain/assistants/scenarios/Index.vue
index 27deb4070..c4914f354 100644
--- a/app/javascript/dashboard/routes/dashboard/captain/assistants/scenarios/Index.vue
+++ b/app/javascript/dashboard/routes/dashboard/captain/assistants/scenarios/Index.vue
@@ -191,7 +191,7 @@ onMounted(() => {
> ?)::#{attribute_data_type} #{filter_operator_value} #{query_operator} ", @attribute_key]
- )
- else
- ActiveRecord::Base.sanitize_sql_array(
- ["(#{table_name}.custom_attributes ->> ?)::#{attribute_data_type} #{filter_operator_value} #{query_operator} ", @attribute_key]
- )
- end
-
- query + not_in_custom_attr_query(table_name, query_hash, attribute_data_type)
- end
-
- def custom_attribute(attribute_key, account, custom_attribute_type)
- current_account = account || Current.account
- attribute_model = custom_attribute_type.presence || self.class::ATTRIBUTE_MODEL
- @custom_attribute = current_account.custom_attribute_definitions.where(
- attribute_model: attribute_model
- ).find_by(attribute_key: attribute_key)
- end
-
- def not_in_custom_attr_query(table_name, query_hash, attribute_data_type)
- return '' unless query_hash[:filter_operator] == 'not_equal_to'
-
- ActiveRecord::Base.sanitize_sql_array(
- [" OR (#{table_name}.custom_attributes ->> ?)::#{attribute_data_type} IS NULL ", @attribute_key]
- )
- end
-
def equals_to_filter_string(filter_operator, current_index)
return "IN (:value_#{current_index})" if filter_operator == 'equal_to'
diff --git a/app/services/filters/custom_attribute_filter_helper.rb b/app/services/filters/custom_attribute_filter_helper.rb
new file mode 100644
index 000000000..f0715c611
--- /dev/null
+++ b/app/services/filters/custom_attribute_filter_helper.rb
@@ -0,0 +1,55 @@
+module Filters::CustomAttributeFilterHelper
+ def custom_attribute_query(query_hash, custom_attribute_type, current_index)
+ @attribute_key = query_hash[:attribute_key]
+ @custom_attribute_type = custom_attribute_type
+ attribute_data_type
+ return '' if @custom_attribute.blank?
+
+ build_custom_attr_query(query_hash, current_index)
+ end
+
+ private
+
+ def attribute_model
+ @attribute_model = @custom_attribute_type.presence || self.class::ATTRIBUTE_MODEL
+ end
+
+ def attribute_data_type
+ attribute_type = custom_attribute(@attribute_key, @account, attribute_model).try(:attribute_display_type)
+ @attribute_data_type = self.class::ATTRIBUTE_TYPES[attribute_type]
+ end
+
+ def build_custom_attr_query(query_hash, current_index)
+ filter_operator_value = filter_operation(query_hash, current_index)
+ query_operator = query_hash[:query_operator]
+ table_name = attribute_model == 'conversation_attribute' ? 'conversations' : 'contacts'
+
+ query = if attribute_data_type == 'text'
+ ActiveRecord::Base.sanitize_sql_array(
+ ["LOWER(#{table_name}.custom_attributes ->> ?)::#{attribute_data_type} #{filter_operator_value} #{query_operator} ", @attribute_key]
+ )
+ else
+ ActiveRecord::Base.sanitize_sql_array(
+ ["(#{table_name}.custom_attributes ->> ?)::#{attribute_data_type} #{filter_operator_value} #{query_operator} ", @attribute_key]
+ )
+ end
+
+ query + not_in_custom_attr_query(table_name, query_hash, attribute_data_type)
+ end
+
+ def custom_attribute(attribute_key, account, custom_attribute_type)
+ current_account = account || Current.account
+ attribute_model = custom_attribute_type.presence || self.class::ATTRIBUTE_MODEL
+ @custom_attribute = current_account.custom_attribute_definitions.where(
+ attribute_model: attribute_model
+ ).find_by(attribute_key: attribute_key)
+ end
+
+ def not_in_custom_attr_query(table_name, query_hash, attribute_data_type)
+ return '' unless query_hash[:filter_operator] == 'not_equal_to'
+
+ ActiveRecord::Base.sanitize_sql_array(
+ [" OR (#{table_name}.custom_attributes ->> ?)::#{attribute_data_type} IS NULL ", @attribute_key]
+ )
+ end
+end
diff --git a/app/views/fields/confirmed_at_field/_show.html.erb b/app/views/fields/confirmed_at_field/_show.html.erb
new file mode 100644
index 000000000..7f06246f7
--- /dev/null
+++ b/app/views/fields/confirmed_at_field/_show.html.erb
@@ -0,0 +1,3 @@
+<% if field.data %>
+ <%= field.datetime %>
+<% end %>
diff --git a/config/features.yml b/config/features.yml
index 3aa41e603..894d94ef0 100644
--- a/config/features.yml
+++ b/config/features.yml
@@ -191,7 +191,6 @@
- name: assignment_v2
display_name: Assignment V2
enabled: false
- chatwoot_internal: true
- name: twilio_content_templates
display_name: Twilio Content Templates
enabled: false
diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb
index b193c2e14..db7be0e43 100644
--- a/config/initializers/rack_attack.rb
+++ b/config/initializers/rack_attack.rb
@@ -185,7 +185,8 @@ class Rack::Attack
###-----------------------------------------------###
## Prevent Abuse of Converstion Transcript APIs ###
- throttle('/api/v1/accounts/:account_id/conversations/:conversation_id/transcript', limit: 30, period: 1.hour) do |req|
+ throttle('/api/v1/accounts/:account_id/conversations/:conversation_id/transcript',
+ limit: ENV.fetch('RATE_LIMIT_CONVERSATION_TRANSCRIPT', '1000').to_i, period: 1.hour) do |req|
match_data = %r{/api/v1/accounts/(?\d+)/conversations/(?\d+)/transcript}.match(req.path)
match_data[:account_id] if match_data.present?
end
diff --git a/enterprise/app/controllers/api/v1/accounts/captain/assistants_controller.rb b/enterprise/app/controllers/api/v1/accounts/captain/assistants_controller.rb
index ebeaaf67f..c1ac4b98b 100644
--- a/enterprise/app/controllers/api/v1/accounts/captain/assistants_controller.rb
+++ b/enterprise/app/controllers/api/v1/accounts/captain/assistants_controller.rb
@@ -24,10 +24,16 @@ class Api::V1::Accounts::Captain::AssistantsController < Api::V1::Accounts::Base
end
def playground
- response = Captain::Llm::AssistantChatService.new(assistant: @assistant).generate_response(
- additional_message: params[:message_content],
- message_history: message_history
- )
+ response = if captain_v2_enabled?
+ Captain::Assistant::AgentRunnerService.new(assistant: @assistant, source: 'playground').generate_response(
+ message_history: playground_message_history
+ )
+ else
+ Captain::Llm::AssistantChatService.new(assistant: @assistant, source: 'playground').generate_response(
+ additional_message: playground_params[:message_content],
+ message_history: message_history
+ )
+ end
render json: response
end
@@ -64,10 +70,31 @@ class Api::V1::Accounts::Captain::AssistantsController < Api::V1::Accounts::Base
end
def playground_params
- params.require(:assistant).permit(:message_content, message_history: [:role, :content])
+ params.require(:assistant).permit(:message_content, message_history: [:role, :content, :agent_name])
end
def message_history
- (playground_params[:message_history] || []).map { |message| { role: message[:role], content: message[:content] } }
+ (playground_params[:message_history] || []).map do |message|
+ {
+ role: message[:role],
+ content: message[:content],
+ agent_name: message[:agent_name]
+ }.compact
+ end
+ end
+
+ def playground_message_history
+ history = message_history
+ current_message = playground_params[:message_content]
+ return history if current_message.blank?
+
+ current_user_message = { role: 'user', content: current_message }
+ return history if history.last == current_user_message
+
+ history + [current_user_message]
+ end
+
+ def captain_v2_enabled?
+ @assistant.account.feature_enabled?('captain_integration_v2')
end
end
diff --git a/enterprise/app/helpers/captain/chat_helper.rb b/enterprise/app/helpers/captain/chat_helper.rb
index d5ac6df33..265f54d69 100644
--- a/enterprise/app/helpers/captain/chat_helper.rb
+++ b/enterprise/app/helpers/captain/chat_helper.rb
@@ -5,7 +5,6 @@ module Captain::ChatHelper
def request_chat_completion
log_chat_completion_request
-
chat = build_chat
add_messages_to_chat(chat)
@@ -86,7 +85,8 @@ module Captain::ChatHelper
temperature: temperature,
metadata: {
assistant_id: @assistant&.id,
- channel_type: resolved_channel_type
+ channel_type: resolved_channel_type,
+ source: @source
}.compact
}
end
@@ -130,7 +130,6 @@ module Captain::ChatHelper
end
def log_chat_completion_request
- Rails.logger.info("#{self.class.name} Assistant: #{@assistant.id}, Requesting chat completion " \
- "for messages #{@messages} with #{@tools&.length || 0} tools")
+ Rails.logger.info("#{self.class.name} Assistant: #{@assistant.id}, requesting completion for #{@messages} with #{@tools&.length || 0} tools")
end
end
diff --git a/enterprise/app/models/captain/assistant.rb b/enterprise/app/models/captain/assistant.rb
index 4f039d57a..08bff5ef3 100644
--- a/enterprise/app/models/captain/assistant.rb
+++ b/enterprise/app/models/captain/assistant.rb
@@ -106,7 +106,7 @@ class Captain::Assistant < ApplicationRecord
scenarios: scenarios.enabled.map do |scenario|
{
title: scenario.title,
- key: scenario.title.parameterize.underscore,
+ key: scenario.handoff_key,
description: scenario.description
}
end,
diff --git a/enterprise/app/models/captain/scenario.rb b/enterprise/app/models/captain/scenario.rb
index c43468804..8a6a3c979 100644
--- a/enterprise/app/models/captain/scenario.rb
+++ b/enterprise/app/models/captain/scenario.rb
@@ -24,6 +24,19 @@ class Captain::Scenario < ApplicationRecord
include Concerns::CaptainToolsHelpers
include Concerns::Agentable
+ # OpenAI enforces a 64-char limit on function names. The ai-agents gem
+ # prepends "handoff_to_" (11 chars), so we keep a safety margin and cap
+ # the full tool name to MAX_HANDOFF_TOOL_NAME_LENGTH (60 chars).
+ # Format: "scenario_{id}_{slug}_agent" for persisted records (stable + readable),
+ # and "scenario_draft_{slug}_agent" for unsaved records, with slug truncated
+ # based on the available length budget.
+ HANDOFF_TOOL_PREFIX = 'handoff_to_'.freeze
+ HANDOFF_KEY_PREFIX = 'scenario'.freeze
+ HANDOFF_KEY_SUFFIX = 'agent'.freeze
+ MAX_HANDOFF_TOOL_NAME_LENGTH = 60
+ MAX_AGENT_NAME_LENGTH = MAX_HANDOFF_TOOL_NAME_LENGTH - HANDOFF_TOOL_PREFIX.length
+ MAX_HANDOFF_SLUG_LENGTH = 24
+
self.table_name = 'captain_scenarios'
belongs_to :assistant, class_name: 'Captain::Assistant'
@@ -42,6 +55,10 @@ class Captain::Scenario < ApplicationRecord
before_save :resolve_tool_references
+ def handoff_key
+ [handoff_id_key, compact_handoff_slug, HANDOFF_KEY_SUFFIX].compact.join('_')
+ end
+
def prompt_context
{
title: title,
@@ -56,7 +73,28 @@ class Captain::Scenario < ApplicationRecord
private
def agent_name
- "#{title} Agent".parameterize(separator: '_')
+ handoff_key
+ end
+
+ def handoff_id_key
+ return "#{HANDOFF_KEY_PREFIX}_#{id}" if id.present?
+
+ "#{HANDOFF_KEY_PREFIX}_draft"
+ end
+
+ def compact_handoff_slug
+ slug = title.to_s.parameterize(separator: '_').presence
+ return nil if slug.blank?
+
+ max_slug_length = [MAX_HANDOFF_SLUG_LENGTH, dynamic_slug_max_length].min
+ return nil if max_slug_length <= 0
+
+ slug.first(max_slug_length).sub(/_+\z/, '').presence
+ end
+
+ def dynamic_slug_max_length
+ # handoff_to_#{scenario___agent}
+ MAX_AGENT_NAME_LENGTH - handoff_id_key.length - HANDOFF_KEY_SUFFIX.length - 2
end
def agent_tools
diff --git a/enterprise/app/services/captain/assistant/agent_runner_service.rb b/enterprise/app/services/captain/assistant/agent_runner_service.rb
index bdf35e98e..1875a9953 100644
--- a/enterprise/app/services/captain/assistant/agent_runner_service.rb
+++ b/enterprise/app/services/captain/assistant/agent_runner_service.rb
@@ -19,11 +19,11 @@ class Captain::Assistant::AgentRunnerService
CONTACT_INBOX_STATE_ATTRIBUTES = %i[id hmac_verified].freeze
CAMPAIGN_STATE_ATTRIBUTES = %i[id title message campaign_type description].freeze
-
- def initialize(assistant:, conversation: nil, callbacks: {})
+ def initialize(assistant:, conversation: nil, callbacks: {}, source: nil)
@assistant = assistant
@conversation = conversation
@callbacks = callbacks
+ @source = source
end
def generate_response(message_history: [])
@@ -32,8 +32,7 @@ class Captain::Assistant::AgentRunnerService
process_agent_result(result)
rescue StandardError => e
- # when running the agent runner service in a rake task, the conversation might not have an account associated
- # for regular production usage, it will run just fine
+ # In rake/local runs, conversation may not be present, so account is optional here.
ChatwootExceptionTracker.new(e, account: @conversation&.account).capture_exception
Rails.logger.error "[Captain V2] AgentRunnerService error: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
@@ -128,6 +127,7 @@ class Captain::Assistant::AgentRunnerService
assistant_id: @assistant.id,
assistant_config: @assistant.config
}
+ state[:source] = @source if @source.present?
build_conversation_state(state) if @conversation
state
@@ -140,8 +140,7 @@ class Captain::Assistant::AgentRunnerService
state[:campaign] = @conversation.campaign.attributes.symbolize_keys.slice(*CAMPAIGN_STATE_ATTRIBUTES) if @conversation.campaign
return unless @conversation.contact_inbox
- state[:contact_inbox] =
- @conversation.contact_inbox.attributes.symbolize_keys.slice(*CONTACT_INBOX_STATE_ATTRIBUTES)
+ state[:contact_inbox] = @conversation.contact_inbox.attributes.symbolize_keys.slice(*CONTACT_INBOX_STATE_ATTRIBUTES)
end
def build_and_wire_agents
@@ -180,6 +179,7 @@ class Captain::Assistant::AgentRunnerService
format(ATTR_LANGFUSE_METADATA, 'conversation_id') => conversation[:id],
format(ATTR_LANGFUSE_METADATA, 'conversation_display_id') => conversation[:display_id],
format(ATTR_LANGFUSE_METADATA, 'channel_type') => state[:channel_type],
+ format(ATTR_LANGFUSE_METADATA, 'source') => state[:source],
ATTR_LANGFUSE_TRACE_INPUT => trace_input,
ATTR_LANGFUSE_OBSERVATION_INPUT => trace_input
}.compact.transform_values(&:to_s)
diff --git a/enterprise/app/services/captain/llm/assistant_chat_service.rb b/enterprise/app/services/captain/llm/assistant_chat_service.rb
index 5a2976e39..c1403ed1a 100644
--- a/enterprise/app/services/captain/llm/assistant_chat_service.rb
+++ b/enterprise/app/services/captain/llm/assistant_chat_service.rb
@@ -1,11 +1,12 @@
class Captain::Llm::AssistantChatService < Llm::BaseAiService
include Captain::ChatHelper
- def initialize(assistant: nil, conversation_id: nil)
+ def initialize(assistant: nil, conversation_id: nil, source: nil)
super()
@assistant = assistant
@conversation_id = conversation_id
+ @source = source
@messages = [system_message]
@response = ''
diff --git a/lib/global_config_service.rb b/lib/global_config_service.rb
index 0649c24af..31612a240 100644
--- a/lib/global_config_service.rb
+++ b/lib/global_config_service.rb
@@ -14,4 +14,8 @@ class GlobalConfigService
GlobalConfig.clear_cache
i.value
end
+
+ def self.account_signup_enabled?
+ load('ENABLE_ACCOUNT_SIGNUP', 'false').to_s != 'false'
+ end
end
diff --git a/package.json b/package.json
index c1efcaabd..0f74d03f4 100644
--- a/package.json
+++ b/package.json
@@ -36,8 +36,8 @@
"@chatwoot/ninja-keys": "1.2.3",
"@chatwoot/prosemirror-schema": "1.3.7",
"@chatwoot/utils": "^0.0.52",
- "@formkit/core": "^1.6.7",
- "@formkit/vue": "^1.6.7",
+ "@formkit/core": "^1.7.2",
+ "@formkit/vue": "^1.7.2",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
"@highlightjs/vue-plugin": "^2.1.0",
"@iconify-json/fluent": "^1.2.32",
@@ -49,7 +49,7 @@
"@scmmishra/pico-search": "0.6.0",
"@sentry/vue": "^8.55.0",
"@sindresorhus/slugify": "2.2.1",
- "@tailwindcss/typography": "^0.5.15",
+ "@tailwindcss/typography": "^0.5.19",
"@tanstack/vue-table": "^8.20.5",
"@twilio/voice-sdk": "^2.12.4",
"@vitejs/plugin-vue": "^5.1.4",
@@ -59,7 +59,7 @@
"@vueuse/components": "^12.0.0",
"@vueuse/core": "^12.0.0",
"activestorage": "^5.2.6",
- "axios": "^1.13.2",
+ "axios": "^1.13.6",
"camelcase-keys": "^9.1.3",
"chart.js": "~4.4.4",
"color2k": "^2.0.2",
@@ -68,7 +68,7 @@
"countries-and-timezones": "^3.6.0",
"date-fns": "2.21.1",
"date-fns-tz": "^1.3.3",
- "dompurify": "3.2.4",
+ "dompurify": "3.3.2",
"flag-icons": "^7.2.3",
"floating-vue": "^5.2.2",
"highlight.js": "^11.10.0",
@@ -99,7 +99,7 @@
"vue": "^3.5.12",
"vue-chartjs": "5.3.1",
"vue-datepicker-next": "^1.0.3",
- "vue-dompurify-html": "^5.1.0",
+ "vue-dompurify-html": "^5.3.0",
"vue-i18n": "9.14.5",
"vue-letter": "^0.2.1",
"vue-router": "~4.4.5",
@@ -111,7 +111,7 @@
"wavesurfer.js": "7.8.6"
},
"devDependencies": {
- "@egoist/tailwindcss-icons": "^1.9.0",
+ "@egoist/tailwindcss-icons": "^1.9.2",
"@histoire/plugin-vue": "0.17.15",
"@iconify-json/logos": "^1.2.10",
"@iconify-json/lucide": "^1.2.82",
@@ -142,7 +142,7 @@
"prettier": "^3.3.3",
"prosemirror-model": "^1.22.3",
"size-limit": "^8.2.4",
- "tailwindcss": "^3.4.13",
+ "tailwindcss": "^3.4.19",
"vite": "^5.4.21",
"vite-plugin-ruby": "^5.0.0",
"vitest": "3.0.5"
@@ -160,7 +160,9 @@
"overrides": {
"vite-node": "2.0.1",
"vite": "5.4.21",
- "vitest": "3.0.5"
+ "vitest": "3.0.5",
+ "minimatch@<4": "3.1.5",
+ "minimatch@>=9.0.0 <9.0.7": "9.0.9"
}
},
"lint-staged": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3bb47a794..abd4acdeb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,6 +8,8 @@ overrides:
vite-node: 2.0.1
vite: 5.4.21
vitest: 3.0.5
+ minimatch@<4: 3.1.5
+ minimatch@>=9.0.0 <9.0.7: 9.0.9
importers:
@@ -29,11 +31,11 @@ importers:
specifier: ^0.0.52
version: 0.0.52
'@formkit/core':
- specifier: ^1.6.7
- version: 1.6.7
+ specifier: ^1.7.2
+ version: 1.7.2
'@formkit/vue':
- specifier: ^1.6.7
- version: 1.6.7(tailwindcss@3.4.13)(vue@3.5.12(typescript@5.6.2))
+ specifier: ^1.7.2
+ version: 1.7.2(vue@3.5.12(typescript@5.6.2))
'@hcaptcha/vue3-hcaptcha':
specifier: ^1.3.0
version: 1.3.0(vue@3.5.12(typescript@5.6.2))
@@ -68,8 +70,8 @@ importers:
specifier: 2.2.1
version: 2.2.1
'@tailwindcss/typography':
- specifier: ^0.5.15
- version: 0.5.15(tailwindcss@3.4.13)
+ specifier: ^0.5.19
+ version: 0.5.19(tailwindcss@3.4.19)
'@tanstack/vue-table':
specifier: ^8.20.5
version: 8.20.5(vue@3.5.12(typescript@5.6.2))
@@ -98,8 +100,8 @@ importers:
specifier: ^5.2.6
version: 5.2.8
axios:
- specifier: ^1.13.2
- version: 1.13.2
+ specifier: ^1.13.6
+ version: 1.13.6
camelcase-keys:
specifier: ^9.1.3
version: 9.1.3
@@ -125,8 +127,8 @@ importers:
specifier: ^1.3.3
version: 1.3.8(date-fns@2.21.1)
dompurify:
- specifier: 3.2.4
- version: 3.2.4
+ specifier: 3.3.2
+ version: 3.3.2
flag-icons:
specifier: ^7.2.3
version: 7.2.3
@@ -218,8 +220,8 @@ importers:
specifier: ^1.0.3
version: 1.0.3(vue@3.5.12(typescript@5.6.2))
vue-dompurify-html:
- specifier: ^5.1.0
- version: 5.1.0(vue@3.5.12(typescript@5.6.2))
+ specifier: ^5.3.0
+ version: 5.3.0(vue@3.5.12(typescript@5.6.2))
vue-i18n:
specifier: 9.14.5
version: 9.14.5(vue@3.5.12(typescript@5.6.2))
@@ -249,8 +251,8 @@ importers:
version: 7.8.6
devDependencies:
'@egoist/tailwindcss-icons':
- specifier: ^1.9.0
- version: 1.9.0(tailwindcss@3.4.13)
+ specifier: ^1.9.2
+ version: 1.9.2(tailwindcss@3.4.19)
'@histoire/plugin-vue':
specifier: 0.17.15
version: 0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))
@@ -342,8 +344,8 @@ importers:
specifier: ^8.2.4
version: 8.2.6
tailwindcss:
- specifier: ^3.4.13
- version: 3.4.13
+ specifier: ^3.4.19
+ version: 3.4.19
vite:
specifier: 5.4.21
version: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
@@ -402,9 +404,6 @@ packages:
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
- '@antfu/utils@8.1.1':
- resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==}
-
'@asamuzakjp/css-color@4.1.0':
resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==}
@@ -700,8 +699,8 @@ packages:
peerDependencies:
postcss-selector-parser: ^6.0.10
- '@egoist/tailwindcss-icons@1.9.0':
- resolution: {integrity: sha512-xWA9cUy6hzlK7Y6TaoRIcwmilSXiTJ8rbXcEdf9uht7yzDgw/yIgF4rThIQMrpD2Y2v4od51+r2y6Z7GStanDQ==}
+ '@egoist/tailwindcss-icons@1.9.2':
+ resolution: {integrity: sha512-I6XsSykmhu2cASg5Hp/ICLsJ/K/1aXPaSKjgbWaNp2xYnb4We/arWMmkhhV+9CglOFCUbqx0A3mM2kWV32ZIhw==}
peerDependencies:
tailwindcss: '*'
@@ -874,46 +873,35 @@ packages:
'@floating-ui/utils@0.2.7':
resolution: {integrity: sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==}
- '@formkit/core@1.6.7':
- resolution: {integrity: sha512-wEoWK7crcCPRV5KJfEGLjjIS+qwbuD8I5Ur0zTtKRQrdO4oRL6kVoubxQOpgnq1l8sWfcRY8Wpf22Wna2LD20Q==}
+ '@formkit/core@1.7.2':
+ resolution: {integrity: sha512-XDRVqkDtOziU3z44hdvgWEqGpiv6nTNeCmP8cnESKkr24a4keQuEwmfDVvibYV0ywyTMg6ylp2lyklCYeRHykQ==}
- '@formkit/dev@1.6.7':
- resolution: {integrity: sha512-mMtkfvfkl1P1v0haizUE4DadalbG9/3m0ZymmMKKb0F3pojQJFtdfohy67ZQKtmzy4bamowHyEUr+XzLbKY2EA==}
+ '@formkit/dev@1.7.2':
+ resolution: {integrity: sha512-W38xbbFS4h4LTV22kUC6ZbPHBmlM2lVbAz5PSYU3SPaNc4FeXp4GTe4GzLEmcS82B+5L1zbSOgGB43kWZts7wA==}
- '@formkit/i18n@1.6.7':
- resolution: {integrity: sha512-i9Mnc2XHCm2c10fppEIxdGv+jqOaixO22iFXX3xF+AkJnxtOzV5hP4f3/TeG+BNahGUq8vj+e1y+VMnjS6duxA==}
+ '@formkit/i18n@1.7.2':
+ resolution: {integrity: sha512-Zs6f+rtP2j2Nnt1HkNrL85WU6rtS1l1Q0BAQjCMGQPsbrppiL7/TZ5bNIrVm0DTntLgG3firDS7bNWAxPSwerQ==}
- '@formkit/inputs@1.6.7':
- resolution: {integrity: sha512-VLxoAJn5VGOEXkGI499lju5Irnu12cu+spI1HL//46nlVkqnb1XcV0k0MK9K+hogz4fGmyZUvHf0lxU6dh7ZZQ==}
+ '@formkit/inputs@1.7.2':
+ resolution: {integrity: sha512-4xs7RJN8EFGctTCNRXBTvor2O8RvuEEK3q2Hl/RMU5lhhn5tmck90fkkeAr9o+rWRoSNiV8XgbLQArQ/B1IYPw==}
- '@formkit/observer@1.6.7':
- resolution: {integrity: sha512-ei5z5ernNMKKiBuoRcFgEthhP1i+KKb02hsPsikLA3XehuoJdWIejn9AAq6jOEGbUMZ5XAAgFJcxzO5tnKuPnw==}
+ '@formkit/observer@1.7.2':
+ resolution: {integrity: sha512-KUr5mcu2SAeHOOK1FaMyFigtA8hkHLsUkaPFWpTC81j79o1AUjJppmfPaX6PbtlHLeMs2Zq8Qhp6VAhi7D2WJg==}
- '@formkit/rules@1.6.7':
- resolution: {integrity: sha512-adzOuTvf6ghZbV0g0ZH9+MU9jfoF4DojBztAbqzFP/fT4d+WxhSHHlkWq6PU66fHPy3OH4DkWdx9trL1wGHuzQ==}
+ '@formkit/rules@1.7.2':
+ resolution: {integrity: sha512-2e5qKlXzmL9LAetncFp7xkHEX/UAJsU3bo1iL3idloH3HALf5fIdg3lgOKwCNDMdLjbfiKJ6lVwFaeFfFpcDKw==}
- '@formkit/themes@1.6.7':
- resolution: {integrity: sha512-TIiWr4TMAFUg1pQz2E4GErfAhBv2Q2VbWlk6pqXPWI8UyPTjmcinEnCSIWDCX6FPPqiYShBnh8123nTO7pyvjA==}
- peerDependencies:
- tailwindcss: ^3.2.0
- unocss: 0.x.x
- windicss: ^3.0.0
- peerDependenciesMeta:
- tailwindcss:
- optional: true
- unocss:
- optional: true
- windicss:
- optional: true
+ '@formkit/themes@1.7.2':
+ resolution: {integrity: sha512-AaZHy7l9D44Ya3cQRqZ8RIpaTTsCjTB1gX13NlpqYSs6yG0yBTmJ7L7kW60bOGdhs/vmIwSel578EBwz98nybQ==}
- '@formkit/utils@1.6.7':
- resolution: {integrity: sha512-aU3CDLzCkC5Dnx6iS3swbsIbys7E+2VOaLWFRnS7wk7kFa8EnENi67qc2E2KFE05RT4UCEAIYMAQY6wvek29gA==}
+ '@formkit/utils@1.7.2':
+ resolution: {integrity: sha512-bBF6alUBOqFfJHjVB95Vck0hp36vlw4QfFJxGfTO6BX68AEaFzzzabtpwfy0DbcHtwHh4Yn7l/rOWGxXEve+QQ==}
- '@formkit/validation@1.6.7':
- resolution: {integrity: sha512-4wUUG+Pz3hPeiLccYiXAzsrF7SXk28PYAeHJeBngIv9K82ieljBJpvvuCJDyA6SeSMOvmbI92TG4wx4u5cDLOw==}
+ '@formkit/validation@1.7.2':
+ resolution: {integrity: sha512-JJsLP7AI/++VujdwtBeUcPhCqY3FXSKZ7hajT7Ow5Feab7JLqVPjxVMFbXDgEOLjq0ex1NX/I+EQHfm5sqMRsA==}
- '@formkit/vue@1.6.7':
- resolution: {integrity: sha512-w3kjQD0lvtImyyTiy+fLaIZM/4r6sLDbpBIwke8ZA/d5orzNE96JPaloVKbH+HwCo6+z/1mclh1pW1S+7RgMcw==}
+ '@formkit/vue@1.7.2':
+ resolution: {integrity: sha512-jrvXl2ZhS6X5klTbP4N5zc0Dg37AjbAf8SCVoz7mfligVkmwrrF4SN3waMBcH+n9gqT+vrkOYb6bQXdvjUdnCQ==}
peerDependencies:
vue: ^3.4.0
@@ -985,8 +973,8 @@ packages:
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
- '@iconify/utils@2.3.0':
- resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==}
+ '@iconify/utils@3.1.0':
+ resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==}
'@intlify/core-base@9.14.2':
resolution: {integrity: sha512-DZyQ4Hk22sC81MP4qiCDuU+LdaYW91A6lCjq8AWPvY3+mGMzhGDfOCzvyR6YBQxtlPjFqMoFk9ylnNYRAQwXtQ==}
@@ -1291,10 +1279,10 @@ packages:
peerDependencies:
size-limit: 8.2.6
- '@tailwindcss/typography@0.5.15':
- resolution: {integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==}
+ '@tailwindcss/typography@0.5.19':
+ resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
peerDependencies:
- tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20'
+ tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
'@tanstack/table-core@8.20.5':
resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==}
@@ -1579,8 +1567,8 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
- acorn@8.15.0:
- resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -1712,8 +1700,8 @@ packages:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
- axios@1.13.2:
- resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
+ axios@1.13.6:
+ resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -1745,8 +1733,8 @@ packages:
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
- brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
@@ -1922,9 +1910,6 @@ packages:
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
- confbox@0.2.2:
- resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
-
config-chain@1.1.13:
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
@@ -2166,8 +2151,9 @@ packages:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
- dompurify@3.2.4:
- resolution: {integrity: sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==}
+ dompurify@3.3.2:
+ resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==}
+ engines: {node: '>=20'}
domutils@3.1.0:
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
@@ -2450,9 +2436,6 @@ packages:
resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
engines: {node: '>=12.0.0'}
- exsolve@1.0.8:
- resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
-
extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
@@ -2645,10 +2628,6 @@ packages:
resolution: {integrity: sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==}
engines: {node: '>=18'}
- globals@15.15.0:
- resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
- engines: {node: '>=18'}
-
globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}
@@ -2796,8 +2775,8 @@ packages:
resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==}
engines: {node: '>= 4'}
- immutable@4.3.7:
- resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==}
+ immutable@4.3.8:
+ resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==}
import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
@@ -3001,6 +2980,10 @@ packages:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
+ jiti@1.21.7:
+ resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
+ hasBin: true
+
js-beautify@1.15.1:
resolution: {integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==}
engines: {node: '>=14'}
@@ -3077,9 +3060,6 @@ packages:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
- kolorist@1.8.0:
- resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
-
launch-editor@2.9.1:
resolution: {integrity: sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==}
@@ -3097,8 +3077,8 @@ packages:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
- lilconfig@3.1.2:
- resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
+ lilconfig@3.1.3:
+ resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'}
lines-and-columns@1.2.4:
@@ -3131,10 +3111,6 @@ packages:
lit@2.2.6:
resolution: {integrity: sha512-K2vkeGABfSJSfkhqHy86ujchJs3NR9nW1bEEiV+bXDkbiQ60Tv5GUausYN2mXigZn8lC1qXuc46ArQRKYmumZw==}
- local-pkg@1.1.2:
- resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
- engines: {node: '>=14'}
-
locate-path@5.0.0:
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
engines: {node: '>=8'}
@@ -3147,12 +3123,6 @@ packages:
resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- lodash.castarray@4.4.0:
- resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
-
- lodash.isplainobject@4.0.6:
- resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
-
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
@@ -3287,15 +3257,11 @@ packages:
min-document@2.19.0:
resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
- minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ minimatch@3.1.5:
+ resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
- minimatch@9.0.1:
- resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
- engines: {node: '>=16 || 14 >=14.17'}
-
- minimatch@9.0.5:
- resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ minimatch@9.0.9:
+ resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
@@ -3308,8 +3274,8 @@ packages:
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
- mlly@1.8.0:
- resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
+ mlly@1.8.1:
+ resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==}
mpd-parser@0.21.0:
resolution: {integrity: sha512-NbpMJ57qQzFmfCiP1pbL7cGMbVTD0X1hqNgL0VYP1wLlZXLf/HtmvQpNkOA1AHkPVeGQng+7/jEtSvNUzV7Gdg==}
@@ -3606,9 +3572,6 @@ packages:
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
- pkg-types@2.3.0:
- resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
-
pngjs@5.0.0:
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
engines: {node: '>=10.13.0'}
@@ -3915,9 +3878,6 @@ packages:
engines: {node: '>=10.13.0'}
hasBin: true
- quansync@0.2.11:
- resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
-
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
@@ -4269,8 +4229,8 @@ packages:
resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==}
engines: {node: '>=10.0.0'}
- tailwindcss@3.4.13:
- resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==}
+ tailwindcss@3.4.19:
+ resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -4432,8 +4392,8 @@ packages:
uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
- ufo@1.6.1:
- resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
+ ufo@1.6.3:
+ resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
@@ -4622,10 +4582,10 @@ packages:
'@vue/composition-api':
optional: true
- vue-dompurify-html@5.1.0:
- resolution: {integrity: sha512-616o2/PBdOLM2bwlRWLdzeEC9NerLkwiudqNgaIJ5vBQWXec+u7Kuzh+45DtQQrids67s4pHnTnJZLVfyPMxbA==}
+ vue-dompurify-html@5.3.0:
+ resolution: {integrity: sha512-HJQGBHbfSPcb6Mu97McdKbX7TqRHZa6Ji8OCpCNyuHca5QvQZ8IiuwghFPSO8OkSQfqXPNPKFMZdCOrnGGmOSQ==}
peerDependencies:
- vue: ^3.0.0
+ vue: ^3.4.36
vue-eslint-parser@9.4.3:
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
@@ -4944,8 +4904,6 @@ snapshots:
package-manager-detector: 1.6.0
tinyexec: 1.0.2
- '@antfu/utils@8.1.1': {}
-
'@asamuzakjp/css-color@4.1.0':
dependencies:
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
@@ -5262,12 +5220,10 @@ snapshots:
dependencies:
postcss-selector-parser: 6.1.1
- '@egoist/tailwindcss-icons@1.9.0(tailwindcss@3.4.13)':
+ '@egoist/tailwindcss-icons@1.9.2(tailwindcss@3.4.19)':
dependencies:
- '@iconify/utils': 2.3.0
- tailwindcss: 3.4.13
- transitivePeerDependencies:
- - supports-color
+ '@iconify/utils': 3.1.0
+ tailwindcss: 3.4.19
'@esbuild/aix-ppc64@0.21.5':
optional: true
@@ -5354,7 +5310,7 @@ snapshots:
ignore: 5.2.4
import-fresh: 3.3.0
js-yaml: 4.1.0
- minimatch: 3.1.2
+ minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
@@ -5368,7 +5324,7 @@ snapshots:
ignore: 5.2.4
import-fresh: 3.3.0
js-yaml: 4.1.0
- minimatch: 3.1.2
+ minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
@@ -5385,67 +5341,61 @@ snapshots:
'@floating-ui/utils@0.2.7': {}
- '@formkit/core@1.6.7':
+ '@formkit/core@1.7.2':
dependencies:
- '@formkit/utils': 1.6.7
+ '@formkit/utils': 1.7.2
- '@formkit/dev@1.6.7':
+ '@formkit/dev@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/utils': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/utils': 1.7.2
- '@formkit/i18n@1.6.7':
+ '@formkit/i18n@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/utils': 1.6.7
- '@formkit/validation': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/utils': 1.7.2
+ '@formkit/validation': 1.7.2
- '@formkit/inputs@1.6.7':
+ '@formkit/inputs@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/utils': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/utils': 1.7.2
- '@formkit/observer@1.6.7':
+ '@formkit/observer@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/utils': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/utils': 1.7.2
- '@formkit/rules@1.6.7':
+ '@formkit/rules@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/utils': 1.6.7
- '@formkit/validation': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/utils': 1.7.2
+ '@formkit/validation': 1.7.2
- '@formkit/themes@1.6.7(tailwindcss@3.4.13)':
+ '@formkit/themes@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- optionalDependencies:
- tailwindcss: 3.4.13
+ '@formkit/core': 1.7.2
- '@formkit/utils@1.6.7': {}
+ '@formkit/utils@1.7.2': {}
- '@formkit/validation@1.6.7':
+ '@formkit/validation@1.7.2':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/observer': 1.6.7
- '@formkit/utils': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/observer': 1.7.2
+ '@formkit/utils': 1.7.2
- '@formkit/vue@1.6.7(tailwindcss@3.4.13)(vue@3.5.12(typescript@5.6.2))':
+ '@formkit/vue@1.7.2(vue@3.5.12(typescript@5.6.2))':
dependencies:
- '@formkit/core': 1.6.7
- '@formkit/dev': 1.6.7
- '@formkit/i18n': 1.6.7
- '@formkit/inputs': 1.6.7
- '@formkit/observer': 1.6.7
- '@formkit/rules': 1.6.7
- '@formkit/themes': 1.6.7(tailwindcss@3.4.13)
- '@formkit/utils': 1.6.7
- '@formkit/validation': 1.6.7
+ '@formkit/core': 1.7.2
+ '@formkit/dev': 1.7.2
+ '@formkit/i18n': 1.7.2
+ '@formkit/inputs': 1.7.2
+ '@formkit/observer': 1.7.2
+ '@formkit/rules': 1.7.2
+ '@formkit/themes': 1.7.2
+ '@formkit/utils': 1.7.2
+ '@formkit/validation': 1.7.2
vue: 3.5.12(typescript@5.6.2)
- transitivePeerDependencies:
- - tailwindcss
- - unocss
- - windicss
'@hcaptcha/vue3-hcaptcha@1.3.0(vue@3.5.12(typescript@5.6.2))':
dependencies:
@@ -5511,7 +5461,7 @@ snapshots:
dependencies:
'@humanwhocodes/object-schema': 2.0.3
debug: 4.3.5
- minimatch: 3.1.2
+ minimatch: 3.1.5
transitivePeerDependencies:
- supports-color
@@ -5549,18 +5499,11 @@ snapshots:
'@iconify/types@2.0.0': {}
- '@iconify/utils@2.3.0':
+ '@iconify/utils@3.1.0':
dependencies:
'@antfu/install-pkg': 1.1.0
- '@antfu/utils': 8.1.1
'@iconify/types': 2.0.0
- debug: 4.4.3
- globals: 15.15.0
- kolorist: 1.8.0
- local-pkg: 1.1.2
- mlly: 1.8.0
- transitivePeerDependencies:
- - supports-color
+ mlly: 1.8.1
'@intlify/core-base@9.14.2':
dependencies:
@@ -5847,13 +5790,10 @@ snapshots:
semver: 7.5.3
size-limit: 8.2.6
- '@tailwindcss/typography@0.5.15(tailwindcss@3.4.13)':
+ '@tailwindcss/typography@0.5.19(tailwindcss@3.4.19)':
dependencies:
- lodash.castarray: 4.4.0
- lodash.isplainobject: 4.0.6
- lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
- tailwindcss: 3.4.13
+ tailwindcss: 3.4.19
'@tanstack/table-core@8.20.5': {}
@@ -6230,7 +6170,7 @@ snapshots:
acorn@8.14.0: {}
- acorn@8.15.0: {}
+ acorn@8.16.0: {}
activestorage@5.2.8:
dependencies:
@@ -6391,7 +6331,7 @@ snapshots:
dependencies:
possible-typed-array-names: 1.0.0
- axios@1.13.2:
+ axios@1.13.6:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.5
@@ -6431,7 +6371,7 @@ snapshots:
balanced-match: 1.0.2
concat-map: 0.0.1
- brace-expansion@2.0.1:
+ brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
@@ -6633,8 +6573,6 @@ snapshots:
confbox@0.1.8: {}
- confbox@0.2.2: {}
-
config-chain@1.1.13:
dependencies:
ini: 1.3.8
@@ -6850,7 +6788,7 @@ snapshots:
dependencies:
domelementtype: 2.3.0
- dompurify@3.2.4:
+ dompurify@3.3.2:
optionalDependencies:
'@types/trusted-types': 2.0.7
@@ -6877,7 +6815,7 @@ snapshots:
dependencies:
'@one-ini/wasm': 0.1.1
commander: 10.0.1
- minimatch: 9.0.1
+ minimatch: 9.0.9
semver: 7.6.3
ee-first@1.1.1: {}
@@ -7144,7 +7082,7 @@ snapshots:
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
- minimatch: 3.1.2
+ minimatch: 3.1.5
object.fromentries: 2.0.8
object.groupby: 1.0.3
object.values: 1.2.0
@@ -7224,7 +7162,7 @@ snapshots:
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
- minimatch: 3.1.2
+ minimatch: 3.1.5
natural-compare: 1.4.0
optionator: 0.9.3
strip-ansi: 6.0.1
@@ -7270,8 +7208,6 @@ snapshots:
expect-type@1.1.0: {}
- exsolve@1.0.8: {}
-
extend-shallow@2.0.1:
dependencies:
is-extendable: 0.1.1
@@ -7456,7 +7392,7 @@ snapshots:
dependencies:
foreground-child: 3.3.0
jackspeak: 3.4.3
- minimatch: 9.0.5
+ minimatch: 9.0.9
minipass: 7.1.2
package-json-from-dist: 1.0.0
path-scurry: 1.11.1
@@ -7466,7 +7402,7 @@ snapshots:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
- minimatch: 3.1.2
+ minimatch: 3.1.5
once: 1.4.0
path-is-absolute: 1.0.1
@@ -7487,8 +7423,6 @@ snapshots:
globals@15.14.0: {}
- globals@15.15.0: {}
-
globalthis@1.0.3:
dependencies:
define-properties: 1.2.0
@@ -7684,7 +7618,7 @@ snapshots:
ignore@6.0.2: {}
- immutable@4.3.7:
+ immutable@4.3.8:
optional: true
import-fresh@3.3.0:
@@ -7874,6 +7808,8 @@ snapshots:
jiti@1.21.6: {}
+ jiti@1.21.7: {}
+
js-beautify@1.15.1:
dependencies:
config-chain: 1.1.13
@@ -7990,8 +7926,6 @@ snapshots:
kind-of@6.0.3: {}
- kolorist@1.8.0: {}
-
launch-editor@2.9.1:
dependencies:
picocolors: 1.1.0
@@ -8008,7 +7942,7 @@ snapshots:
lilconfig@2.1.0: {}
- lilconfig@3.1.2: {}
+ lilconfig@3.1.3: {}
lines-and-columns@1.2.4: {}
@@ -8059,12 +7993,6 @@ snapshots:
lit-element: 3.3.3
lit-html: 2.8.0
- local-pkg@1.1.2:
- dependencies:
- mlly: 1.8.0
- pkg-types: 2.3.0
- quansync: 0.2.11
-
locate-path@5.0.0:
dependencies:
p-locate: 4.1.0
@@ -8077,10 +8005,6 @@ snapshots:
dependencies:
p-locate: 6.0.0
- lodash.castarray@4.4.0: {}
-
- lodash.isplainobject@4.0.6: {}
-
lodash.merge@4.6.2: {}
lodash.truncate@4.4.2: {}
@@ -8217,17 +8141,13 @@ snapshots:
dependencies:
dom-walk: 0.1.2
- minimatch@3.1.2:
+ minimatch@3.1.5:
dependencies:
brace-expansion: 1.1.11
- minimatch@9.0.1:
+ minimatch@9.0.9:
dependencies:
- brace-expansion: 2.0.1
-
- minimatch@9.0.5:
- dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimist@1.2.8: {}
@@ -8235,12 +8155,12 @@ snapshots:
mitt@3.0.1: {}
- mlly@1.8.0:
+ mlly@1.8.1:
dependencies:
- acorn: 8.15.0
+ acorn: 8.16.0
pathe: 2.0.3
pkg-types: 1.3.1
- ufo: 1.6.1
+ ufo: 1.6.3
mpd-parser@0.21.0:
dependencies:
@@ -8511,13 +8431,7 @@ snapshots:
pkg-types@1.3.1:
dependencies:
confbox: 0.1.8
- mlly: 1.8.0
- pathe: 2.0.3
-
- pkg-types@2.3.0:
- dependencies:
- confbox: 0.2.2
- exsolve: 1.0.8
+ mlly: 1.8.1
pathe: 2.0.3
pngjs@5.0.0: {}
@@ -8634,7 +8548,7 @@ snapshots:
postcss-load-config@4.0.2(postcss@8.4.47):
dependencies:
- lilconfig: 3.1.2
+ lilconfig: 3.1.3
yaml: 2.5.1
optionalDependencies:
postcss: 8.4.47
@@ -8889,8 +8803,6 @@ snapshots:
pngjs: 5.0.0
yargs: 15.4.1
- quansync@0.2.11: {}
-
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
@@ -9035,7 +8947,7 @@ snapshots:
sass@1.79.3:
dependencies:
chokidar: 4.0.3
- immutable: 4.3.7
+ immutable: 4.3.8
source-map-js: 1.2.1
optional: true
@@ -9289,7 +9201,7 @@ snapshots:
string-width: 4.2.3
strip-ansi: 6.0.1
- tailwindcss@3.4.13:
+ tailwindcss@3.4.19:
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -9299,12 +9211,12 @@ snapshots:
fast-glob: 3.3.2
glob-parent: 6.0.2
is-glob: 4.0.3
- jiti: 1.21.6
- lilconfig: 2.1.0
+ jiti: 1.21.7
+ lilconfig: 3.1.3
micromatch: 4.0.8
normalize-path: 3.0.0
object-hash: 3.0.0
- picocolors: 1.1.0
+ picocolors: 1.1.1
postcss: 8.4.47
postcss-import: 15.1.0(postcss@8.4.47)
postcss-js: 4.0.1(postcss@8.4.47)
@@ -9324,7 +9236,7 @@ snapshots:
terser@5.33.0:
dependencies:
'@jridgewell/source-map': 0.3.11
- acorn: 8.15.0
+ acorn: 8.16.0
commander: 2.20.3
source-map-support: 0.5.21
optional: true
@@ -9333,7 +9245,7 @@ snapshots:
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 10.4.5
- minimatch: 9.0.5
+ minimatch: 9.0.9
text-segmentation@1.0.3:
dependencies:
@@ -9487,7 +9399,7 @@ snapshots:
uc.micro@2.1.0: {}
- ufo@1.6.1: {}
+ ufo@1.6.3: {}
unbox-primitive@1.0.2:
dependencies:
@@ -9672,9 +9584,9 @@ snapshots:
dependencies:
vue: 3.5.12(typescript@5.6.2)
- vue-dompurify-html@5.1.0(vue@3.5.12(typescript@5.6.2)):
+ vue-dompurify-html@5.3.0(vue@3.5.12(typescript@5.6.2)):
dependencies:
- dompurify: 3.2.4
+ dompurify: 3.3.2
vue: 3.5.12(typescript@5.6.2)
vue-eslint-parser@9.4.3(eslint@8.57.0):
diff --git a/spec/controllers/api/v1/accounts/agents_controller_spec.rb b/spec/controllers/api/v1/accounts/agents_controller_spec.rb
index a74cbe21e..46b38677a 100644
--- a/spec/controllers/api/v1/accounts/agents_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/agents_controller_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe 'Agents API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.parsed_body.size).to eq(account.users.count)
end
@@ -122,6 +123,7 @@ RSpec.describe 'Agents API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(other_agent.reload.name).to eq(params[:name])
end
@@ -171,6 +173,7 @@ RSpec.describe 'Agents API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.parsed_body['email']).to eq(params[:email])
expect(account.users.last.name).to eq('NewUser')
end
diff --git a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb
index 1b92d464f..d9ea3e641 100644
--- a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb
@@ -45,6 +45,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
response_body = response.parsed_body
contact_emails = response_body['payload'].pluck('email')
contact_inboxes_source_ids = response_body['payload'].flat_map { |c| c['contact_inboxes'].pluck('source_id') }
@@ -331,6 +332,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.body).to include(contact2.email)
expect(response.body).not_to include(contact1.email)
end
@@ -443,6 +445,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.body).to include(contact2.email)
expect(response.body).to include(contact1.email)
end
@@ -497,6 +500,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.body).to include(contact.name)
end
end
@@ -620,6 +624,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(contact.reload.name).to eq('Test Blub')
# custom attributes are merged properly without overwriting existing ones
expect(contact.custom_attributes).to eq({ 'test' => 'new test', 'test1' => 'test1', 'test2' => 'test2' })
diff --git a/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb
index f7ff042e5..9ab8d7316 100644
--- a/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/conversations/messages_controller_spec.rb
@@ -31,6 +31,7 @@ RSpec.describe 'Conversation Messages API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(conversation.messages.count).to eq(1)
expect(conversation.messages.first.content).to eq(params[:content])
end
@@ -182,6 +183,7 @@ RSpec.describe 'Conversation Messages API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:meta][:contact][:id]).to eq(conversation.contact_id)
end
end
diff --git a/spec/controllers/api/v1/accounts/conversations_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations_controller_spec.rb
index 4b3d5cc5f..ab70d1c65 100644
--- a/spec/controllers/api/v1/accounts/conversations_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/conversations_controller_spec.rb
@@ -27,6 +27,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
body = JSON.parse(response.body, symbolize_names: true)
expect(body[:data][:meta][:all_count]).to eq(1)
expect(body[:data][:meta].keys).to include(:all_count, :mine_count, :assigned_count, :unassigned_count)
@@ -165,6 +166,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
response_data = JSON.parse(response.body, symbolize_names: true)
expect(response_data.count).to eq(2)
end
@@ -234,6 +236,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(conversation.display_id)
end
@@ -282,6 +285,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:priority]).to eq('high')
end
@@ -342,6 +346,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
response_data = JSON.parse(response.body, symbolize_names: true)
expect(response_data[:additional_attributes]).to eq(additional_attributes)
end
@@ -449,9 +454,11 @@ RSpec.describe 'Conversations API', type: :request do
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_status",
headers: agent.create_new_auth_token,
+ params: { status: 'open' },
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(conversation.reload.status).to eq('open')
end
diff --git a/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb b/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb
index b93ca8ecf..8aae60d53 100644
--- a/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb
@@ -32,6 +32,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(2)
end
@@ -95,6 +96,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(inbox.id)
end
@@ -383,6 +385,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.body).to include('test.com')
end
@@ -478,6 +481,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(inbox.reload.enable_auto_assignment).to be_falsey
expect(inbox.reload.portal_id).to eq(portal.id)
expect(response.parsed_body['name']).to eq 'new test inbox'
diff --git a/spec/controllers/api/v1/accounts/teams_controller_spec.rb b/spec/controllers/api/v1/accounts/teams_controller_spec.rb
index 347510db6..78ae78696 100644
--- a/spec/controllers/api/v1/accounts/teams_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/teams_controller_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.parsed_body.first['id']).to eq(account.teams.first.id)
end
end
@@ -45,6 +46,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.parsed_body['id']).to eq(team.id)
end
end
@@ -83,6 +85,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(Team.count).to eq(2)
end
end
@@ -121,6 +124,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(team.reload.name).to eq('new-team')
end
end
diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb
index ec49ecd39..d76f22187 100644
--- a/spec/controllers/api/v1/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts_controller_spec.rb
@@ -81,6 +81,29 @@ RSpec.describe 'Accounts API', type: :request do
end
end
+ context 'when ENABLE_ACCOUNT_SIGNUP is stored as boolean false' do
+ before do
+ GlobalConfig.clear_cache
+ InstallationConfig.where(name: 'ENABLE_ACCOUNT_SIGNUP').delete_all
+ InstallationConfig.create!(name: 'ENABLE_ACCOUNT_SIGNUP', value: false, locked: false)
+ end
+
+ after do
+ InstallationConfig.where(name: 'ENABLE_ACCOUNT_SIGNUP').delete_all
+ GlobalConfig.clear_cache
+ end
+
+ it 'responds 404 on requests' do
+ params = { account_name: 'test', email: email, user_full_name: user_full_name, password: 'Password1!' }
+
+ post api_v1_accounts_url,
+ params: params,
+ as: :json
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
context 'when ENABLE_ACCOUNT_SIGNUP env variable is set to api_only' do
it 'does not respond 404 on requests' do
params = { account_name: 'test', email: email, user_full_name: user_full_name, password: 'Password1!' }
@@ -126,6 +149,7 @@ RSpec.describe 'Accounts API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.body).to include(account.name)
expect(response.body).to include(account.locale)
expect(response.body).to include(account.domain)
@@ -161,22 +185,22 @@ RSpec.describe 'Accounts API', type: :request do
end
end
- describe 'PUT /api/v1/accounts/{account.id}' do
+ describe 'PATCH /api/v1/accounts/{account.id}' do
let(:account) { create(:account) }
let(:agent) { create(:user, account: account, role: :agent) }
let(:admin) { create(:user, account: account, role: :administrator) }
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
- put "/api/v1/accounts/#{account.id}"
+ patch "/api/v1/accounts/#{account.id}"
expect(response).to have_http_status(:unauthorized)
end
end
context 'when it is an unauthorized user' do
it 'returns unauthorized' do
- put "/api/v1/accounts/#{account.id}",
- headers: agent.create_new_auth_token
+ patch "/api/v1/accounts/#{account.id}",
+ headers: agent.create_new_auth_token
expect(response).to have_http_status(:unauthorized)
end
@@ -196,11 +220,20 @@ RSpec.describe 'Accounts API', type: :request do
company_size: '1-10'
}
+ it 'returns a valid schema' do
+ patch "/api/v1/accounts/#{account.id}",
+ params: params,
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to conform_schema(200)
+ end
+
it 'modifies an account' do
- put "/api/v1/accounts/#{account.id}",
- params: params,
- headers: admin.create_new_auth_token,
- as: :json
+ patch "/api/v1/accounts/#{account.id}",
+ params: params,
+ headers: admin.create_new_auth_token,
+ as: :json
expect(response).to have_http_status(:success)
expect(account.reload.name).to eq(params[:name])
@@ -219,19 +252,19 @@ RSpec.describe 'Accounts API', type: :request do
it 'updates onboarding step to invite_team if onboarding step is present in account custom attributes' do
account.update(custom_attributes: { onboarding_step: 'account_update' })
- put "/api/v1/accounts/#{account.id}",
- params: params,
- headers: admin.create_new_auth_token,
- as: :json
+ patch "/api/v1/accounts/#{account.id}",
+ params: params,
+ headers: admin.create_new_auth_token,
+ as: :json
expect(account.reload.custom_attributes['onboarding_step']).to eq('invite_team')
end
it 'will not update onboarding step if onboarding step is not present in account custom attributes' do
- put "/api/v1/accounts/#{account.id}",
- params: params,
- headers: admin.create_new_auth_token,
- as: :json
+ patch "/api/v1/accounts/#{account.id}",
+ params: params,
+ headers: admin.create_new_auth_token,
+ as: :json
expect(account.reload.custom_attributes['onboarding_step']).to be_nil
end
@@ -239,10 +272,10 @@ RSpec.describe 'Accounts API', type: :request do
it 'Throws error 422' do
params[:name] = 'test' * 999
- put "/api/v1/accounts/#{account.id}",
- params: params,
- headers: admin.create_new_auth_token,
- as: :json
+ patch "/api/v1/accounts/#{account.id}",
+ params: params,
+ headers: admin.create_new_auth_token,
+ as: :json
expect(response).to have_http_status(:unprocessable_entity)
json_response = response.parsed_body
diff --git a/spec/controllers/api/v1/profiles_controller_spec.rb b/spec/controllers/api/v1/profiles_controller_spec.rb
index 30c5b69f4..19054b523 100644
--- a/spec/controllers/api/v1/profiles_controller_spec.rb
+++ b/spec/controllers/api/v1/profiles_controller_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
json_response = response.parsed_body
expect(json_response['id']).to eq(agent.id)
expect(json_response['email']).to eq(agent.email)
@@ -50,6 +51,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
json_response = response.parsed_body
agent.reload
expect(json_response['id']).to eq(agent.id)
@@ -64,6 +66,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
agent.reload
expect(agent.custom_attributes['phone_number']).to eq('+123456789')
@@ -91,6 +94,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(agent.reload.valid_password?('Test1234!')).to be true
end
diff --git a/spec/controllers/api/v2/accounts_controller_spec.rb b/spec/controllers/api/v2/accounts_controller_spec.rb
index 182ebadac..a39e37a91 100644
--- a/spec/controllers/api/v2/accounts_controller_spec.rb
+++ b/spec/controllers/api/v2/accounts_controller_spec.rb
@@ -94,6 +94,29 @@ RSpec.describe 'Accounts API', type: :request do
end
end
+ context 'when ENABLE_ACCOUNT_SIGNUP is stored as boolean false' do
+ before do
+ GlobalConfig.clear_cache
+ InstallationConfig.where(name: 'ENABLE_ACCOUNT_SIGNUP').delete_all
+ InstallationConfig.create!(name: 'ENABLE_ACCOUNT_SIGNUP', value: false, locked: false)
+ end
+
+ after do
+ InstallationConfig.where(name: 'ENABLE_ACCOUNT_SIGNUP').delete_all
+ GlobalConfig.clear_cache
+ end
+
+ it 'responds 404 on requests' do
+ params = { email: email, password: 'Password1!' }
+
+ post api_v2_accounts_url,
+ params: params,
+ as: :json
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
context 'when ENABLE_ACCOUNT_SIGNUP env variable is set to api_only' do
let(:account_builder) { double }
let(:account) { create(:account) }
diff --git a/spec/controllers/devise/omniauth_callbacks_controller_spec.rb b/spec/controllers/devise/omniauth_callbacks_controller_spec.rb
index 1a775f88f..603458a01 100644
--- a/spec/controllers/devise/omniauth_callbacks_controller_spec.rb
+++ b/spec/controllers/devise/omniauth_callbacks_controller_spec.rb
@@ -106,6 +106,26 @@ RSpec.describe 'DeviseOverrides::OmniauthCallbacksController', type: :request do
end
end
+ it 'blocks signup if config is stored as boolean false' do
+ GlobalConfig.clear_cache
+ InstallationConfig.where(name: 'ENABLE_ACCOUNT_SIGNUP').delete_all
+ InstallationConfig.create!(name: 'ENABLE_ACCOUNT_SIGNUP', value: false, locked: false)
+
+ with_modified_env FRONTEND_URL: 'http://www.example.com' do
+ set_omniauth_config('does-not-exist-for-sure@example.com')
+ allow(email_validation_service).to receive(:perform).and_return(true)
+
+ get '/omniauth/google_oauth2/callback'
+
+ expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
+ follow_redirect!
+ expect(response).to redirect_to(%r{/app/login\?error=no-account-found$})
+ end
+ ensure
+ InstallationConfig.where(name: 'ENABLE_ACCOUNT_SIGNUP').delete_all
+ GlobalConfig.clear_cache
+ end
+
it 'allows login' do
with_modified_env FRONTEND_URL: 'http://www.example.com' do
create(:user, email: 'test@example.com')
diff --git a/spec/controllers/platform/api/v1/accounts_controller_spec.rb b/spec/controllers/platform/api/v1/accounts_controller_spec.rb
index 63f53d0d6..6c95a0209 100644
--- a/spec/controllers/platform/api/v1/accounts_controller_spec.rb
+++ b/spec/controllers/platform/api/v1/accounts_controller_spec.rb
@@ -144,6 +144,7 @@ RSpec.describe 'Platform Accounts API', type: :request do
headers: { api_access_token: platform_app.access_token.token }, as: :json
expect(response).to have_http_status(:success)
+ expect(response).to conform_schema(200)
expect(response.body).to include(account.name)
end
end
diff --git a/spec/enterprise/controllers/api/v1/accounts/captain/assistants_controller_spec.rb b/spec/enterprise/controllers/api/v1/accounts/captain/assistants_controller_spec.rb
index 24deb98dd..4689defaf 100644
--- a/spec/enterprise/controllers/api/v1/accounts/captain/assistants_controller_spec.rb
+++ b/spec/enterprise/controllers/api/v1/accounts/captain/assistants_controller_spec.rb
@@ -259,10 +259,12 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
message_content: 'Hello assistant',
message_history: [
{ role: 'user', content: 'Previous message' },
- { role: 'assistant', content: 'Previous response' }
+ { role: 'assistant', content: 'Previous response', agent_name: 'billing_scenario' }
]
}
end
+ let(:chat_service) { instance_double(Captain::Llm::AssistantChatService) }
+ let(:agent_runner_service) { instance_double(Captain::Assistant::AgentRunnerService) }
context 'when it is an un-authenticated user' do
it 'returns unauthorized' do
@@ -274,11 +276,14 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
end
end
- context 'when it is an agent' do
- it 'generates a response' do
- chat_service = instance_double(Captain::Llm::AssistantChatService)
- allow(Captain::Llm::AssistantChatService).to receive(:new).with(assistant: assistant).and_return(chat_service)
+ context 'when captain v2 is disabled' do
+ it 'generates a response with the legacy assistant chat service' do
+ allow(Captain::Llm::AssistantChatService).to receive(:new).with(
+ assistant: assistant,
+ source: 'playground'
+ ).and_return(chat_service)
allow(chat_service).to receive(:generate_response).and_return({ content: 'Assistant response' })
+ expect(Captain::Assistant::AgentRunnerService).not_to receive(:new)
post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
params: valid_params,
@@ -292,14 +297,15 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
)
expect(json_response[:content]).to eq('Assistant response')
end
- end
- context 'when message_history is not provided' do
it 'uses empty array as default' do
params_without_history = { message_content: 'Hello assistant' }
- chat_service = instance_double(Captain::Llm::AssistantChatService)
- allow(Captain::Llm::AssistantChatService).to receive(:new).with(assistant: assistant).and_return(chat_service)
+ allow(Captain::Llm::AssistantChatService).to receive(:new).with(
+ assistant: assistant,
+ source: 'playground'
+ ).and_return(chat_service)
allow(chat_service).to receive(:generate_response).and_return({ content: 'Assistant response' })
+ expect(Captain::Assistant::AgentRunnerService).not_to receive(:new)
post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
params: params_without_history,
@@ -313,5 +319,53 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
)
end
end
+
+ context 'when captain v2 is enabled' do
+ before do
+ account.enable_features('captain_integration_v2')
+ end
+
+ it 'generates a response with the agent runner service' do
+ allow(Captain::Assistant::AgentRunnerService).to receive(:new).with(
+ assistant: assistant,
+ source: 'playground'
+ ).and_return(agent_runner_service)
+ allow(agent_runner_service).to receive(:generate_response).and_return({ response: 'Assistant response' })
+ expect(Captain::Llm::AssistantChatService).not_to receive(:new)
+
+ post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
+ params: valid_params,
+ headers: agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ expect(agent_runner_service).to have_received(:generate_response).with(
+ message_history: valid_params[:message_history] + [{ role: 'user', content: valid_params[:message_content] }]
+ )
+ expect(json_response[:response]).to eq('Assistant response')
+ end
+
+ it 'does not duplicate the latest user message if it is already in history' do
+ params_with_latest_message = {
+ message_content: 'Hello assistant',
+ message_history: [{ role: 'user', content: 'Hello assistant' }]
+ }
+ allow(Captain::Assistant::AgentRunnerService).to receive(:new).with(
+ assistant: assistant,
+ source: 'playground'
+ ).and_return(agent_runner_service)
+ allow(agent_runner_service).to receive(:generate_response).and_return({ response: 'Assistant response' })
+
+ post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
+ params: params_with_latest_message,
+ headers: agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ expect(agent_runner_service).to have_received(:generate_response).with(
+ message_history: params_with_latest_message[:message_history]
+ )
+ end
+ end
end
end
diff --git a/spec/enterprise/models/captain/scenario_spec.rb b/spec/enterprise/models/captain/scenario_spec.rb
index 163581f01..94ce5325a 100644
--- a/spec/enterprise/models/captain/scenario_spec.rb
+++ b/spec/enterprise/models/captain/scenario_spec.rb
@@ -42,6 +42,45 @@ RSpec.describe Captain::Scenario, type: :model do
end
end
+ describe '#handoff_key' do
+ let(:account) { create(:account) }
+ let(:assistant) { create(:captain_assistant, account: account) }
+
+ it 'uses id plus readable slug for persisted scenarios' do
+ scenario = create(:captain_scenario, assistant: assistant, account: account,
+ title: 'Handle complex refund requests requiring manager approval steps')
+
+ expect(scenario.handoff_key).to start_with("scenario_#{scenario.id}_")
+ expect(scenario.handoff_key).to end_with('_agent')
+ expect("handoff_to_#{scenario.handoff_key}".length).to be <= 60
+ end
+
+ it 'uses a truncated slug key for unsaved scenarios' do
+ scenario = build(:captain_scenario, assistant: assistant, account: account,
+ title: 'Troubleshoot payment gateway errors for recurring subscription charges')
+
+ expect(scenario.handoff_key).to match(/\Ascenario_draft_[a-z0-9_]+_agent\z/)
+ expect("handoff_to_#{scenario.handoff_key}".length).to be <= 60
+ end
+
+ it 'stays within length budget even for large ids' do
+ scenario = build(:captain_scenario, assistant: assistant, account: account,
+ title: 'A very long scenario title used only for budget verification')
+ allow(scenario).to receive(:id).and_return(1_234_567_890_123_456_789)
+
+ expect("handoff_to_#{scenario.handoff_key}".length).to be <= 60
+ end
+
+ it 'exposes handoff keys in assistant prompt context' do
+ scenario = create(:captain_scenario, assistant: assistant, account: account)
+
+ prompt_context = assistant.send(:prompt_context)
+ scenario_config = prompt_context[:scenarios].find { |entry| entry[:title] == scenario.title }
+
+ expect(scenario_config[:key]).to eq(scenario.handoff_key)
+ end
+ end
+
describe 'tool validation and population' do
let(:account) { create(:account) }
let(:assistant) { create(:captain_assistant, account: account) }
diff --git a/spec/enterprise/services/enterprise/message_templates/hook_execution_service_spec.rb b/spec/enterprise/services/enterprise/message_templates/hook_execution_service_spec.rb
index 151e9101a..9eacb0ba1 100644
--- a/spec/enterprise/services/enterprise/message_templates/hook_execution_service_spec.rb
+++ b/spec/enterprise/services/enterprise/message_templates/hook_execution_service_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'schedules captain response job for incoming messages on pending conversations' do
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end
end
@@ -43,7 +43,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'schedules captain response job outside business hours (Captain always responds when configured)' do
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end
it 'performs captain handoff when quota is exceeded (OOO template will kick in after handoff)' do
@@ -52,7 +52,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
custom_attributes: account.custom_attributes.merge('captain_responses_usage' => 100)
)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
expect(conversation.reload.status).to eq('open')
end
@@ -62,7 +62,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
allow(out_of_office_service).to receive(:perform).and_return(true)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
end
@@ -76,7 +76,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'schedules captain response job regardless of time' do
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end
end
@@ -95,7 +95,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
end
it 'performs handoff within business hours when quota exceeded' do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
expect(conversation.reload.status).to eq('open')
end
@@ -110,7 +110,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'does not schedule captain response job' do
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end
end
@@ -122,7 +122,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'does not schedule captain response job' do
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end
end
@@ -130,7 +130,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'does not schedule captain response job' do
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
- create(:message, conversation: conversation, message_type: :outgoing)
+ create(:message, conversation: conversation, message_type: :outgoing, account: account)
end
end
@@ -144,7 +144,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.not_to(change { conversation.reload.messages.template.count })
end
@@ -160,7 +160,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
)
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.not_to(change { conversation.reload.messages.template.count })
end
end
@@ -174,7 +174,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.to change { conversation.reload.messages.template.count }.by(1)
greeting_message = conversation.reload.messages.template.last
@@ -193,7 +193,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
)
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.to change { conversation.reload.messages.template.count }.by(1)
out_of_office_message = conversation.reload.messages.template.last
@@ -211,7 +211,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.to change { conversation.reload.messages.template.count }.by(1)
greeting_message = conversation.reload.messages.template.last
@@ -230,7 +230,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
)
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.to change { conversation.reload.messages.template.count }.by(1)
out_of_office_message = conversation.reload.messages.template.last
@@ -245,7 +245,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'schedules captain response job for incoming messages on pending campaign conversations' do
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(campaign_conversation, assistant)
- create(:message, conversation: campaign_conversation, message_type: :incoming)
+ create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
end
it 'does not send greeting template on campaign conversations' do
@@ -255,7 +255,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
allow(greeting_service).to receive(:perform).and_return(true)
- create(:message, conversation: campaign_conversation, message_type: :incoming)
+ create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
end
@@ -271,7 +271,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
allow(out_of_office_service).to receive(:perform).and_return(true)
- create(:message, conversation: campaign_conversation, message_type: :incoming)
+ create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
end
@@ -284,7 +284,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::EmailCollect).to receive(:new).and_return(email_collect_service)
allow(email_collect_service).to receive(:perform).and_return(true)
- create(:message, conversation: campaign_conversation, message_type: :incoming)
+ create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new)
end
@@ -304,7 +304,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
)
expect do
- create(:message, conversation: campaign_conversation, message_type: :incoming)
+ create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
end.not_to(change { campaign_conversation.messages.template.count })
end
end
@@ -332,7 +332,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'sends out of office message after handoff due to quota exceeded' do
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.to change { conversation.messages.template.count }.by(1)
expect(conversation.reload.status).to eq('open')
@@ -356,7 +356,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
it 'does not send out of office message after handoff' do
expect do
- create(:message, conversation: conversation, message_type: :incoming)
+ create(:message, conversation: conversation, message_type: :incoming, account: account)
end.not_to(change { conversation.messages.template.count })
expect(conversation.reload.status).to eq('open')
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index bb8ea89e1..d863dd58c 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -75,6 +75,10 @@ RSpec.configure do |config|
config.include ActiveSupport::Testing::TimeHelpers
config.include ActionCable::TestHelper
config.include ActiveJob::TestHelper
+
+ # OpenAPI response validation via Skooma
+ path_to_openapi = Rails.root.join('swagger/swagger.json')
+ config.include Skooma::RSpec[path_to_openapi], type: :request
end
Shoulda::Matchers.configure do |config|
diff --git a/spec/services/action_service_spec.rb b/spec/services/action_service_spec.rb
index 95b1e6ecf..f4c20b191 100644
--- a/spec/services/action_service_spec.rb
+++ b/spec/services/action_service_spec.rb
@@ -50,6 +50,26 @@ describe ActionService do
action_service.assign_agent(['nil'])
expect(conversation.reload.assignee).to be_nil
end
+
+ context 'when agent is confirmed' do
+ it 'assigns the agent to the conversation' do
+ inbox_member
+ action_service.assign_agent([agent.id])
+ expect(conversation.reload.assignee).to eq(agent)
+ end
+ end
+
+ context 'when agent is unconfirmed' do
+ let(:unconfirmed_agent) { create(:user, account: account, role: :agent, skip_confirmation: false) }
+ let(:unconfirmed_inbox_member) { create(:inbox_member, inbox: conversation.inbox, user: unconfirmed_agent) }
+
+ it 'does not assign unconfirmed agent to the conversation' do
+ unconfirmed_inbox_member
+ original_assignee = conversation.assignee
+ action_service.assign_agent([unconfirmed_agent.id])
+ expect(conversation.reload.assignee).to eq(original_assignee)
+ end
+ end
end
describe '#assign_team' do
diff --git a/spec/services/message_templates/hook_execution_service_spec.rb b/spec/services/message_templates/hook_execution_service_spec.rb
index fb9437111..e186227be 100644
--- a/spec/services/message_templates/hook_execution_service_spec.rb
+++ b/spec/services/message_templates/hook_execution_service_spec.rb
@@ -15,7 +15,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::Greeting).to receive(:new)
# described class gets called in message after commit
- create(:message, conversation: conversation, message_type: 'activity', content: 'Conversation marked resolved!!')
+ create(:message, conversation: conversation, account: conversation.account, message_type: 'activity', content: 'Conversation marked resolved!!')
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new)
@@ -36,7 +36,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::Greeting).to receive(:new)
# described class gets called in message after commit
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
expect(MessageTemplates::Template::EmailCollect).to have_received(:new).with(conversation: message.conversation)
@@ -54,7 +54,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
allow(greeting_service).to receive(:perform).and_return(true)
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::Greeting).not_to have_received(:new).with(conversation: message.conversation)
end
end
@@ -75,7 +75,7 @@ describe MessageTemplates::HookExecutionService do
allow(greeting_service).to receive(:perform).and_return(true)
# described class gets called in message after commit
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::Greeting).to have_received(:new).with(conversation: message.conversation)
expect(greeting_service).to have_received(:perform)
@@ -90,7 +90,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::EmailCollect).to receive(:new).and_return(true)
# described class gets called in message after commit
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation)
end
@@ -105,7 +105,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::EmailCollect).to receive(:new).and_return(true)
# described class gets called in message after commit
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation)
end
@@ -123,7 +123,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
allow(greeting_service).to receive(:perform).and_return(true)
- create(:message, conversation: conversation)
+ create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
end
@@ -139,7 +139,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
allow(out_of_office_service).to receive(:perform).and_return(true)
- create(:message, conversation: conversation)
+ create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
end
@@ -151,7 +151,7 @@ describe MessageTemplates::HookExecutionService do
conversation = create(:conversation, contact: contact)
conversation.inbox.update(greeting_enabled: true, enable_email_collect: true, greeting_message: 'Hi, this is a greeting message')
- message = create(:message, conversation: conversation, content_type: :incoming_email)
+ message = create(:message, conversation: conversation, account: conversation.account, content_type: :incoming_email)
message.content_attributes = { email: { auto_reply: true } }
message.save!
@@ -188,7 +188,7 @@ describe MessageTemplates::HookExecutionService do
allow(out_of_office_service).to receive(:perform).and_return(true)
# described class gets called in message after commit
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::OutOfOffice).to have_received(:new).with(conversation: message.conversation)
expect(out_of_office_service).to have_received(:perform)
@@ -202,13 +202,13 @@ describe MessageTemplates::HookExecutionService do
conversation.inbox.update(working_hours_enabled: true, out_of_office_message: 'We are out of office')
conversation.inbox.working_hours.today.update!(closed_all_day: true)
- create(:message, conversation: conversation, message_type: :outgoing, created_at: 2.minutes.ago)
+ create(:message, conversation: conversation, account: conversation.account, message_type: :outgoing, created_at: 2.minutes.ago)
out_of_office_service = double
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
allow(out_of_office_service).to receive(:perform).and_return(true)
- create(:message, conversation: conversation)
+ create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
expect(out_of_office_service).not_to have_received(:perform)
@@ -221,13 +221,13 @@ describe MessageTemplates::HookExecutionService do
conversation.inbox.update(working_hours_enabled: true, out_of_office_message: 'We are out of office')
conversation.inbox.working_hours.today.update!(closed_all_day: true)
- create(:message, conversation: conversation, private: true, message_type: :outgoing, created_at: 2.minutes.ago)
+ create(:message, conversation: conversation, account: conversation.account, private: true, message_type: :outgoing, created_at: 2.minutes.ago)
out_of_office_service = double
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
allow(out_of_office_service).to receive(:perform).and_return(true)
- create(:message, conversation: conversation)
+ create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::OutOfOffice).to have_received(:new).with(conversation: conversation)
expect(out_of_office_service).to have_received(:perform)
@@ -247,7 +247,7 @@ describe MessageTemplates::HookExecutionService do
allow(out_of_office_service).to receive(:perform).and_return(true)
# described class gets called in message after commit
- message = create(:message, conversation: conversation, message_type: 'outgoing')
+ message = create(:message, conversation: conversation, account: conversation.account, message_type: 'outgoing')
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new).with(conversation: message.conversation)
expect(out_of_office_service).not_to have_received(:perform)
@@ -265,7 +265,7 @@ describe MessageTemplates::HookExecutionService do
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
allow(out_of_office_service).to receive(:perform).and_return(false)
- message = create(:message, conversation: conversation)
+ message = create(:message, conversation: conversation, account: conversation.account)
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new).with(conversation: message.conversation)
expect(out_of_office_service).not_to receive(:perform)
end
diff --git a/spec/swagger/openapi_spec.rb b/spec/swagger/openapi_spec.rb
new file mode 100644
index 000000000..330f832ea
--- /dev/null
+++ b/spec/swagger/openapi_spec.rb
@@ -0,0 +1,7 @@
+require 'rails_helper'
+
+RSpec.describe 'OpenAPI document', type: :request do
+ it 'is valid against the OpenAPI 3.1.0 meta-schema' do
+ expect(skooma_openapi_schema).to be_valid_document
+ end
+end
diff --git a/swagger/definitions/index.yml b/swagger/definitions/index.yml
index 1033da7dd..e6ca1a041 100644
--- a/swagger/definitions/index.yml
+++ b/swagger/definitions/index.yml
@@ -70,6 +70,8 @@ platform_account:
$ref: ./resource/platform_account.yml
team:
$ref: ./resource/team.yml
+label:
+ $ref: ./resource/label.yml
integrations_app:
$ref: ./resource/integrations/app.yml
integrations_hook:
@@ -142,6 +144,10 @@ inbox_update_payload:
team_create_update_payload:
$ref: ./request/team/create_update_payload.yml
+# Label
+label_create_update_payload:
+ $ref: ./request/label/create_update_payload.yml
+
# Custom Filter
custom_filter_create_update_payload:
$ref: ./request/custom_filter/create_update_payload.yml
diff --git a/swagger/definitions/request/account/update_payload.yml b/swagger/definitions/request/account/update_payload.yml
index b2e47cbc2..4b907ed99 100644
--- a/swagger/definitions/request/account/update_payload.yml
+++ b/swagger/definitions/request/account/update_payload.yml
@@ -18,20 +18,23 @@ properties:
example: 'support@example.com'
# Settings parameters (stored in settings JSONB column)
auto_resolve_after:
- type: integer
+ type:
+ - integer
+ - 'null'
minimum: 10
maximum: 1439856
- nullable: true
description: Auto resolve conversations after specified minutes
example: 1440
auto_resolve_message:
- type: string
- nullable: true
+ type:
+ - string
+ - 'null'
description: Message to send when auto resolving
example: "This conversation has been automatically resolved due to inactivity"
auto_resolve_ignore_waiting:
- type: boolean
- nullable: true
+ type:
+ - boolean
+ - 'null'
description: Whether to ignore waiting conversations for auto resolve
example: false
# Custom attributes parameters (stored in custom_attributes JSONB column)
diff --git a/swagger/definitions/request/conversation/create_payload.yml b/swagger/definitions/request/conversation/create_payload.yml
index c0cc75c46..a5e41f66f 100644
--- a/swagger/definitions/request/conversation/create_payload.yml
+++ b/swagger/definitions/request/conversation/create_payload.yml
@@ -1,7 +1,6 @@
type: object
required:
- source_id
- - inbox_id
properties:
source_id:
type: string
diff --git a/swagger/definitions/request/label/create_update_payload.yml b/swagger/definitions/request/label/create_update_payload.yml
new file mode 100644
index 000000000..e0054e8f0
--- /dev/null
+++ b/swagger/definitions/request/label/create_update_payload.yml
@@ -0,0 +1,18 @@
+type: object
+properties:
+ title:
+ type: string
+ description: The label title
+ example: support
+ description:
+ type: string
+ description: A short description for the label
+ example: Conversations that need support follow-up
+ color:
+ type: string
+ description: Hex color code for the label
+ example: '#1f93ff'
+ show_on_sidebar:
+ type: boolean
+ description: Whether the label should appear in the sidebar
+ example: true
diff --git a/swagger/definitions/resource/account_detail.yml b/swagger/definitions/resource/account_detail.yml
index 0ff463bae..19b927157 100644
--- a/swagger/definitions/resource/account_detail.yml
+++ b/swagger/definitions/resource/account_detail.yml
@@ -26,9 +26,7 @@ properties:
type: object
description: Cache keys for the account
features:
- type: array
- items:
- type: string
+ type: object
description: Enabled features for the account
settings:
type: object
@@ -48,16 +46,24 @@ properties:
description: Custom attributes of the account
properties:
plan_name:
- type: string
+ type:
+ - string
+ - 'null'
description: Subscription plan name
subscribed_quantity:
- type: number
+ type:
+ - number
+ - 'null'
description: Subscribed quantity
subscription_status:
- type: string
+ type:
+ - string
+ - 'null'
description: Subscription status
subscription_ends_on:
- type: string
+ type:
+ - string
+ - 'null'
format: date
description: Subscription end date
industry:
diff --git a/swagger/definitions/resource/account_show_response.yml b/swagger/definitions/resource/account_show_response.yml
index 208b27218..7def2290d 100644
--- a/swagger/definitions/resource/account_show_response.yml
+++ b/swagger/definitions/resource/account_show_response.yml
@@ -3,7 +3,9 @@ allOf:
- type: object
properties:
latest_chatwoot_version:
- type: string
+ type:
+ - string
+ - 'null'
description: Latest version of Chatwoot available
example: "3.0.0"
subscribed_features:
diff --git a/swagger/definitions/resource/agent.yml b/swagger/definitions/resource/agent.yml
index 5287f3e6f..1d7b2b4c3 100644
--- a/swagger/definitions/resource/agent.yml
+++ b/swagger/definitions/resource/agent.yml
@@ -31,5 +31,7 @@ properties:
type: string
description: The thumbnail of the agent
custom_role_id:
- type: integer
+ type:
+ - integer
+ - 'null'
description: The custom role id of the agent
diff --git a/swagger/definitions/resource/audit_log.yml b/swagger/definitions/resource/audit_log.yml
index 9dfa63263..10bbfc285 100644
--- a/swagger/definitions/resource/audit_log.yml
+++ b/swagger/definitions/resource/audit_log.yml
@@ -38,8 +38,9 @@ properties:
type: integer
description: Version number of the audit log entry
comment:
- type: string
- nullable: true
+ type:
+ - string
+ - 'null'
description: Optional comment associated with the audit log entry
request_uuid:
type: string
@@ -48,6 +49,7 @@ properties:
type: integer
description: Unix timestamp when the audit log entry was created
remote_address:
- type: string
- nullable: true
+ type:
+ - string
+ - 'null'
description: IP address from which the action was performed
\ No newline at end of file
diff --git a/swagger/definitions/resource/contact_conversation_message.yml b/swagger/definitions/resource/contact_conversation_message.yml
index e95923e52..a0334dfba 100644
--- a/swagger/definitions/resource/contact_conversation_message.yml
+++ b/swagger/definitions/resource/contact_conversation_message.yml
@@ -31,9 +31,10 @@ properties:
type: string
description: Status of the message
source_id:
- type: string
+ type:
+ - string
+ - 'null'
description: Source ID of the message
- nullable: true
content_type:
type: string
description: Type of the content
@@ -41,13 +42,15 @@ properties:
type: object
description: Attributes of the content
sender_type:
- type: string
+ type:
+ - string
+ - 'null'
description: Type of the sender
- nullable: true
sender_id:
- type: integer
+ type:
+ - integer
+ - 'null'
description: ID of the sender
- nullable: true
external_source_ids:
type: object
description: External source IDs
@@ -55,9 +58,10 @@ properties:
type: object
description: Additional attributes of the message
processed_message_content:
- type: string
+ type:
+ - string
+ - 'null'
description: Processed message content
- nullable: true
sentiment:
type: object
description: Sentiment analysis of the message
@@ -66,9 +70,10 @@ properties:
description: Conversation details
properties:
assignee_id:
- type: integer
+ type:
+ - integer
+ - 'null'
description: ID of the assignee
- nullable: true
unread_count:
type: integer
description: Count of unread messages
diff --git a/swagger/definitions/resource/contact_detail.yml b/swagger/definitions/resource/contact_detail.yml
index 060c91214..705868192 100644
--- a/swagger/definitions/resource/contact_detail.yml
+++ b/swagger/definitions/resource/contact_detail.yml
@@ -11,7 +11,9 @@ properties:
type: string
description: Country of the contact
country_code:
- type: string
+ type:
+ - string
+ - 'null'
description: Country code of the contact
created_at_ip:
type: string
@@ -26,16 +28,18 @@ properties:
type: integer
description: The ID of the contact
identifier:
- type: string
+ type:
+ - string
+ - 'null'
description: The identifier of the contact
- nullable: true
name:
type: string
description: The name of the contact
phone_number:
- type: string
+ type:
+ - string
+ - 'null'
description: The phone number of the contact
- nullable: true
thumbnail:
type: string
description: The thumbnail of the contact
diff --git a/swagger/definitions/resource/contact_inbox.yml b/swagger/definitions/resource/contact_inbox.yml
index 34fd374f2..a5a4eabb9 100644
--- a/swagger/definitions/resource/contact_inbox.yml
+++ b/swagger/definitions/resource/contact_inbox.yml
@@ -22,6 +22,7 @@ properties:
type: string
description: Type of channel
provider:
- type: string
- description: Provider of the inbox
- nullable: true
\ No newline at end of file
+ type:
+ - string
+ - 'null'
+ description: Provider of the inbox
\ No newline at end of file
diff --git a/swagger/definitions/resource/contact_list_item.yml b/swagger/definitions/resource/contact_list_item.yml
index 7765b2265..1be9c6630 100644
--- a/swagger/definitions/resource/contact_list_item.yml
+++ b/swagger/definitions/resource/contact_list_item.yml
@@ -11,7 +11,9 @@ properties:
type: string
description: Country of the contact
country_code:
- type: string
+ type:
+ - string
+ - 'null'
description: Country code of the contact
created_at_ip:
type: string
@@ -21,9 +23,10 @@ properties:
description: Availability status of the contact
enum: ["online", "offline"]
email:
- type: string
+ type:
+ - string
+ - 'null'
description: The email address of the contact
- nullable: true
id:
type: integer
description: The ID of the contact
@@ -31,16 +34,18 @@ properties:
type: string
description: The name of the contact
phone_number:
- type: string
+ type:
+ - string
+ - 'null'
description: The phone number of the contact
- nullable: true
blocked:
type: boolean
description: Whether the contact is blocked
identifier:
- type: string
+ type:
+ - string
+ - 'null'
description: The identifier of the contact
- nullable: true
thumbnail:
type: string
description: The thumbnail of the contact
@@ -48,9 +53,10 @@ properties:
type: object
description: The custom attributes of the contact
last_activity_at:
- type: integer
+ type:
+ - integer
+ - 'null'
description: Timestamp of last activity
- nullable: true
created_at:
type: integer
description: Timestamp when contact was created
diff --git a/swagger/definitions/resource/contact_meta.yml b/swagger/definitions/resource/contact_meta.yml
index f7139b9d2..e718aaa22 100644
--- a/swagger/definitions/resource/contact_meta.yml
+++ b/swagger/definitions/resource/contact_meta.yml
@@ -4,5 +4,7 @@ properties:
type: integer
description: Total number of contacts
current_page:
- type: string
- description: Current page number
\ No newline at end of file
+ type:
+ - string
+ - integer
+ description: Current page number
\ No newline at end of file
diff --git a/swagger/definitions/resource/conversation.yml b/swagger/definitions/resource/conversation.yml
index c1577e693..a0bc7730b 100644
--- a/swagger/definitions/resource/conversation.yml
+++ b/swagger/definitions/resource/conversation.yml
@@ -43,7 +43,9 @@ properties:
type: boolean
description: Whether the conversation is muted
snoozed_until:
- type: number
+ type:
+ - number
+ - 'null'
description: The time at which the conversation will be unmuted
status:
type: string
@@ -56,29 +58,38 @@ properties:
type: number
description: The time at which conversation was updated
timestamp:
- type: string
+ type: number
description: The time at which conversation was created
first_reply_created_at:
- type: number
+ type:
+ - number
+ - 'null'
description: The time at which the first reply was created
unread_count:
type: number
description: The number of unread messages
last_non_activity_message:
- type: object
- $ref: '#/components/schemas/message'
+ oneOf:
+ - $ref: '#/components/schemas/message'
+ - type: 'null'
description: The last non activity message
last_activity_at:
type: number
description: The last activity at of the conversation
priority:
- type: string
+ type:
+ - string
+ - 'null'
description: The priority of the conversation
waiting_since:
- type: number
+ type:
+ - number
+ - 'null'
description: The time at which the conversation was waiting
sla_policy_id:
- type: number
+ type:
+ - number
+ - 'null'
description: The ID of the SLA policy
applied_sla:
type: object
diff --git a/swagger/definitions/resource/conversation_meta.yml b/swagger/definitions/resource/conversation_meta.yml
index 7cffc0fab..a0a4a6200 100644
--- a/swagger/definitions/resource/conversation_meta.yml
+++ b/swagger/definitions/resource/conversation_meta.yml
@@ -45,11 +45,18 @@ properties:
contact:
$ref: '#/components/schemas/contact_detail'
description: Contact details
- agent_last_seen_at:
- type: string
- description: Timestamp when the agent last saw the conversation
+ assignee:
+ allOf:
+ - $ref: '#/components/schemas/agent'
+ description: The agent assigned to the conversation
nullable: true
+ agent_last_seen_at:
+ type:
+ - string
+ - 'null'
+ description: Timestamp when the agent last saw the conversation
assignee_last_seen_at:
- type: string
- description: Timestamp when the assignee last saw the conversation
- nullable: true
\ No newline at end of file
+ type:
+ - string
+ - 'null'
+ description: Timestamp when the assignee last saw the conversation
\ No newline at end of file
diff --git a/swagger/definitions/resource/extension/contact/conversation.yml b/swagger/definitions/resource/extension/contact/conversation.yml
index ef1b0eb75..e58e5d165 100644
--- a/swagger/definitions/resource/extension/contact/conversation.yml
+++ b/swagger/definitions/resource/extension/contact/conversation.yml
@@ -13,7 +13,9 @@ properties:
type: string
description: The availability status of the sender
email:
- type: string
+ type:
+ - string
+ - 'null'
description: The email of the sender
id:
type: number
@@ -22,16 +24,22 @@ properties:
type: string
description: The name of the sender
phone_number:
- type: string
+ type:
+ - string
+ - 'null'
description: The phone number of the sender
blocked:
type: boolean
description: Whether the sender is blocked
identifier:
- type: string
+ type:
+ - string
+ - 'null'
description: The identifier of the sender
thumbnail:
- type: string
+ type:
+ - string
+ - 'null'
description: Avatar URL of the contact
custom_attributes:
type: object
diff --git a/swagger/definitions/resource/inbox.yml b/swagger/definitions/resource/inbox.yml
index 88f5ea288..5ba6b49bb 100644
--- a/swagger/definitions/resource/inbox.yml
+++ b/swagger/definitions/resource/inbox.yml
@@ -28,16 +28,22 @@ properties:
type: string
description: Script used to load the website widget
welcome_title:
- type: string
+ type:
+ - string
+ - 'null'
description: Welcome title to be displayed on the widget
welcome_tagline:
- type: string
+ type:
+ - string
+ - 'null'
description: Welcome tagline to be displayed on the widget
greeting_enabled:
type: boolean
description: The flag which shows whether greeting is enabled
greeting_message:
- type: string
+ type:
+ - string
+ - 'null'
description: A greeting message when the user starts the conversation
channel_id:
type: number
@@ -55,7 +61,9 @@ properties:
type: object
description: Configuration settings for auto assignment
out_of_office_message:
- type: string
+ type:
+ - string
+ - 'null'
description: Message to show when agents are out of office
working_hours:
type: array
@@ -70,16 +78,24 @@ properties:
type: boolean
description: Whether the inbox is closed for the entire day
open_hour:
- type: number
+ type:
+ - number
+ - 'null'
description: Hour when inbox opens (0-23)
open_minutes:
- type: number
+ type:
+ - number
+ - 'null'
description: Minutes of the hour when inbox opens (0-59)
close_hour:
- type: number
+ type:
+ - number
+ - 'null'
description: Hour when inbox closes (0-23)
close_minutes:
- type: number
+ type:
+ - number
+ - 'null'
description: Minutes of the hour when inbox closes (0-59)
open_all_day:
type: boolean
@@ -88,7 +104,9 @@ properties:
type: string
description: Timezone configuration for the inbox
callback_webhook_url:
- type: string
+ type:
+ - string
+ - 'null'
description: Webhook URL for callbacks
allow_messages_after_resolved:
type: boolean
@@ -100,26 +118,38 @@ properties:
type: string
description: Type of sender name to display (e.g., friendly)
business_name:
- type: string
+ type:
+ - string
+ - 'null'
description: Business name associated with the inbox
hmac_mandatory:
type: boolean
description: Whether HMAC verification is mandatory
selected_feature_flags:
- type: object
+ type:
+ - array
+ - 'null'
description: Selected feature flags for the inbox
+ items:
+ type: string
reply_time:
type: string
description: Expected reply time
messaging_service_sid:
- type: string
+ type:
+ - string
+ - 'null'
description: Messaging service SID for SMS providers
phone_number:
- type: string
+ type:
+ - string
+ - 'null'
description: Phone number associated with the inbox
medium:
type: string
description: Medium of communication (e.g., sms, email)
provider:
- type: string
+ type:
+ - string
+ - 'null'
description: Provider of the channel
diff --git a/swagger/definitions/resource/label.yml b/swagger/definitions/resource/label.yml
new file mode 100644
index 000000000..60db5136c
--- /dev/null
+++ b/swagger/definitions/resource/label.yml
@@ -0,0 +1,17 @@
+type: object
+properties:
+ id:
+ type: number
+ description: The ID of the label
+ title:
+ type: string
+ description: The title of the label
+ description:
+ type: string
+ description: The description of the label
+ color:
+ type: string
+ description: Hex color code for the label
+ show_on_sidebar:
+ type: boolean
+ description: Whether the label should appear in the sidebar
diff --git a/swagger/definitions/resource/message.yml b/swagger/definitions/resource/message.yml
index f31936295..a1f598bc8 100644
--- a/swagger/definitions/resource/message.yml
+++ b/swagger/definitions/resource/message.yml
@@ -17,37 +17,49 @@ properties:
description: The ID of the conversation
message_type:
type: integer
- enum: [0, 1, 2]
+ enum: [0, 1, 2, 3]
description: The type of the message
created_at:
type: integer
description: The time at which message was created
updated_at:
- type: integer
+ type:
+ - integer
+ - string
description: The time at which message was updated
private:
type: boolean
description: The flags which shows whether the message is private or not
status:
- type: string
- enum: ["sent", "delivered", "read", "failed"]
+ type:
+ - string
+ - 'null'
+ enum: ["sent", "delivered", "read", "failed", null]
description: The status of the message
source_id:
- type: string
+ type:
+ - string
+ - 'null'
description: The source ID of the message
content_type:
- type: string
- enum: ["text", "input_select", "cards", "form"]
+ type:
+ - string
+ - 'null'
+ enum: ["text", "input_text", "input_textarea", "input_email", "input_select", "cards", "form", "article", "incoming_email", "input_csat", "integrations", "sticker", "voice_call", null]
description: The type of the template message
content_attributes:
type: object
description: The content attributes for each content_type
sender_type:
- type: string
- enum: ["contact", "agent", "agent_bot"]
+ type:
+ - string
+ - 'null'
+ enum: ["Contact", "User", "AgentBot", "Captain::Assistant", null]
description: The type of the sender
sender_id:
- type: number
+ type:
+ - number
+ - 'null'
description: The ID of the sender
external_source_ids:
type: object
@@ -56,16 +68,24 @@ properties:
type: object
description: The additional attributes of the message
processed_message_content:
- type: string
+ type:
+ - string
+ - 'null'
description: The processed message content
sentiment:
- type: object
+ type:
+ - object
+ - 'null'
description: The sentiment of the message
conversation:
- type: object
+ type:
+ - object
+ - 'null'
description: The conversation object
attachment:
- type: object
+ type:
+ - object
+ - 'null'
description: The file object attached to the image
sender:
type: object
diff --git a/swagger/definitions/resource/message_detailed.yml b/swagger/definitions/resource/message_detailed.yml
index 49ff7aa09..9f9e45fc3 100644
--- a/swagger/definitions/resource/message_detailed.yml
+++ b/swagger/definitions/resource/message_detailed.yml
@@ -18,7 +18,7 @@ properties:
description: "The type of the message (0: incoming, 1: outgoing, 2: activity, 3: template)"
content_type:
type: string
- enum: ["text", "input_select", "cards", "form", "input_csat"]
+ enum: ["text", "input_text", "input_textarea", "input_email", "input_select", "cards", "form", "article", "incoming_email", "input_csat", "integrations", "sticker", "voice_call"]
description: The type of the message content
status:
type: string
@@ -29,9 +29,15 @@ properties:
description: The content attributes for each content_type
properties:
in_reply_to:
- type: string
+ type:
+ - string
+ - 'null'
description: ID of the message this is replying to
- nullable: true
+ echo_id:
+ type:
+ - string
+ - 'null'
+ description: The echo ID of the message, used for deduplication
created_at:
type: integer
description: The timestamp when message was created
@@ -39,9 +45,38 @@ properties:
type: boolean
description: The flag which shows whether the message is private or not
source_id:
- type: string
+ type:
+ - string
+ - 'null'
description: The source ID of the message
- nullable: true
sender:
$ref: '#/components/schemas/contact_detail'
- description: The sender of the message (only for incoming messages)
\ No newline at end of file
+ description: The sender of the message (only for incoming messages)
+ attachments:
+ type: array
+ description: The list of attachments associated with the message
+ items:
+ type: object
+ properties:
+ id:
+ type: number
+ description: The ID of the attachment
+ message_id:
+ type: number
+ description: The ID of the message
+ file_type:
+ type: string
+ enum: ["image", "video", "audio", "file", "location", "fallback", "share", "story_mention", "contact", "ig_reel"]
+ description: The type of the attached file
+ account_id:
+ type: number
+ description: The ID of the account
+ data_url:
+ type: string
+ description: The URL of the attached file
+ thumb_url:
+ type: string
+ description: The thumbnail URL of the attached file
+ file_size:
+ type: number
+ description: The size of the attached file in bytes
diff --git a/swagger/definitions/resource/portal_meta.yml b/swagger/definitions/resource/portal_meta.yml
index 64b44fc99..db67cc333 100644
--- a/swagger/definitions/resource/portal_meta.yml
+++ b/swagger/definitions/resource/portal_meta.yml
@@ -4,16 +4,19 @@ properties:
type: integer
description: Total number of articles
archived_articles_count:
- type: integer
- nullable: true
+ type:
+ - integer
+ - 'null'
description: Number of archived articles
published_count:
- type: integer
- nullable: true
+ type:
+ - integer
+ - 'null'
description: Number of published articles
draft_articles_count:
- type: integer
- nullable: true
+ type:
+ - integer
+ - 'null'
description: Number of draft articles
categories_count:
type: integer
diff --git a/swagger/definitions/resource/reporting_event.yml b/swagger/definitions/resource/reporting_event.yml
index 85cf71b8c..cea859db5 100644
--- a/swagger/definitions/resource/reporting_event.yml
+++ b/swagger/definitions/resource/reporting_event.yml
@@ -26,16 +26,19 @@ properties:
type: number
description: ID of the account
conversation_id:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: ID of the conversation
inbox_id:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: ID of the inbox
user_id:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: ID of the user/agent
created_at:
type: string
diff --git a/swagger/definitions/resource/reports/agent_summary.yml b/swagger/definitions/resource/reports/agent_summary.yml
index 47c632ddf..db7e9d66a 100644
--- a/swagger/definitions/resource/reports/agent_summary.yml
+++ b/swagger/definitions/resource/reports/agent_summary.yml
@@ -13,16 +13,19 @@ items:
type: number
description: Number of conversations resolved by the agent during the date range
avg_resolution_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) to resolve conversations. Null if no data available.
avg_first_response_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) for the first response. Null if no data available.
avg_reply_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) between replies. Null if no data available.
example:
- id: 1
diff --git a/swagger/definitions/resource/reports/inbox_summary.yml b/swagger/definitions/resource/reports/inbox_summary.yml
index 9a9adcf6b..badf64328 100644
--- a/swagger/definitions/resource/reports/inbox_summary.yml
+++ b/swagger/definitions/resource/reports/inbox_summary.yml
@@ -13,16 +13,19 @@ items:
type: number
description: Number of conversations resolved in the inbox during the date range
avg_resolution_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) to resolve conversations. Null if no data available.
avg_first_response_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) for the first response. Null if no data available.
avg_reply_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) between replies. Null if no data available.
example:
- id: 1
diff --git a/swagger/definitions/resource/reports/team_summary.yml b/swagger/definitions/resource/reports/team_summary.yml
index 98f5895a9..40ec48265 100644
--- a/swagger/definitions/resource/reports/team_summary.yml
+++ b/swagger/definitions/resource/reports/team_summary.yml
@@ -13,16 +13,19 @@ items:
type: number
description: Number of conversations resolved by the team during the date range
avg_resolution_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) to resolve conversations. Null if no data available.
avg_first_response_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) for the first response. Null if no data available.
avg_reply_time:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
description: Average time (in seconds) between replies. Null if no data available.
example:
- id: 1
diff --git a/swagger/definitions/resource/team.yml b/swagger/definitions/resource/team.yml
index eda41ed3e..d02d70e23 100644
--- a/swagger/definitions/resource/team.yml
+++ b/swagger/definitions/resource/team.yml
@@ -7,7 +7,9 @@ properties:
type: string
description: The name of the team
description:
- type: string
+ type:
+ - string
+ - 'null'
description: The description about the team
allow_auto_assign:
type: boolean
diff --git a/swagger/definitions/resource/user.yml b/swagger/definitions/resource/user.yml
index 329dba12e..50bba19a1 100644
--- a/swagger/definitions/resource/user.yml
+++ b/swagger/definitions/resource/user.yml
@@ -13,17 +13,21 @@ properties:
confirmed:
type: boolean
display_name:
- type: string
- nullable: true
+ type:
+ - string
+ - 'null'
message_signature:
- type: string
- nullable: true
+ type:
+ - string
+ - 'null'
email:
type: string
hmac_identifier:
type: string
inviter_id:
- type: number
+ type:
+ - number
+ - 'null'
name:
type: string
provider:
@@ -38,8 +42,9 @@ properties:
uid:
type: string
type:
- type: string
- nullable: true
+ type:
+ - string
+ - 'null'
custom_attributes:
type: object
description: Available for users who are created through platform APIs and has custom attributes associated.
@@ -55,7 +60,9 @@ properties:
status:
type: string
active_at:
- type: string
+ type:
+ - string
+ - 'null'
format: date-time
role:
type: string
@@ -71,8 +78,10 @@ properties:
auto_offline:
type: boolean
custom_role_id:
- type: number
- nullable: true
+ type:
+ - number
+ - 'null'
custom_role:
- type: object
- nullable: true
+ type:
+ - object
+ - 'null'
diff --git a/swagger/index.yml b/swagger/index.yml
index dd460d111..5c62e350f 100644
--- a/swagger/index.yml
+++ b/swagger/index.yml
@@ -1,4 +1,4 @@
-openapi: '3.0.4'
+openapi: '3.1.0'
info:
title: Chatwoot
description: This is the API documentation for Chatwoot server.
@@ -67,6 +67,8 @@ tags:
description: Communication channels setup
- name: Integrations
description: Third-party integrations
+ - name: Labels
+ description: Account label management APIs
- name: Messages
description: Message management APIs
- name: Profile
@@ -112,6 +114,7 @@ x-tagGroups:
- Custom Filters
- Inboxes
- Integrations
+ - Labels
- Messages
- Profile
- Reports
diff --git a/swagger/paths/application/conversation/messages/index.yml b/swagger/paths/application/conversation/messages/index.yml
index 02693a244..6dd7321f9 100644
--- a/swagger/paths/application/conversation/messages/index.yml
+++ b/swagger/paths/application/conversation/messages/index.yml
@@ -5,6 +5,17 @@ summary: Get messages
security:
- userApiKey: []
description: List all messages of a conversation
+parameters:
+ - name: after
+ in: query
+ schema:
+ type: integer
+ description: Fetch messages after the message with this ID. Returns up to 100 messages in ascending order.
+ - name: before
+ in: query
+ schema:
+ type: integer
+ description: Fetch messages before the message with this ID. Returns up to 20 messages in ascending order.
responses:
'200':
description: Success
@@ -27,10 +38,14 @@ responses:
assignee:
$ref: '#/components/schemas/agent'
agent_last_seen_at:
- type: string
+ type:
+ - string
+ - 'null'
format: date-time
assignee_last_seen_at:
- type: string
+ type:
+ - string
+ - 'null'
format: date-time
payload:
type: array
diff --git a/swagger/paths/application/conversation/update.yml b/swagger/paths/application/conversation/update.yml
index fbe8e668b..45f8887a4 100644
--- a/swagger/paths/application/conversation/update.yml
+++ b/swagger/paths/application/conversation/update.yml
@@ -25,6 +25,10 @@ requestBody:
responses:
'200':
description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/conversation'
'401':
description: Unauthorized
content:
diff --git a/swagger/paths/application/inboxes/index.yml b/swagger/paths/application/inboxes/index.yml
index 89abb6009..3d9f4b4e0 100644
--- a/swagger/paths/application/inboxes/index.yml
+++ b/swagger/paths/application/inboxes/index.yml
@@ -33,3 +33,38 @@ get:
application/json:
schema:
$ref: '#/components/schemas/bad_request_error'
+post:
+ tags:
+ - Inboxes
+ operationId: inboxCreation
+ summary: Create an inbox
+ description: You can create more than one website inbox in each account
+ security:
+ - userApiKey: []
+ parameters:
+ - $ref: '#/components/parameters/account_id'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/inbox_create_payload'
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/inbox'
+ '404':
+ description: Inbox not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/application/inboxes/update.yml b/swagger/paths/application/inboxes/update.yml
index e076dd532..912335861 100644
--- a/swagger/paths/application/inboxes/update.yml
+++ b/swagger/paths/application/inboxes/update.yml
@@ -1,3 +1,38 @@
+get:
+ tags:
+ - Inboxes
+ operationId: GetInbox
+ summary: Get an inbox
+ security:
+ - userApiKey: []
+ description: Get an inbox available in the current account
+ parameters:
+ - $ref: '#/components/parameters/account_id'
+ - name: id
+ in: path
+ schema:
+ type: number
+ description: ID of the inbox
+ required: true
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/inbox'
+ '404':
+ description: Inbox not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
patch:
tags:
- Inboxes
@@ -26,8 +61,6 @@ patch:
content:
application/json:
schema:
- type: object
- description: 'Updated inbox object'
$ref: '#/components/schemas/inbox'
'404':
description: Inbox not found
diff --git a/swagger/paths/application/labels/create.yml b/swagger/paths/application/labels/create.yml
new file mode 100644
index 000000000..70d1128c1
--- /dev/null
+++ b/swagger/paths/application/labels/create.yml
@@ -0,0 +1,26 @@
+tags:
+ - Labels
+operationId: create-a-label
+summary: Create a label
+security:
+ - userApiKey: []
+description: Create a label in the account
+requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/label_create_update_payload'
+responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/label'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/application/labels/delete.yml b/swagger/paths/application/labels/delete.yml
new file mode 100644
index 000000000..85aea9a78
--- /dev/null
+++ b/swagger/paths/application/labels/delete.yml
@@ -0,0 +1,22 @@
+tags:
+ - Labels
+operationId: delete-a-label
+summary: Delete a label
+security:
+ - userApiKey: []
+description: Delete a label from the account
+responses:
+ '200':
+ description: Success
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
+ '404':
+ description: The label does not exist in the account
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/application/labels/index.yml b/swagger/paths/application/labels/index.yml
new file mode 100644
index 000000000..174e2a442
--- /dev/null
+++ b/swagger/paths/application/labels/index.yml
@@ -0,0 +1,26 @@
+tags:
+ - Labels
+operationId: list-all-labels
+summary: List all labels
+security:
+ - userApiKey: []
+description: List all labels available in the current account
+responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ payload:
+ type: array
+ description: Array of labels
+ items:
+ $ref: '#/components/schemas/label'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/application/labels/show.yml b/swagger/paths/application/labels/show.yml
new file mode 100644
index 000000000..3e065a7cd
--- /dev/null
+++ b/swagger/paths/application/labels/show.yml
@@ -0,0 +1,26 @@
+tags:
+ - Labels
+operationId: get-details-of-a-single-label
+summary: Get a label
+security:
+ - userApiKey: []
+description: Get the details of a label in the account
+responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/label'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
+ '404':
+ description: The given label ID does not exist in the account
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/application/labels/update.yml b/swagger/paths/application/labels/update.yml
new file mode 100644
index 000000000..6cdbd94ae
--- /dev/null
+++ b/swagger/paths/application/labels/update.yml
@@ -0,0 +1,26 @@
+tags:
+ - Labels
+operationId: update-a-label
+summary: Update a label
+security:
+ - userApiKey: []
+description: Update a label's attributes
+requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/label_create_update_payload'
+responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/label'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml
index 3f8bab7d9..55a9dd13e 100644
--- a/swagger/paths/index.yml
+++ b/swagger/paths/index.yml
@@ -167,7 +167,7 @@
# ------------ Application API routes ------------#
# Accounts
-/api/v1/accounts/{id}:
+/api/v1/accounts/{account_id}:
parameters:
- $ref: '#/components/parameters/account_id'
get:
@@ -413,10 +413,6 @@
# Inboxes
/api/v1/accounts/{account_id}/inboxes:
$ref: ./application/inboxes/index.yml
-/api/v1/accounts/{account_id}/inboxes/{id}/:
- $ref: ./application/inboxes/show.yml
-/api/v1/accounts/{account_id}/inboxes/:
- $ref: ./application/inboxes/create.yml
/api/v1/accounts/{account_id}/inboxes/{id}:
$ref: ./application/inboxes/update.yml
/api/v1/accounts/{account_id}/inboxes/{id}/agent_bot:
@@ -442,6 +438,30 @@
delete:
$ref: ./application/inboxes/inbox_members/delete.yml
+# Labels
+/api/v1/accounts/{account_id}/labels:
+ parameters:
+ - $ref: '#/components/parameters/account_id'
+ get:
+ $ref: ./application/labels/index.yml
+ post:
+ $ref: ./application/labels/create.yml
+/api/v1/accounts/{account_id}/labels/{id}:
+ parameters:
+ - $ref: '#/components/parameters/account_id'
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: number
+ description: ID of the label
+ get:
+ $ref: ./application/labels/show.yml
+ patch:
+ $ref: ./application/labels/update.yml
+ delete:
+ $ref: ./application/labels/delete.yml
+
# Messages
/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages:
parameters:
diff --git a/swagger/paths/profile/index.yml b/swagger/paths/profile/index.yml
index 17eda92d0..1896fd5f8 100644
--- a/swagger/paths/profile/index.yml
+++ b/swagger/paths/profile/index.yml
@@ -19,3 +19,80 @@ get:
application/json:
schema:
$ref: '#/components/schemas/bad_request_error'
+put:
+ tags:
+ - Profile
+ operationId: updateProfile
+ summary: Update user profile
+ description: Update the user profile details
+ security:
+ - userApiKey: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - profile
+ properties:
+ profile:
+ type: object
+ properties:
+ name:
+ type: string
+ email:
+ type: string
+ display_name:
+ type: string
+ message_signature:
+ type: string
+ phone_number:
+ type: string
+ current_password:
+ type: string
+ password:
+ type: string
+ password_confirmation:
+ type: string
+ ui_settings:
+ type: object
+ multipart/form-data:
+ schema:
+ type: object
+ required:
+ - profile
+ properties:
+ profile:
+ type: object
+ properties:
+ name:
+ type: string
+ email:
+ type: string
+ display_name:
+ type: string
+ message_signature:
+ type: string
+ phone_number:
+ type: string
+ current_password:
+ type: string
+ password:
+ type: string
+ password_confirmation:
+ type: string
+ avatar:
+ type: string
+ format: binary
+ ui_settings:
+ type: object
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/user'
+ '401':
+ description: Unauthorized
diff --git a/swagger/swagger.json b/swagger/swagger.json
index d721affa4..5044585c1 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -1,5 +1,5 @@
{
- "openapi": "3.0.4",
+ "openapi": "3.1.0",
"info": {
"title": "Chatwoot",
"description": "This is the API documentation for Chatwoot server.",
@@ -1476,7 +1476,7 @@
}
}
},
- "/api/v1/accounts/{id}": {
+ "/api/v1/accounts/{account_id}": {
"parameters": [
{
"$ref": "#/components/parameters/account_id"
@@ -4721,7 +4721,14 @@
},
"responses": {
"200": {
- "description": "Success"
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/conversation"
+ }
+ }
+ }
},
"401": {
"description": "Unauthorized",
@@ -5426,70 +5433,7 @@
}
}
}
- }
- },
- "/api/v1/accounts/{account_id}/inboxes/{id}/": {
- "get": {
- "tags": [
- "Inboxes"
- ],
- "operationId": "GetInbox",
- "summary": "Get an inbox",
- "security": [
- {
- "userApiKey": []
- }
- ],
- "description": "Get an inbox available in the current account",
- "parameters": [
- {
- "$ref": "#/components/parameters/account_id"
- },
- {
- "name": "id",
- "in": "path",
- "schema": {
- "type": "number"
- },
- "description": "ID of the inbox",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/inbox"
- }
- }
- }
- },
- "404": {
- "description": "Inbox not found",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/bad_request_error"
- }
- }
- }
- },
- "403": {
- "description": "Access denied",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/bad_request_error"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/accounts/{account_id}/inboxes/": {
+ },
"post": {
"tags": [
"Inboxes"
@@ -5552,6 +5496,65 @@
}
},
"/api/v1/accounts/{account_id}/inboxes/{id}": {
+ "get": {
+ "tags": [
+ "Inboxes"
+ ],
+ "operationId": "GetInbox",
+ "summary": "Get an inbox",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get an inbox available in the current account",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ },
+ {
+ "name": "id",
+ "in": "path",
+ "schema": {
+ "type": "number"
+ },
+ "description": "ID of the inbox",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/inbox"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Inbox not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access denied",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
"patch": {
"tags": [
"Inboxes"
@@ -6098,6 +6101,246 @@
}
}
},
+ "/api/v1/accounts/{account_id}/labels": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "list-all-labels",
+ "summary": "List all labels",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "List all labels available in the current account",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "payload": {
+ "type": "array",
+ "description": "Array of labels",
+ "items": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "create-a-label",
+ "summary": "Create a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Create a label in the account",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label_create_update_payload"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/accounts/{account_id}/labels/{id}": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ },
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "number"
+ },
+ "description": "ID of the label"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "get-details-of-a-single-label",
+ "summary": "Get a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get the details of a label in the account",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "The given label ID does not exist in the account",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "update-a-label",
+ "summary": "Update a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Update a label's attributes",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label_create_update_payload"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "delete-a-label",
+ "summary": "Delete a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Delete a label from the account",
+ "responses": {
+ "200": {
+ "description": "Success"
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "The label does not exist in the account",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages": {
"parameters": [
{
@@ -6119,6 +6362,24 @@
}
],
"description": "List all messages of a conversation",
+ "parameters": [
+ {
+ "name": "after",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ },
+ "description": "Fetch messages after the message with this ID. Returns up to 100 messages in ascending order."
+ },
+ {
+ "name": "before",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ },
+ "description": "Fetch messages before the message with this ID. Returns up to 20 messages in ascending order."
+ }
+ ],
"responses": {
"200": {
"description": "Success",
@@ -6146,11 +6407,17 @@
"$ref": "#/components/schemas/agent"
},
"agent_last_seen_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"assignee_last_seen_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
}
}
@@ -6555,6 +6822,127 @@
}
}
}
+ },
+ "put": {
+ "tags": [
+ "Profile"
+ ],
+ "operationId": "updateProfile",
+ "summary": "Update user profile",
+ "description": "Update the user profile details",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "profile"
+ ],
+ "properties": {
+ "profile": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "message_signature": {
+ "type": "string"
+ },
+ "phone_number": {
+ "type": "string"
+ },
+ "current_password": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "password_confirmation": {
+ "type": "string"
+ },
+ "ui_settings": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ },
+ "multipart/form-data": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "profile"
+ ],
+ "properties": {
+ "profile": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "message_signature": {
+ "type": "string"
+ },
+ "phone_number": {
+ "type": "string"
+ },
+ "current_password": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "password_confirmation": {
+ "type": "string"
+ },
+ "avatar": {
+ "type": "string",
+ "format": "binary"
+ },
+ "ui_settings": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/user"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized"
+ }
+ }
}
},
"/api/v1/accounts/{account_id}/teams": {
@@ -8798,18 +9186,24 @@
"description": "Total number of articles"
},
"archived_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of archived articles"
},
"published_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of published articles"
},
"draft_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of draft articles"
},
"categories_count": {
@@ -9103,7 +9497,10 @@
"description": "Whether the conversation is muted"
},
"snoozed_until": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation will be unmuted"
},
"status": {
@@ -9124,11 +9521,14 @@
"description": "The time at which conversation was updated"
},
"timestamp": {
- "type": "string",
+ "type": "number",
"description": "The time at which conversation was created"
},
"first_reply_created_at": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the first reply was created"
},
"unread_count": {
@@ -9136,22 +9536,39 @@
"description": "The number of unread messages"
},
"last_non_activity_message": {
- "$ref": "#/components/schemas/message"
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/message"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The last non activity message"
},
"last_activity_at": {
"type": "number",
"description": "The last activity at of the conversation"
},
"priority": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The priority of the conversation"
},
"waiting_since": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation was waiting"
},
"sla_policy_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the SLA policy"
},
"applied_sla": {
@@ -9195,7 +9612,8 @@
"enum": [
0,
1,
- 2
+ 2,
+ 3
],
"description": "The type of the message"
},
@@ -9204,7 +9622,10 @@
"description": "The time at which message was created"
},
"updated_at": {
- "type": "integer",
+ "type": [
+ "integer",
+ "string"
+ ],
"description": "The time at which message was updated"
},
"private": {
@@ -9212,26 +9633,46 @@
"description": "The flags which shows whether the message is private or not"
},
"status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"sent",
"delivered",
"read",
- "failed"
+ "failed",
+ null
],
"description": "The status of the message"
},
"source_id": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The source ID of the message"
},
"content_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
- "form"
+ "form",
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call",
+ null
],
"description": "The type of the template message"
},
@@ -9240,16 +9681,24 @@
"description": "The content attributes for each content_type"
},
"sender_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
- "contact",
- "agent",
- "agent_bot"
+ "Contact",
+ "User",
+ "AgentBot",
+ "Captain::Assistant",
+ null
],
"description": "The type of the sender"
},
"sender_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the sender"
},
"external_source_ids": {
@@ -9261,19 +9710,31 @@
"description": "The additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The processed message content"
},
"sentiment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The sentiment of the message"
},
"conversation": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The conversation object"
},
"attachment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The file object attached to the image"
},
"sender": {
@@ -9304,12 +9765,16 @@
"type": "boolean"
},
"display_name": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"message_signature": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"email": {
"type": "string"
@@ -9318,7 +9783,10 @@
"type": "string"
},
"inviter_id": {
- "type": "number"
+ "type": [
+ "number",
+ "null"
+ ]
},
"name": {
"type": "string"
@@ -9343,8 +9811,10 @@
"type": "string"
},
"type": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"custom_attributes": {
"type": "object",
@@ -9365,7 +9835,10 @@
"type": "string"
},
"active_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"role": {
@@ -9391,12 +9864,16 @@
"type": "boolean"
},
"custom_role_id": {
- "type": "number",
- "nullable": true
+ "type": [
+ "number",
+ "null"
+ ]
},
"custom_role": {
- "type": "object",
- "nullable": true
+ "type": [
+ "object",
+ "null"
+ ]
}
}
}
@@ -9454,7 +9931,10 @@
"description": "The thumbnail of the agent"
},
"custom_role_id": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "The custom role id of the agent"
}
}
@@ -9499,11 +9979,17 @@
"description": "Script used to load the website widget"
},
"welcome_title": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome title to be displayed on the widget"
},
"welcome_tagline": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome tagline to be displayed on the widget"
},
"greeting_enabled": {
@@ -9511,7 +9997,10 @@
"description": "The flag which shows whether greeting is enabled"
},
"greeting_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "A greeting message when the user starts the conversation"
},
"channel_id": {
@@ -9535,7 +10024,10 @@
"description": "Configuration settings for auto assignment"
},
"out_of_office_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to show when agents are out of office"
},
"working_hours": {
@@ -9553,19 +10045,31 @@
"description": "Whether the inbox is closed for the entire day"
},
"open_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox opens (0-23)"
},
"open_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox opens (0-59)"
},
"close_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox closes (0-23)"
},
"close_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox closes (0-59)"
},
"open_all_day": {
@@ -9580,7 +10084,10 @@
"description": "Timezone configuration for the inbox"
},
"callback_webhook_url": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Webhook URL for callbacks"
},
"allow_messages_after_resolved": {
@@ -9596,7 +10103,10 @@
"description": "Type of sender name to display (e.g., friendly)"
},
"business_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Business name associated with the inbox"
},
"hmac_mandatory": {
@@ -9604,19 +10114,31 @@
"description": "Whether HMAC verification is mandatory"
},
"selected_feature_flags": {
- "type": "object",
- "description": "Selected feature flags for the inbox"
+ "type": [
+ "array",
+ "null"
+ ],
+ "description": "Selected feature flags for the inbox",
+ "items": {
+ "type": "string"
+ }
},
"reply_time": {
"type": "string",
"description": "Expected reply time"
},
"messaging_service_sid": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Messaging service SID for SMS providers"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Phone number associated with the inbox"
},
"medium": {
@@ -9624,7 +10146,10 @@
"description": "Medium of communication (e.g., sms, email)"
},
"provider": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Provider of the channel"
}
}
@@ -9859,10 +10384,7 @@
"description": "Cache keys for the account"
},
"features": {
- "type": "array",
- "items": {
- "type": "string"
- },
+ "type": "object",
"description": "Enabled features for the account"
},
"settings": {
@@ -9888,19 +10410,31 @@
"description": "Custom attributes of the account",
"properties": {
"plan_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription plan name"
},
"subscribed_quantity": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Subscribed quantity"
},
"subscription_status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription status"
},
"subscription_ends_on": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date",
"description": "Subscription end date"
},
@@ -9946,7 +10480,10 @@
"type": "object",
"properties": {
"latest_chatwoot_version": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Latest version of Chatwoot available",
"example": "3.0.0"
},
@@ -10007,7 +10544,10 @@
"description": "The name of the team"
},
"description": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The description about the team"
},
"allow_auto_assign": {
@@ -10024,6 +10564,31 @@
}
}
},
+ "label": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the label"
+ },
+ "title": {
+ "type": "string",
+ "description": "The title of the label"
+ },
+ "description": {
+ "type": "string",
+ "description": "The description of the label"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar"
+ }
+ }
+ },
"integrations_app": {
"type": "object",
"properties": {
@@ -10150,8 +10715,10 @@
"description": "Version number of the audit log entry"
},
"comment": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Optional comment associated with the audit log entry"
},
"request_uuid": {
@@ -10163,8 +10730,10 @@
"description": "Unix timestamp when the audit log entry was created"
},
"remote_address": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "IP address from which the action was performed"
}
}
@@ -10400,22 +10969,28 @@
"example": "support@example.com"
},
"auto_resolve_after": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"minimum": 10,
"maximum": 1439856,
- "nullable": true,
"description": "Auto resolve conversations after specified minutes",
"example": 1440
},
"auto_resolve_message": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to send when auto resolving",
"example": "This conversation has been automatically resolved due to inactivity"
},
"auto_resolve_ignore_waiting": {
- "type": "boolean",
- "nullable": true,
+ "type": [
+ "boolean",
+ "null"
+ ],
"description": "Whether to ignore waiting conversations for auto resolve",
"example": false
},
@@ -10819,8 +11394,7 @@
"conversation_create_payload": {
"type": "object",
"required": [
- "source_id",
- "inbox_id"
+ "source_id"
],
"properties": {
"source_id": {
@@ -11324,6 +11898,31 @@
}
}
},
+ "label_create_update_payload": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "The label title",
+ "example": "support"
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the label",
+ "example": "Conversations that need support follow-up"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label",
+ "example": "#1f93ff"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar",
+ "example": true
+ }
+ }
+ },
"custom_filter_create_update_payload": {
"type": "object",
"properties": {
@@ -11827,7 +12426,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -11839,7 +12441,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -11847,11 +12452,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -11958,7 +12569,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -11970,7 +12584,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -11978,11 +12595,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -12045,7 +12668,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -12057,7 +12683,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -12065,11 +12694,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -12450,18 +13085,24 @@
"description": "Number of conversations resolved in the inbox during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -12504,18 +13145,24 @@
"description": "Number of conversations resolved by the agent during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -12558,18 +13205,24 @@
"description": "Number of conversations resolved by the team during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -12609,7 +13262,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -12631,18 +13287,22 @@
"description": "The ID of the contact"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"name": {
"type": "string",
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"thumbnail": {
"type": "string",
@@ -12694,10 +13354,18 @@
"type": "string",
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
"form",
- "input_csat"
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call"
],
"description": "The type of the message content"
},
@@ -12716,12 +13384,21 @@
"description": "The content attributes for each content_type",
"properties": {
"in_reply_to": {
- "type": "string",
- "description": "ID of the message this is replying to",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "ID of the message this is replying to"
}
}
},
+ "echo_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The echo ID of the message, used for deduplication"
+ },
"created_at": {
"type": "integer",
"description": "The timestamp when message was created"
@@ -12731,12 +13408,63 @@
"description": "The flag which shows whether the message is private or not"
},
"source_id": {
- "type": "string",
- "description": "The source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The source ID of the message"
},
"sender": {
"$ref": "#/components/schemas/contact_detail"
+ },
+ "attachments": {
+ "type": "array",
+ "description": "The list of attachments associated with the message",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the attachment"
+ },
+ "message_id": {
+ "type": "number",
+ "description": "The ID of the message"
+ },
+ "file_type": {
+ "type": "string",
+ "enum": [
+ "image",
+ "video",
+ "audio",
+ "file",
+ "location",
+ "fallback",
+ "share",
+ "story_mention",
+ "contact",
+ "ig_reel"
+ ],
+ "description": "The type of the attached file"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "The ID of the account"
+ },
+ "data_url": {
+ "type": "string",
+ "description": "The URL of the attached file"
+ },
+ "thumb_url": {
+ "type": "string",
+ "description": "The thumbnail URL of the attached file"
+ },
+ "file_size": {
+ "type": "number",
+ "description": "The size of the attached file in bytes"
+ }
+ }
+ }
}
}
},
@@ -12805,15 +13533,28 @@
"contact": {
"$ref": "#/components/schemas/contact_detail"
},
- "agent_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the agent last saw the conversation",
+ "assignee": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/agent"
+ }
+ ],
+ "description": "The agent assigned to the conversation",
"nullable": true
},
+ "agent_last_seen_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the agent last saw the conversation"
+ },
"assignee_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the assignee last saw the conversation",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the assignee last saw the conversation"
}
}
},
@@ -12840,7 +13581,10 @@
"description": "Total number of contacts"
},
"current_page": {
- "type": "string",
+ "type": [
+ "string",
+ "integer"
+ ],
"description": "Current page number"
}
}
@@ -12876,9 +13620,11 @@
"description": "Type of channel"
},
"provider": {
- "type": "string",
- "description": "Provider of the inbox",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Provider of the inbox"
}
}
}
@@ -12900,7 +13646,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -12918,9 +13667,11 @@
]
},
"email": {
- "type": "string",
- "description": "The email address of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The email address of the contact"
},
"id": {
"type": "integer",
@@ -12931,18 +13682,22 @@
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"blocked": {
"type": "boolean",
"description": "Whether the contact is blocked"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"thumbnail": {
"type": "string",
@@ -12953,9 +13708,11 @@
"description": "The custom attributes of the contact"
},
"last_activity_at": {
- "type": "integer",
- "description": "Timestamp of last activity",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "Timestamp of last activity"
},
"created_at": {
"type": "integer",
@@ -13037,9 +13794,11 @@
"description": "Status of the message"
},
"source_id": {
- "type": "string",
- "description": "Source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Source ID of the message"
},
"content_type": {
"type": "string",
@@ -13050,14 +13809,18 @@
"description": "Attributes of the content"
},
"sender_type": {
- "type": "string",
- "description": "Type of the sender",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Type of the sender"
},
"sender_id": {
- "type": "integer",
- "description": "ID of the sender",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the sender"
},
"external_source_ids": {
"type": "object",
@@ -13068,9 +13831,11 @@
"description": "Additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
- "description": "Processed message content",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Processed message content"
},
"sentiment": {
"type": "object",
@@ -13081,9 +13846,11 @@
"description": "Conversation details",
"properties": {
"assignee_id": {
- "type": "integer",
- "description": "ID of the assignee",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the assignee"
},
"unread_count": {
"type": "integer",
@@ -13169,7 +13936,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -13181,7 +13951,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -13189,11 +13962,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -13279,18 +14058,24 @@
"description": "ID of the account"
},
"conversation_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the conversation"
},
"inbox_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the inbox"
},
"user_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the user/agent"
},
"created_at": {
@@ -13623,6 +14408,10 @@
"name": "Integrations",
"description": "Third-party integrations"
},
+ {
+ "name": "Labels",
+ "description": "Account label management APIs"
+ },
{
"name": "Messages",
"description": "Message management APIs"
@@ -13695,6 +14484,7 @@
"Custom Filters",
"Inboxes",
"Integrations",
+ "Labels",
"Messages",
"Profile",
"Reports",
diff --git a/swagger/tag_groups/application.yml b/swagger/tag_groups/application.yml
index 85d96c5b7..e29cc5d94 100644
--- a/swagger/tag_groups/application.yml
+++ b/swagger/tag_groups/application.yml
@@ -1,4 +1,4 @@
-openapi: '3.0.4'
+openapi: '3.1.0'
info:
title: Chatwoot - Application API
description: Application API endpoints for Chatwoot
@@ -36,6 +36,8 @@ tags:
description: Manage inboxes
- name: Integrations
description: Manage integrations
+ - name: Labels
+ description: Manage account labels
- name: Messages
description: Manage messages
- name: Profile
@@ -62,4 +64,4 @@ components:
type: apiKey
in: header
name: api_access_token
- description: This token can be obtained by visiting the profile page or via rails console. Provides access to endpoints based on the user permissions levels.
\ No newline at end of file
+ description: This token can be obtained by visiting the profile page or via rails console. Provides access to endpoints based on the user permissions levels.
diff --git a/swagger/tag_groups/application_swagger.json b/swagger/tag_groups/application_swagger.json
index 844be0350..85bad5cfb 100644
--- a/swagger/tag_groups/application_swagger.json
+++ b/swagger/tag_groups/application_swagger.json
@@ -1,5 +1,5 @@
{
- "openapi": "3.0.4",
+ "openapi": "3.1.0",
"info": {
"title": "Chatwoot",
"description": "This is the API documentation for Chatwoot server.",
@@ -19,7 +19,7 @@
}
],
"paths": {
- "/api/v1/accounts/{id}": {
+ "/api/v1/accounts/{account_id}": {
"parameters": [
{
"$ref": "#/components/parameters/account_id"
@@ -3264,7 +3264,14 @@
},
"responses": {
"200": {
- "description": "Success"
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/conversation"
+ }
+ }
+ }
},
"401": {
"description": "Unauthorized",
@@ -3969,70 +3976,7 @@
}
}
}
- }
- },
- "/api/v1/accounts/{account_id}/inboxes/{id}/": {
- "get": {
- "tags": [
- "Inboxes"
- ],
- "operationId": "GetInbox",
- "summary": "Get an inbox",
- "security": [
- {
- "userApiKey": []
- }
- ],
- "description": "Get an inbox available in the current account",
- "parameters": [
- {
- "$ref": "#/components/parameters/account_id"
- },
- {
- "name": "id",
- "in": "path",
- "schema": {
- "type": "number"
- },
- "description": "ID of the inbox",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/inbox"
- }
- }
- }
- },
- "404": {
- "description": "Inbox not found",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/bad_request_error"
- }
- }
- }
- },
- "403": {
- "description": "Access denied",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/bad_request_error"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/accounts/{account_id}/inboxes/": {
+ },
"post": {
"tags": [
"Inboxes"
@@ -4095,6 +4039,65 @@
}
},
"/api/v1/accounts/{account_id}/inboxes/{id}": {
+ "get": {
+ "tags": [
+ "Inboxes"
+ ],
+ "operationId": "GetInbox",
+ "summary": "Get an inbox",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get an inbox available in the current account",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ },
+ {
+ "name": "id",
+ "in": "path",
+ "schema": {
+ "type": "number"
+ },
+ "description": "ID of the inbox",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/inbox"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Inbox not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access denied",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
"patch": {
"tags": [
"Inboxes"
@@ -4641,6 +4644,246 @@
}
}
},
+ "/api/v1/accounts/{account_id}/labels": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "list-all-labels",
+ "summary": "List all labels",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "List all labels available in the current account",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "payload": {
+ "type": "array",
+ "description": "Array of labels",
+ "items": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "create-a-label",
+ "summary": "Create a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Create a label in the account",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label_create_update_payload"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/accounts/{account_id}/labels/{id}": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ },
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "number"
+ },
+ "description": "ID of the label"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "get-details-of-a-single-label",
+ "summary": "Get a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get the details of a label in the account",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "The given label ID does not exist in the account",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "update-a-label",
+ "summary": "Update a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Update a label's attributes",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label_create_update_payload"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/label"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Labels"
+ ],
+ "operationId": "delete-a-label",
+ "summary": "Delete a label",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Delete a label from the account",
+ "responses": {
+ "200": {
+ "description": "Success"
+ },
+ "401": {
+ "description": "Unauthorized",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "The label does not exist in the account",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages": {
"parameters": [
{
@@ -4662,6 +4905,24 @@
}
],
"description": "List all messages of a conversation",
+ "parameters": [
+ {
+ "name": "after",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ },
+ "description": "Fetch messages after the message with this ID. Returns up to 100 messages in ascending order."
+ },
+ {
+ "name": "before",
+ "in": "query",
+ "schema": {
+ "type": "integer"
+ },
+ "description": "Fetch messages before the message with this ID. Returns up to 20 messages in ascending order."
+ }
+ ],
"responses": {
"200": {
"description": "Success",
@@ -4689,11 +4950,17 @@
"$ref": "#/components/schemas/agent"
},
"agent_last_seen_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"assignee_last_seen_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
}
}
@@ -5098,6 +5365,127 @@
}
}
}
+ },
+ "put": {
+ "tags": [
+ "Profile"
+ ],
+ "operationId": "updateProfile",
+ "summary": "Update user profile",
+ "description": "Update the user profile details",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "profile"
+ ],
+ "properties": {
+ "profile": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "message_signature": {
+ "type": "string"
+ },
+ "phone_number": {
+ "type": "string"
+ },
+ "current_password": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "password_confirmation": {
+ "type": "string"
+ },
+ "ui_settings": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ },
+ "multipart/form-data": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "profile"
+ ],
+ "properties": {
+ "profile": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "message_signature": {
+ "type": "string"
+ },
+ "phone_number": {
+ "type": "string"
+ },
+ "current_password": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "password_confirmation": {
+ "type": "string"
+ },
+ "avatar": {
+ "type": "string",
+ "format": "binary"
+ },
+ "ui_settings": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/user"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized"
+ }
+ }
}
},
"/api/v1/accounts/{account_id}/teams": {
@@ -7305,18 +7693,24 @@
"description": "Total number of articles"
},
"archived_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of archived articles"
},
"published_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of published articles"
},
"draft_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of draft articles"
},
"categories_count": {
@@ -7610,7 +8004,10 @@
"description": "Whether the conversation is muted"
},
"snoozed_until": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation will be unmuted"
},
"status": {
@@ -7631,11 +8028,14 @@
"description": "The time at which conversation was updated"
},
"timestamp": {
- "type": "string",
+ "type": "number",
"description": "The time at which conversation was created"
},
"first_reply_created_at": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the first reply was created"
},
"unread_count": {
@@ -7643,22 +8043,39 @@
"description": "The number of unread messages"
},
"last_non_activity_message": {
- "$ref": "#/components/schemas/message"
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/message"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The last non activity message"
},
"last_activity_at": {
"type": "number",
"description": "The last activity at of the conversation"
},
"priority": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The priority of the conversation"
},
"waiting_since": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation was waiting"
},
"sla_policy_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the SLA policy"
},
"applied_sla": {
@@ -7702,7 +8119,8 @@
"enum": [
0,
1,
- 2
+ 2,
+ 3
],
"description": "The type of the message"
},
@@ -7711,7 +8129,10 @@
"description": "The time at which message was created"
},
"updated_at": {
- "type": "integer",
+ "type": [
+ "integer",
+ "string"
+ ],
"description": "The time at which message was updated"
},
"private": {
@@ -7719,26 +8140,46 @@
"description": "The flags which shows whether the message is private or not"
},
"status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"sent",
"delivered",
"read",
- "failed"
+ "failed",
+ null
],
"description": "The status of the message"
},
"source_id": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The source ID of the message"
},
"content_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
- "form"
+ "form",
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call",
+ null
],
"description": "The type of the template message"
},
@@ -7747,16 +8188,24 @@
"description": "The content attributes for each content_type"
},
"sender_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
- "contact",
- "agent",
- "agent_bot"
+ "Contact",
+ "User",
+ "AgentBot",
+ "Captain::Assistant",
+ null
],
"description": "The type of the sender"
},
"sender_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the sender"
},
"external_source_ids": {
@@ -7768,19 +8217,31 @@
"description": "The additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The processed message content"
},
"sentiment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The sentiment of the message"
},
"conversation": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The conversation object"
},
"attachment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The file object attached to the image"
},
"sender": {
@@ -7811,12 +8272,16 @@
"type": "boolean"
},
"display_name": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"message_signature": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"email": {
"type": "string"
@@ -7825,7 +8290,10 @@
"type": "string"
},
"inviter_id": {
- "type": "number"
+ "type": [
+ "number",
+ "null"
+ ]
},
"name": {
"type": "string"
@@ -7850,8 +8318,10 @@
"type": "string"
},
"type": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"custom_attributes": {
"type": "object",
@@ -7872,7 +8342,10 @@
"type": "string"
},
"active_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"role": {
@@ -7898,12 +8371,16 @@
"type": "boolean"
},
"custom_role_id": {
- "type": "number",
- "nullable": true
+ "type": [
+ "number",
+ "null"
+ ]
},
"custom_role": {
- "type": "object",
- "nullable": true
+ "type": [
+ "object",
+ "null"
+ ]
}
}
}
@@ -7961,7 +8438,10 @@
"description": "The thumbnail of the agent"
},
"custom_role_id": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "The custom role id of the agent"
}
}
@@ -8006,11 +8486,17 @@
"description": "Script used to load the website widget"
},
"welcome_title": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome title to be displayed on the widget"
},
"welcome_tagline": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome tagline to be displayed on the widget"
},
"greeting_enabled": {
@@ -8018,7 +8504,10 @@
"description": "The flag which shows whether greeting is enabled"
},
"greeting_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "A greeting message when the user starts the conversation"
},
"channel_id": {
@@ -8042,7 +8531,10 @@
"description": "Configuration settings for auto assignment"
},
"out_of_office_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to show when agents are out of office"
},
"working_hours": {
@@ -8060,19 +8552,31 @@
"description": "Whether the inbox is closed for the entire day"
},
"open_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox opens (0-23)"
},
"open_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox opens (0-59)"
},
"close_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox closes (0-23)"
},
"close_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox closes (0-59)"
},
"open_all_day": {
@@ -8087,7 +8591,10 @@
"description": "Timezone configuration for the inbox"
},
"callback_webhook_url": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Webhook URL for callbacks"
},
"allow_messages_after_resolved": {
@@ -8103,7 +8610,10 @@
"description": "Type of sender name to display (e.g., friendly)"
},
"business_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Business name associated with the inbox"
},
"hmac_mandatory": {
@@ -8111,19 +8621,31 @@
"description": "Whether HMAC verification is mandatory"
},
"selected_feature_flags": {
- "type": "object",
- "description": "Selected feature flags for the inbox"
+ "type": [
+ "array",
+ "null"
+ ],
+ "description": "Selected feature flags for the inbox",
+ "items": {
+ "type": "string"
+ }
},
"reply_time": {
"type": "string",
"description": "Expected reply time"
},
"messaging_service_sid": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Messaging service SID for SMS providers"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Phone number associated with the inbox"
},
"medium": {
@@ -8131,7 +8653,10 @@
"description": "Medium of communication (e.g., sms, email)"
},
"provider": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Provider of the channel"
}
}
@@ -8366,10 +8891,7 @@
"description": "Cache keys for the account"
},
"features": {
- "type": "array",
- "items": {
- "type": "string"
- },
+ "type": "object",
"description": "Enabled features for the account"
},
"settings": {
@@ -8395,19 +8917,31 @@
"description": "Custom attributes of the account",
"properties": {
"plan_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription plan name"
},
"subscribed_quantity": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Subscribed quantity"
},
"subscription_status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription status"
},
"subscription_ends_on": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date",
"description": "Subscription end date"
},
@@ -8453,7 +8987,10 @@
"type": "object",
"properties": {
"latest_chatwoot_version": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Latest version of Chatwoot available",
"example": "3.0.0"
},
@@ -8514,7 +9051,10 @@
"description": "The name of the team"
},
"description": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The description about the team"
},
"allow_auto_assign": {
@@ -8531,6 +9071,31 @@
}
}
},
+ "label": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the label"
+ },
+ "title": {
+ "type": "string",
+ "description": "The title of the label"
+ },
+ "description": {
+ "type": "string",
+ "description": "The description of the label"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar"
+ }
+ }
+ },
"integrations_app": {
"type": "object",
"properties": {
@@ -8657,8 +9222,10 @@
"description": "Version number of the audit log entry"
},
"comment": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Optional comment associated with the audit log entry"
},
"request_uuid": {
@@ -8670,8 +9237,10 @@
"description": "Unix timestamp when the audit log entry was created"
},
"remote_address": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "IP address from which the action was performed"
}
}
@@ -8907,22 +9476,28 @@
"example": "support@example.com"
},
"auto_resolve_after": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"minimum": 10,
"maximum": 1439856,
- "nullable": true,
"description": "Auto resolve conversations after specified minutes",
"example": 1440
},
"auto_resolve_message": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to send when auto resolving",
"example": "This conversation has been automatically resolved due to inactivity"
},
"auto_resolve_ignore_waiting": {
- "type": "boolean",
- "nullable": true,
+ "type": [
+ "boolean",
+ "null"
+ ],
"description": "Whether to ignore waiting conversations for auto resolve",
"example": false
},
@@ -9326,8 +9901,7 @@
"conversation_create_payload": {
"type": "object",
"required": [
- "source_id",
- "inbox_id"
+ "source_id"
],
"properties": {
"source_id": {
@@ -9831,6 +10405,31 @@
}
}
},
+ "label_create_update_payload": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "The label title",
+ "example": "support"
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the label",
+ "example": "Conversations that need support follow-up"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label",
+ "example": "#1f93ff"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar",
+ "example": true
+ }
+ }
+ },
"custom_filter_create_update_payload": {
"type": "object",
"properties": {
@@ -10334,7 +10933,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -10346,7 +10948,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -10354,11 +10959,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -10465,7 +11076,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -10477,7 +11091,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -10485,11 +11102,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -10552,7 +11175,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -10564,7 +11190,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -10572,11 +11201,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -10957,18 +11592,24 @@
"description": "Number of conversations resolved in the inbox during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -11011,18 +11652,24 @@
"description": "Number of conversations resolved by the agent during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -11065,18 +11712,24 @@
"description": "Number of conversations resolved by the team during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -11116,7 +11769,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -11138,18 +11794,22 @@
"description": "The ID of the contact"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"name": {
"type": "string",
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"thumbnail": {
"type": "string",
@@ -11201,10 +11861,18 @@
"type": "string",
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
"form",
- "input_csat"
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call"
],
"description": "The type of the message content"
},
@@ -11223,12 +11891,21 @@
"description": "The content attributes for each content_type",
"properties": {
"in_reply_to": {
- "type": "string",
- "description": "ID of the message this is replying to",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "ID of the message this is replying to"
}
}
},
+ "echo_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The echo ID of the message, used for deduplication"
+ },
"created_at": {
"type": "integer",
"description": "The timestamp when message was created"
@@ -11238,12 +11915,63 @@
"description": "The flag which shows whether the message is private or not"
},
"source_id": {
- "type": "string",
- "description": "The source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The source ID of the message"
},
"sender": {
"$ref": "#/components/schemas/contact_detail"
+ },
+ "attachments": {
+ "type": "array",
+ "description": "The list of attachments associated with the message",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the attachment"
+ },
+ "message_id": {
+ "type": "number",
+ "description": "The ID of the message"
+ },
+ "file_type": {
+ "type": "string",
+ "enum": [
+ "image",
+ "video",
+ "audio",
+ "file",
+ "location",
+ "fallback",
+ "share",
+ "story_mention",
+ "contact",
+ "ig_reel"
+ ],
+ "description": "The type of the attached file"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "The ID of the account"
+ },
+ "data_url": {
+ "type": "string",
+ "description": "The URL of the attached file"
+ },
+ "thumb_url": {
+ "type": "string",
+ "description": "The thumbnail URL of the attached file"
+ },
+ "file_size": {
+ "type": "number",
+ "description": "The size of the attached file in bytes"
+ }
+ }
+ }
}
}
},
@@ -11312,15 +12040,28 @@
"contact": {
"$ref": "#/components/schemas/contact_detail"
},
- "agent_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the agent last saw the conversation",
+ "assignee": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/agent"
+ }
+ ],
+ "description": "The agent assigned to the conversation",
"nullable": true
},
+ "agent_last_seen_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the agent last saw the conversation"
+ },
"assignee_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the assignee last saw the conversation",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the assignee last saw the conversation"
}
}
},
@@ -11347,7 +12088,10 @@
"description": "Total number of contacts"
},
"current_page": {
- "type": "string",
+ "type": [
+ "string",
+ "integer"
+ ],
"description": "Current page number"
}
}
@@ -11383,9 +12127,11 @@
"description": "Type of channel"
},
"provider": {
- "type": "string",
- "description": "Provider of the inbox",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Provider of the inbox"
}
}
}
@@ -11407,7 +12153,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -11425,9 +12174,11 @@
]
},
"email": {
- "type": "string",
- "description": "The email address of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The email address of the contact"
},
"id": {
"type": "integer",
@@ -11438,18 +12189,22 @@
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"blocked": {
"type": "boolean",
"description": "Whether the contact is blocked"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"thumbnail": {
"type": "string",
@@ -11460,9 +12215,11 @@
"description": "The custom attributes of the contact"
},
"last_activity_at": {
- "type": "integer",
- "description": "Timestamp of last activity",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "Timestamp of last activity"
},
"created_at": {
"type": "integer",
@@ -11544,9 +12301,11 @@
"description": "Status of the message"
},
"source_id": {
- "type": "string",
- "description": "Source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Source ID of the message"
},
"content_type": {
"type": "string",
@@ -11557,14 +12316,18 @@
"description": "Attributes of the content"
},
"sender_type": {
- "type": "string",
- "description": "Type of the sender",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Type of the sender"
},
"sender_id": {
- "type": "integer",
- "description": "ID of the sender",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the sender"
},
"external_source_ids": {
"type": "object",
@@ -11575,9 +12338,11 @@
"description": "Additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
- "description": "Processed message content",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Processed message content"
},
"sentiment": {
"type": "object",
@@ -11588,9 +12353,11 @@
"description": "Conversation details",
"properties": {
"assignee_id": {
- "type": "integer",
- "description": "ID of the assignee",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the assignee"
},
"unread_count": {
"type": "integer",
@@ -11676,7 +12443,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -11688,7 +12458,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -11696,11 +12469,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -11786,18 +12565,24 @@
"description": "ID of the account"
},
"conversation_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the conversation"
},
"inbox_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the inbox"
},
"user_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the user/agent"
},
"created_at": {
@@ -12114,6 +12899,10 @@
"name": "Integrations",
"description": "Third-party integrations"
},
+ {
+ "name": "Labels",
+ "description": "Account label management APIs"
+ },
{
"name": "Messages",
"description": "Message management APIs"
@@ -12170,6 +12959,7 @@
"Custom Filters",
"Inboxes",
"Integrations",
+ "Labels",
"Messages",
"Profile",
"Reports",
diff --git a/swagger/tag_groups/client.yml b/swagger/tag_groups/client.yml
index fdd177b97..098ff654e 100644
--- a/swagger/tag_groups/client.yml
+++ b/swagger/tag_groups/client.yml
@@ -1,4 +1,4 @@
-openapi: '3.0.4'
+openapi: '3.1.0'
info:
title: Chatwoot - Client API
description: Client API endpoints for Chatwoot
diff --git a/swagger/tag_groups/client_swagger.json b/swagger/tag_groups/client_swagger.json
index ebeb4a9cb..dccfe52cc 100644
--- a/swagger/tag_groups/client_swagger.json
+++ b/swagger/tag_groups/client_swagger.json
@@ -1,5 +1,5 @@
{
- "openapi": "3.0.4",
+ "openapi": "3.1.0",
"info": {
"title": "Chatwoot",
"description": "This is the API documentation for Chatwoot server.",
@@ -958,18 +958,24 @@
"description": "Total number of articles"
},
"archived_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of archived articles"
},
"published_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of published articles"
},
"draft_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of draft articles"
},
"categories_count": {
@@ -1263,7 +1269,10 @@
"description": "Whether the conversation is muted"
},
"snoozed_until": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation will be unmuted"
},
"status": {
@@ -1284,11 +1293,14 @@
"description": "The time at which conversation was updated"
},
"timestamp": {
- "type": "string",
+ "type": "number",
"description": "The time at which conversation was created"
},
"first_reply_created_at": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the first reply was created"
},
"unread_count": {
@@ -1296,22 +1308,39 @@
"description": "The number of unread messages"
},
"last_non_activity_message": {
- "$ref": "#/components/schemas/message"
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/message"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The last non activity message"
},
"last_activity_at": {
"type": "number",
"description": "The last activity at of the conversation"
},
"priority": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The priority of the conversation"
},
"waiting_since": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation was waiting"
},
"sla_policy_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the SLA policy"
},
"applied_sla": {
@@ -1355,7 +1384,8 @@
"enum": [
0,
1,
- 2
+ 2,
+ 3
],
"description": "The type of the message"
},
@@ -1364,7 +1394,10 @@
"description": "The time at which message was created"
},
"updated_at": {
- "type": "integer",
+ "type": [
+ "integer",
+ "string"
+ ],
"description": "The time at which message was updated"
},
"private": {
@@ -1372,26 +1405,46 @@
"description": "The flags which shows whether the message is private or not"
},
"status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"sent",
"delivered",
"read",
- "failed"
+ "failed",
+ null
],
"description": "The status of the message"
},
"source_id": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The source ID of the message"
},
"content_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
- "form"
+ "form",
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call",
+ null
],
"description": "The type of the template message"
},
@@ -1400,16 +1453,24 @@
"description": "The content attributes for each content_type"
},
"sender_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
- "contact",
- "agent",
- "agent_bot"
+ "Contact",
+ "User",
+ "AgentBot",
+ "Captain::Assistant",
+ null
],
"description": "The type of the sender"
},
"sender_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the sender"
},
"external_source_ids": {
@@ -1421,19 +1482,31 @@
"description": "The additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The processed message content"
},
"sentiment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The sentiment of the message"
},
"conversation": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The conversation object"
},
"attachment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The file object attached to the image"
},
"sender": {
@@ -1464,12 +1537,16 @@
"type": "boolean"
},
"display_name": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"message_signature": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"email": {
"type": "string"
@@ -1478,7 +1555,10 @@
"type": "string"
},
"inviter_id": {
- "type": "number"
+ "type": [
+ "number",
+ "null"
+ ]
},
"name": {
"type": "string"
@@ -1503,8 +1583,10 @@
"type": "string"
},
"type": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"custom_attributes": {
"type": "object",
@@ -1525,7 +1607,10 @@
"type": "string"
},
"active_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"role": {
@@ -1551,12 +1636,16 @@
"type": "boolean"
},
"custom_role_id": {
- "type": "number",
- "nullable": true
+ "type": [
+ "number",
+ "null"
+ ]
},
"custom_role": {
- "type": "object",
- "nullable": true
+ "type": [
+ "object",
+ "null"
+ ]
}
}
}
@@ -1614,7 +1703,10 @@
"description": "The thumbnail of the agent"
},
"custom_role_id": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "The custom role id of the agent"
}
}
@@ -1659,11 +1751,17 @@
"description": "Script used to load the website widget"
},
"welcome_title": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome title to be displayed on the widget"
},
"welcome_tagline": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome tagline to be displayed on the widget"
},
"greeting_enabled": {
@@ -1671,7 +1769,10 @@
"description": "The flag which shows whether greeting is enabled"
},
"greeting_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "A greeting message when the user starts the conversation"
},
"channel_id": {
@@ -1695,7 +1796,10 @@
"description": "Configuration settings for auto assignment"
},
"out_of_office_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to show when agents are out of office"
},
"working_hours": {
@@ -1713,19 +1817,31 @@
"description": "Whether the inbox is closed for the entire day"
},
"open_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox opens (0-23)"
},
"open_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox opens (0-59)"
},
"close_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox closes (0-23)"
},
"close_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox closes (0-59)"
},
"open_all_day": {
@@ -1740,7 +1856,10 @@
"description": "Timezone configuration for the inbox"
},
"callback_webhook_url": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Webhook URL for callbacks"
},
"allow_messages_after_resolved": {
@@ -1756,7 +1875,10 @@
"description": "Type of sender name to display (e.g., friendly)"
},
"business_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Business name associated with the inbox"
},
"hmac_mandatory": {
@@ -1764,19 +1886,31 @@
"description": "Whether HMAC verification is mandatory"
},
"selected_feature_flags": {
- "type": "object",
- "description": "Selected feature flags for the inbox"
+ "type": [
+ "array",
+ "null"
+ ],
+ "description": "Selected feature flags for the inbox",
+ "items": {
+ "type": "string"
+ }
},
"reply_time": {
"type": "string",
"description": "Expected reply time"
},
"messaging_service_sid": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Messaging service SID for SMS providers"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Phone number associated with the inbox"
},
"medium": {
@@ -1784,7 +1918,10 @@
"description": "Medium of communication (e.g., sms, email)"
},
"provider": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Provider of the channel"
}
}
@@ -2019,10 +2156,7 @@
"description": "Cache keys for the account"
},
"features": {
- "type": "array",
- "items": {
- "type": "string"
- },
+ "type": "object",
"description": "Enabled features for the account"
},
"settings": {
@@ -2048,19 +2182,31 @@
"description": "Custom attributes of the account",
"properties": {
"plan_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription plan name"
},
"subscribed_quantity": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Subscribed quantity"
},
"subscription_status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription status"
},
"subscription_ends_on": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date",
"description": "Subscription end date"
},
@@ -2106,7 +2252,10 @@
"type": "object",
"properties": {
"latest_chatwoot_version": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Latest version of Chatwoot available",
"example": "3.0.0"
},
@@ -2167,7 +2316,10 @@
"description": "The name of the team"
},
"description": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The description about the team"
},
"allow_auto_assign": {
@@ -2184,6 +2336,31 @@
}
}
},
+ "label": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the label"
+ },
+ "title": {
+ "type": "string",
+ "description": "The title of the label"
+ },
+ "description": {
+ "type": "string",
+ "description": "The description of the label"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar"
+ }
+ }
+ },
"integrations_app": {
"type": "object",
"properties": {
@@ -2310,8 +2487,10 @@
"description": "Version number of the audit log entry"
},
"comment": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Optional comment associated with the audit log entry"
},
"request_uuid": {
@@ -2323,8 +2502,10 @@
"description": "Unix timestamp when the audit log entry was created"
},
"remote_address": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "IP address from which the action was performed"
}
}
@@ -2560,22 +2741,28 @@
"example": "support@example.com"
},
"auto_resolve_after": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"minimum": 10,
"maximum": 1439856,
- "nullable": true,
"description": "Auto resolve conversations after specified minutes",
"example": 1440
},
"auto_resolve_message": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to send when auto resolving",
"example": "This conversation has been automatically resolved due to inactivity"
},
"auto_resolve_ignore_waiting": {
- "type": "boolean",
- "nullable": true,
+ "type": [
+ "boolean",
+ "null"
+ ],
"description": "Whether to ignore waiting conversations for auto resolve",
"example": false
},
@@ -2979,8 +3166,7 @@
"conversation_create_payload": {
"type": "object",
"required": [
- "source_id",
- "inbox_id"
+ "source_id"
],
"properties": {
"source_id": {
@@ -3484,6 +3670,31 @@
}
}
},
+ "label_create_update_payload": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "The label title",
+ "example": "support"
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the label",
+ "example": "Conversations that need support follow-up"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label",
+ "example": "#1f93ff"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar",
+ "example": true
+ }
+ }
+ },
"custom_filter_create_update_payload": {
"type": "object",
"properties": {
@@ -3987,7 +4198,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -3999,7 +4213,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4007,11 +4224,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4118,7 +4341,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -4130,7 +4356,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4138,11 +4367,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4205,7 +4440,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -4217,7 +4455,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4225,11 +4466,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4610,18 +4857,24 @@
"description": "Number of conversations resolved in the inbox during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4664,18 +4917,24 @@
"description": "Number of conversations resolved by the agent during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4718,18 +4977,24 @@
"description": "Number of conversations resolved by the team during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4769,7 +5034,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -4791,18 +5059,22 @@
"description": "The ID of the contact"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"name": {
"type": "string",
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"thumbnail": {
"type": "string",
@@ -4854,10 +5126,18 @@
"type": "string",
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
"form",
- "input_csat"
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call"
],
"description": "The type of the message content"
},
@@ -4876,12 +5156,21 @@
"description": "The content attributes for each content_type",
"properties": {
"in_reply_to": {
- "type": "string",
- "description": "ID of the message this is replying to",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "ID of the message this is replying to"
}
}
},
+ "echo_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The echo ID of the message, used for deduplication"
+ },
"created_at": {
"type": "integer",
"description": "The timestamp when message was created"
@@ -4891,12 +5180,63 @@
"description": "The flag which shows whether the message is private or not"
},
"source_id": {
- "type": "string",
- "description": "The source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The source ID of the message"
},
"sender": {
"$ref": "#/components/schemas/contact_detail"
+ },
+ "attachments": {
+ "type": "array",
+ "description": "The list of attachments associated with the message",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the attachment"
+ },
+ "message_id": {
+ "type": "number",
+ "description": "The ID of the message"
+ },
+ "file_type": {
+ "type": "string",
+ "enum": [
+ "image",
+ "video",
+ "audio",
+ "file",
+ "location",
+ "fallback",
+ "share",
+ "story_mention",
+ "contact",
+ "ig_reel"
+ ],
+ "description": "The type of the attached file"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "The ID of the account"
+ },
+ "data_url": {
+ "type": "string",
+ "description": "The URL of the attached file"
+ },
+ "thumb_url": {
+ "type": "string",
+ "description": "The thumbnail URL of the attached file"
+ },
+ "file_size": {
+ "type": "number",
+ "description": "The size of the attached file in bytes"
+ }
+ }
+ }
}
}
},
@@ -4965,15 +5305,28 @@
"contact": {
"$ref": "#/components/schemas/contact_detail"
},
- "agent_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the agent last saw the conversation",
+ "assignee": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/agent"
+ }
+ ],
+ "description": "The agent assigned to the conversation",
"nullable": true
},
+ "agent_last_seen_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the agent last saw the conversation"
+ },
"assignee_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the assignee last saw the conversation",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the assignee last saw the conversation"
}
}
},
@@ -5000,7 +5353,10 @@
"description": "Total number of contacts"
},
"current_page": {
- "type": "string",
+ "type": [
+ "string",
+ "integer"
+ ],
"description": "Current page number"
}
}
@@ -5036,9 +5392,11 @@
"description": "Type of channel"
},
"provider": {
- "type": "string",
- "description": "Provider of the inbox",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Provider of the inbox"
}
}
}
@@ -5060,7 +5418,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -5078,9 +5439,11 @@
]
},
"email": {
- "type": "string",
- "description": "The email address of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The email address of the contact"
},
"id": {
"type": "integer",
@@ -5091,18 +5454,22 @@
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"blocked": {
"type": "boolean",
"description": "Whether the contact is blocked"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"thumbnail": {
"type": "string",
@@ -5113,9 +5480,11 @@
"description": "The custom attributes of the contact"
},
"last_activity_at": {
- "type": "integer",
- "description": "Timestamp of last activity",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "Timestamp of last activity"
},
"created_at": {
"type": "integer",
@@ -5197,9 +5566,11 @@
"description": "Status of the message"
},
"source_id": {
- "type": "string",
- "description": "Source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Source ID of the message"
},
"content_type": {
"type": "string",
@@ -5210,14 +5581,18 @@
"description": "Attributes of the content"
},
"sender_type": {
- "type": "string",
- "description": "Type of the sender",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Type of the sender"
},
"sender_id": {
- "type": "integer",
- "description": "ID of the sender",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the sender"
},
"external_source_ids": {
"type": "object",
@@ -5228,9 +5603,11 @@
"description": "Additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
- "description": "Processed message content",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Processed message content"
},
"sentiment": {
"type": "object",
@@ -5241,9 +5618,11 @@
"description": "Conversation details",
"properties": {
"assignee_id": {
- "type": "integer",
- "description": "ID of the assignee",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the assignee"
},
"unread_count": {
"type": "integer",
@@ -5329,7 +5708,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -5341,7 +5723,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -5349,11 +5734,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -5439,18 +5830,24 @@
"description": "ID of the account"
},
"conversation_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the conversation"
},
"inbox_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the inbox"
},
"user_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the user/agent"
},
"created_at": {
@@ -5759,6 +6156,7 @@
"Custom Filters",
"Inboxes",
"Integrations",
+ "Labels",
"Messages",
"Profile",
"Reports",
diff --git a/swagger/tag_groups/other_swagger.json b/swagger/tag_groups/other_swagger.json
index 9aa9f5a7a..6c6d88176 100644
--- a/swagger/tag_groups/other_swagger.json
+++ b/swagger/tag_groups/other_swagger.json
@@ -1,5 +1,5 @@
{
- "openapi": "3.0.4",
+ "openapi": "3.1.0",
"info": {
"title": "Chatwoot",
"description": "This is the API documentation for Chatwoot server.",
@@ -373,18 +373,24 @@
"description": "Total number of articles"
},
"archived_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of archived articles"
},
"published_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of published articles"
},
"draft_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of draft articles"
},
"categories_count": {
@@ -678,7 +684,10 @@
"description": "Whether the conversation is muted"
},
"snoozed_until": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation will be unmuted"
},
"status": {
@@ -699,11 +708,14 @@
"description": "The time at which conversation was updated"
},
"timestamp": {
- "type": "string",
+ "type": "number",
"description": "The time at which conversation was created"
},
"first_reply_created_at": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the first reply was created"
},
"unread_count": {
@@ -711,22 +723,39 @@
"description": "The number of unread messages"
},
"last_non_activity_message": {
- "$ref": "#/components/schemas/message"
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/message"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The last non activity message"
},
"last_activity_at": {
"type": "number",
"description": "The last activity at of the conversation"
},
"priority": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The priority of the conversation"
},
"waiting_since": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation was waiting"
},
"sla_policy_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the SLA policy"
},
"applied_sla": {
@@ -770,7 +799,8 @@
"enum": [
0,
1,
- 2
+ 2,
+ 3
],
"description": "The type of the message"
},
@@ -779,7 +809,10 @@
"description": "The time at which message was created"
},
"updated_at": {
- "type": "integer",
+ "type": [
+ "integer",
+ "string"
+ ],
"description": "The time at which message was updated"
},
"private": {
@@ -787,26 +820,46 @@
"description": "The flags which shows whether the message is private or not"
},
"status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"sent",
"delivered",
"read",
- "failed"
+ "failed",
+ null
],
"description": "The status of the message"
},
"source_id": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The source ID of the message"
},
"content_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
- "form"
+ "form",
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call",
+ null
],
"description": "The type of the template message"
},
@@ -815,16 +868,24 @@
"description": "The content attributes for each content_type"
},
"sender_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
- "contact",
- "agent",
- "agent_bot"
+ "Contact",
+ "User",
+ "AgentBot",
+ "Captain::Assistant",
+ null
],
"description": "The type of the sender"
},
"sender_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the sender"
},
"external_source_ids": {
@@ -836,19 +897,31 @@
"description": "The additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The processed message content"
},
"sentiment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The sentiment of the message"
},
"conversation": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The conversation object"
},
"attachment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The file object attached to the image"
},
"sender": {
@@ -879,12 +952,16 @@
"type": "boolean"
},
"display_name": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"message_signature": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"email": {
"type": "string"
@@ -893,7 +970,10 @@
"type": "string"
},
"inviter_id": {
- "type": "number"
+ "type": [
+ "number",
+ "null"
+ ]
},
"name": {
"type": "string"
@@ -918,8 +998,10 @@
"type": "string"
},
"type": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"custom_attributes": {
"type": "object",
@@ -940,7 +1022,10 @@
"type": "string"
},
"active_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"role": {
@@ -966,12 +1051,16 @@
"type": "boolean"
},
"custom_role_id": {
- "type": "number",
- "nullable": true
+ "type": [
+ "number",
+ "null"
+ ]
},
"custom_role": {
- "type": "object",
- "nullable": true
+ "type": [
+ "object",
+ "null"
+ ]
}
}
}
@@ -1029,7 +1118,10 @@
"description": "The thumbnail of the agent"
},
"custom_role_id": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "The custom role id of the agent"
}
}
@@ -1074,11 +1166,17 @@
"description": "Script used to load the website widget"
},
"welcome_title": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome title to be displayed on the widget"
},
"welcome_tagline": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome tagline to be displayed on the widget"
},
"greeting_enabled": {
@@ -1086,7 +1184,10 @@
"description": "The flag which shows whether greeting is enabled"
},
"greeting_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "A greeting message when the user starts the conversation"
},
"channel_id": {
@@ -1110,7 +1211,10 @@
"description": "Configuration settings for auto assignment"
},
"out_of_office_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to show when agents are out of office"
},
"working_hours": {
@@ -1128,19 +1232,31 @@
"description": "Whether the inbox is closed for the entire day"
},
"open_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox opens (0-23)"
},
"open_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox opens (0-59)"
},
"close_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox closes (0-23)"
},
"close_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox closes (0-59)"
},
"open_all_day": {
@@ -1155,7 +1271,10 @@
"description": "Timezone configuration for the inbox"
},
"callback_webhook_url": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Webhook URL for callbacks"
},
"allow_messages_after_resolved": {
@@ -1171,7 +1290,10 @@
"description": "Type of sender name to display (e.g., friendly)"
},
"business_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Business name associated with the inbox"
},
"hmac_mandatory": {
@@ -1179,19 +1301,31 @@
"description": "Whether HMAC verification is mandatory"
},
"selected_feature_flags": {
- "type": "object",
- "description": "Selected feature flags for the inbox"
+ "type": [
+ "array",
+ "null"
+ ],
+ "description": "Selected feature flags for the inbox",
+ "items": {
+ "type": "string"
+ }
},
"reply_time": {
"type": "string",
"description": "Expected reply time"
},
"messaging_service_sid": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Messaging service SID for SMS providers"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Phone number associated with the inbox"
},
"medium": {
@@ -1199,7 +1333,10 @@
"description": "Medium of communication (e.g., sms, email)"
},
"provider": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Provider of the channel"
}
}
@@ -1434,10 +1571,7 @@
"description": "Cache keys for the account"
},
"features": {
- "type": "array",
- "items": {
- "type": "string"
- },
+ "type": "object",
"description": "Enabled features for the account"
},
"settings": {
@@ -1463,19 +1597,31 @@
"description": "Custom attributes of the account",
"properties": {
"plan_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription plan name"
},
"subscribed_quantity": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Subscribed quantity"
},
"subscription_status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription status"
},
"subscription_ends_on": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date",
"description": "Subscription end date"
},
@@ -1521,7 +1667,10 @@
"type": "object",
"properties": {
"latest_chatwoot_version": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Latest version of Chatwoot available",
"example": "3.0.0"
},
@@ -1582,7 +1731,10 @@
"description": "The name of the team"
},
"description": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The description about the team"
},
"allow_auto_assign": {
@@ -1599,6 +1751,31 @@
}
}
},
+ "label": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the label"
+ },
+ "title": {
+ "type": "string",
+ "description": "The title of the label"
+ },
+ "description": {
+ "type": "string",
+ "description": "The description of the label"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar"
+ }
+ }
+ },
"integrations_app": {
"type": "object",
"properties": {
@@ -1725,8 +1902,10 @@
"description": "Version number of the audit log entry"
},
"comment": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Optional comment associated with the audit log entry"
},
"request_uuid": {
@@ -1738,8 +1917,10 @@
"description": "Unix timestamp when the audit log entry was created"
},
"remote_address": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "IP address from which the action was performed"
}
}
@@ -1975,22 +2156,28 @@
"example": "support@example.com"
},
"auto_resolve_after": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"minimum": 10,
"maximum": 1439856,
- "nullable": true,
"description": "Auto resolve conversations after specified minutes",
"example": 1440
},
"auto_resolve_message": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to send when auto resolving",
"example": "This conversation has been automatically resolved due to inactivity"
},
"auto_resolve_ignore_waiting": {
- "type": "boolean",
- "nullable": true,
+ "type": [
+ "boolean",
+ "null"
+ ],
"description": "Whether to ignore waiting conversations for auto resolve",
"example": false
},
@@ -2394,8 +2581,7 @@
"conversation_create_payload": {
"type": "object",
"required": [
- "source_id",
- "inbox_id"
+ "source_id"
],
"properties": {
"source_id": {
@@ -2899,6 +3085,31 @@
}
}
},
+ "label_create_update_payload": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "The label title",
+ "example": "support"
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the label",
+ "example": "Conversations that need support follow-up"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label",
+ "example": "#1f93ff"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar",
+ "example": true
+ }
+ }
+ },
"custom_filter_create_update_payload": {
"type": "object",
"properties": {
@@ -3402,7 +3613,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -3414,7 +3628,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -3422,11 +3639,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -3533,7 +3756,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -3545,7 +3771,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -3553,11 +3782,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -3620,7 +3855,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -3632,7 +3870,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -3640,11 +3881,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4025,18 +4272,24 @@
"description": "Number of conversations resolved in the inbox during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4079,18 +4332,24 @@
"description": "Number of conversations resolved by the agent during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4133,18 +4392,24 @@
"description": "Number of conversations resolved by the team during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4184,7 +4449,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -4206,18 +4474,22 @@
"description": "The ID of the contact"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"name": {
"type": "string",
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"thumbnail": {
"type": "string",
@@ -4269,10 +4541,18 @@
"type": "string",
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
"form",
- "input_csat"
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call"
],
"description": "The type of the message content"
},
@@ -4291,12 +4571,21 @@
"description": "The content attributes for each content_type",
"properties": {
"in_reply_to": {
- "type": "string",
- "description": "ID of the message this is replying to",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "ID of the message this is replying to"
}
}
},
+ "echo_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The echo ID of the message, used for deduplication"
+ },
"created_at": {
"type": "integer",
"description": "The timestamp when message was created"
@@ -4306,12 +4595,63 @@
"description": "The flag which shows whether the message is private or not"
},
"source_id": {
- "type": "string",
- "description": "The source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The source ID of the message"
},
"sender": {
"$ref": "#/components/schemas/contact_detail"
+ },
+ "attachments": {
+ "type": "array",
+ "description": "The list of attachments associated with the message",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the attachment"
+ },
+ "message_id": {
+ "type": "number",
+ "description": "The ID of the message"
+ },
+ "file_type": {
+ "type": "string",
+ "enum": [
+ "image",
+ "video",
+ "audio",
+ "file",
+ "location",
+ "fallback",
+ "share",
+ "story_mention",
+ "contact",
+ "ig_reel"
+ ],
+ "description": "The type of the attached file"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "The ID of the account"
+ },
+ "data_url": {
+ "type": "string",
+ "description": "The URL of the attached file"
+ },
+ "thumb_url": {
+ "type": "string",
+ "description": "The thumbnail URL of the attached file"
+ },
+ "file_size": {
+ "type": "number",
+ "description": "The size of the attached file in bytes"
+ }
+ }
+ }
}
}
},
@@ -4380,15 +4720,28 @@
"contact": {
"$ref": "#/components/schemas/contact_detail"
},
- "agent_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the agent last saw the conversation",
+ "assignee": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/agent"
+ }
+ ],
+ "description": "The agent assigned to the conversation",
"nullable": true
},
+ "agent_last_seen_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the agent last saw the conversation"
+ },
"assignee_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the assignee last saw the conversation",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the assignee last saw the conversation"
}
}
},
@@ -4415,7 +4768,10 @@
"description": "Total number of contacts"
},
"current_page": {
- "type": "string",
+ "type": [
+ "string",
+ "integer"
+ ],
"description": "Current page number"
}
}
@@ -4451,9 +4807,11 @@
"description": "Type of channel"
},
"provider": {
- "type": "string",
- "description": "Provider of the inbox",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Provider of the inbox"
}
}
}
@@ -4475,7 +4833,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -4493,9 +4854,11 @@
]
},
"email": {
- "type": "string",
- "description": "The email address of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The email address of the contact"
},
"id": {
"type": "integer",
@@ -4506,18 +4869,22 @@
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"blocked": {
"type": "boolean",
"description": "Whether the contact is blocked"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"thumbnail": {
"type": "string",
@@ -4528,9 +4895,11 @@
"description": "The custom attributes of the contact"
},
"last_activity_at": {
- "type": "integer",
- "description": "Timestamp of last activity",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "Timestamp of last activity"
},
"created_at": {
"type": "integer",
@@ -4612,9 +4981,11 @@
"description": "Status of the message"
},
"source_id": {
- "type": "string",
- "description": "Source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Source ID of the message"
},
"content_type": {
"type": "string",
@@ -4625,14 +4996,18 @@
"description": "Attributes of the content"
},
"sender_type": {
- "type": "string",
- "description": "Type of the sender",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Type of the sender"
},
"sender_id": {
- "type": "integer",
- "description": "ID of the sender",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the sender"
},
"external_source_ids": {
"type": "object",
@@ -4643,9 +5018,11 @@
"description": "Additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
- "description": "Processed message content",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Processed message content"
},
"sentiment": {
"type": "object",
@@ -4656,9 +5033,11 @@
"description": "Conversation details",
"properties": {
"assignee_id": {
- "type": "integer",
- "description": "ID of the assignee",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the assignee"
},
"unread_count": {
"type": "integer",
@@ -4744,7 +5123,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -4756,7 +5138,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4764,11 +5149,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4854,18 +5245,24 @@
"description": "ID of the account"
},
"conversation_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the conversation"
},
"inbox_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the inbox"
},
"user_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the user/agent"
},
"created_at": {
@@ -5166,6 +5563,7 @@
"Custom Filters",
"Inboxes",
"Integrations",
+ "Labels",
"Messages",
"Profile",
"Reports",
diff --git a/swagger/tag_groups/others.yml b/swagger/tag_groups/others.yml
index 08219959c..682f7ca18 100644
--- a/swagger/tag_groups/others.yml
+++ b/swagger/tag_groups/others.yml
@@ -1,4 +1,4 @@
-openapi: '3.0.4'
+openapi: '3.1.0'
info:
title: Chatwoot - Other APIs
description: Other API endpoints for Chatwoot
diff --git a/swagger/tag_groups/platform.yml b/swagger/tag_groups/platform.yml
index 139dd741e..f465f244f 100644
--- a/swagger/tag_groups/platform.yml
+++ b/swagger/tag_groups/platform.yml
@@ -1,4 +1,4 @@
-openapi: '3.0.4'
+openapi: '3.1.0'
info:
title: Chatwoot - Platform API
description: Platform API endpoints for Chatwoot
diff --git a/swagger/tag_groups/platform_swagger.json b/swagger/tag_groups/platform_swagger.json
index a830a8d56..4be91b8b2 100644
--- a/swagger/tag_groups/platform_swagger.json
+++ b/swagger/tag_groups/platform_swagger.json
@@ -1,5 +1,5 @@
{
- "openapi": "3.0.4",
+ "openapi": "3.1.0",
"info": {
"title": "Chatwoot",
"description": "This is the API documentation for Chatwoot server.",
@@ -1134,18 +1134,24 @@
"description": "Total number of articles"
},
"archived_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of archived articles"
},
"published_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of published articles"
},
"draft_articles_count": {
- "type": "integer",
- "nullable": true,
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "Number of draft articles"
},
"categories_count": {
@@ -1439,7 +1445,10 @@
"description": "Whether the conversation is muted"
},
"snoozed_until": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation will be unmuted"
},
"status": {
@@ -1460,11 +1469,14 @@
"description": "The time at which conversation was updated"
},
"timestamp": {
- "type": "string",
+ "type": "number",
"description": "The time at which conversation was created"
},
"first_reply_created_at": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the first reply was created"
},
"unread_count": {
@@ -1472,22 +1484,39 @@
"description": "The number of unread messages"
},
"last_non_activity_message": {
- "$ref": "#/components/schemas/message"
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/message"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The last non activity message"
},
"last_activity_at": {
"type": "number",
"description": "The last activity at of the conversation"
},
"priority": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The priority of the conversation"
},
"waiting_since": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The time at which the conversation was waiting"
},
"sla_policy_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the SLA policy"
},
"applied_sla": {
@@ -1531,7 +1560,8 @@
"enum": [
0,
1,
- 2
+ 2,
+ 3
],
"description": "The type of the message"
},
@@ -1540,7 +1570,10 @@
"description": "The time at which message was created"
},
"updated_at": {
- "type": "integer",
+ "type": [
+ "integer",
+ "string"
+ ],
"description": "The time at which message was updated"
},
"private": {
@@ -1548,26 +1581,46 @@
"description": "The flags which shows whether the message is private or not"
},
"status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"sent",
"delivered",
"read",
- "failed"
+ "failed",
+ null
],
"description": "The status of the message"
},
"source_id": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The source ID of the message"
},
"content_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
- "form"
+ "form",
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call",
+ null
],
"description": "The type of the template message"
},
@@ -1576,16 +1629,24 @@
"description": "The content attributes for each content_type"
},
"sender_type": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"enum": [
- "contact",
- "agent",
- "agent_bot"
+ "Contact",
+ "User",
+ "AgentBot",
+ "Captain::Assistant",
+ null
],
"description": "The type of the sender"
},
"sender_id": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "The ID of the sender"
},
"external_source_ids": {
@@ -1597,19 +1658,31 @@
"description": "The additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The processed message content"
},
"sentiment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The sentiment of the message"
},
"conversation": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The conversation object"
},
"attachment": {
- "type": "object",
+ "type": [
+ "object",
+ "null"
+ ],
"description": "The file object attached to the image"
},
"sender": {
@@ -1640,12 +1713,16 @@
"type": "boolean"
},
"display_name": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"message_signature": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"email": {
"type": "string"
@@ -1654,7 +1731,10 @@
"type": "string"
},
"inviter_id": {
- "type": "number"
+ "type": [
+ "number",
+ "null"
+ ]
},
"name": {
"type": "string"
@@ -1679,8 +1759,10 @@
"type": "string"
},
"type": {
- "type": "string",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ]
},
"custom_attributes": {
"type": "object",
@@ -1701,7 +1783,10 @@
"type": "string"
},
"active_at": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date-time"
},
"role": {
@@ -1727,12 +1812,16 @@
"type": "boolean"
},
"custom_role_id": {
- "type": "number",
- "nullable": true
+ "type": [
+ "number",
+ "null"
+ ]
},
"custom_role": {
- "type": "object",
- "nullable": true
+ "type": [
+ "object",
+ "null"
+ ]
}
}
}
@@ -1790,7 +1879,10 @@
"description": "The thumbnail of the agent"
},
"custom_role_id": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"description": "The custom role id of the agent"
}
}
@@ -1835,11 +1927,17 @@
"description": "Script used to load the website widget"
},
"welcome_title": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome title to be displayed on the widget"
},
"welcome_tagline": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Welcome tagline to be displayed on the widget"
},
"greeting_enabled": {
@@ -1847,7 +1945,10 @@
"description": "The flag which shows whether greeting is enabled"
},
"greeting_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "A greeting message when the user starts the conversation"
},
"channel_id": {
@@ -1871,7 +1972,10 @@
"description": "Configuration settings for auto assignment"
},
"out_of_office_message": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to show when agents are out of office"
},
"working_hours": {
@@ -1889,19 +1993,31 @@
"description": "Whether the inbox is closed for the entire day"
},
"open_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox opens (0-23)"
},
"open_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox opens (0-59)"
},
"close_hour": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Hour when inbox closes (0-23)"
},
"close_minutes": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Minutes of the hour when inbox closes (0-59)"
},
"open_all_day": {
@@ -1916,7 +2032,10 @@
"description": "Timezone configuration for the inbox"
},
"callback_webhook_url": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Webhook URL for callbacks"
},
"allow_messages_after_resolved": {
@@ -1932,7 +2051,10 @@
"description": "Type of sender name to display (e.g., friendly)"
},
"business_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Business name associated with the inbox"
},
"hmac_mandatory": {
@@ -1940,19 +2062,31 @@
"description": "Whether HMAC verification is mandatory"
},
"selected_feature_flags": {
- "type": "object",
- "description": "Selected feature flags for the inbox"
+ "type": [
+ "array",
+ "null"
+ ],
+ "description": "Selected feature flags for the inbox",
+ "items": {
+ "type": "string"
+ }
},
"reply_time": {
"type": "string",
"description": "Expected reply time"
},
"messaging_service_sid": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Messaging service SID for SMS providers"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Phone number associated with the inbox"
},
"medium": {
@@ -1960,7 +2094,10 @@
"description": "Medium of communication (e.g., sms, email)"
},
"provider": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Provider of the channel"
}
}
@@ -2195,10 +2332,7 @@
"description": "Cache keys for the account"
},
"features": {
- "type": "array",
- "items": {
- "type": "string"
- },
+ "type": "object",
"description": "Enabled features for the account"
},
"settings": {
@@ -2224,19 +2358,31 @@
"description": "Custom attributes of the account",
"properties": {
"plan_name": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription plan name"
},
"subscribed_quantity": {
- "type": "number",
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Subscribed quantity"
},
"subscription_status": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Subscription status"
},
"subscription_ends_on": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"format": "date",
"description": "Subscription end date"
},
@@ -2282,7 +2428,10 @@
"type": "object",
"properties": {
"latest_chatwoot_version": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Latest version of Chatwoot available",
"example": "3.0.0"
},
@@ -2343,7 +2492,10 @@
"description": "The name of the team"
},
"description": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The description about the team"
},
"allow_auto_assign": {
@@ -2360,6 +2512,31 @@
}
}
},
+ "label": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the label"
+ },
+ "title": {
+ "type": "string",
+ "description": "The title of the label"
+ },
+ "description": {
+ "type": "string",
+ "description": "The description of the label"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar"
+ }
+ }
+ },
"integrations_app": {
"type": "object",
"properties": {
@@ -2486,8 +2663,10 @@
"description": "Version number of the audit log entry"
},
"comment": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Optional comment associated with the audit log entry"
},
"request_uuid": {
@@ -2499,8 +2678,10 @@
"description": "Unix timestamp when the audit log entry was created"
},
"remote_address": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "IP address from which the action was performed"
}
}
@@ -2736,22 +2917,28 @@
"example": "support@example.com"
},
"auto_resolve_after": {
- "type": "integer",
+ "type": [
+ "integer",
+ "null"
+ ],
"minimum": 10,
"maximum": 1439856,
- "nullable": true,
"description": "Auto resolve conversations after specified minutes",
"example": 1440
},
"auto_resolve_message": {
- "type": "string",
- "nullable": true,
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Message to send when auto resolving",
"example": "This conversation has been automatically resolved due to inactivity"
},
"auto_resolve_ignore_waiting": {
- "type": "boolean",
- "nullable": true,
+ "type": [
+ "boolean",
+ "null"
+ ],
"description": "Whether to ignore waiting conversations for auto resolve",
"example": false
},
@@ -3155,8 +3342,7 @@
"conversation_create_payload": {
"type": "object",
"required": [
- "source_id",
- "inbox_id"
+ "source_id"
],
"properties": {
"source_id": {
@@ -3660,6 +3846,31 @@
}
}
},
+ "label_create_update_payload": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "The label title",
+ "example": "support"
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the label",
+ "example": "Conversations that need support follow-up"
+ },
+ "color": {
+ "type": "string",
+ "description": "Hex color code for the label",
+ "example": "#1f93ff"
+ },
+ "show_on_sidebar": {
+ "type": "boolean",
+ "description": "Whether the label should appear in the sidebar",
+ "example": true
+ }
+ }
+ },
"custom_filter_create_update_payload": {
"type": "object",
"properties": {
@@ -4163,7 +4374,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -4175,7 +4389,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4183,11 +4400,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4294,7 +4517,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -4306,7 +4532,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4314,11 +4543,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4381,7 +4616,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -4393,7 +4631,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -4401,11 +4642,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -4786,18 +5033,24 @@
"description": "Number of conversations resolved in the inbox during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4840,18 +5093,24 @@
"description": "Number of conversations resolved by the agent during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4894,18 +5153,24 @@
"description": "Number of conversations resolved by the team during the date range"
},
"avg_resolution_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) to resolve conversations. Null if no data available."
},
"avg_first_response_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) for the first response. Null if no data available."
},
"avg_reply_time": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "Average time (in seconds) between replies. Null if no data available."
}
}
@@ -4945,7 +5210,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -4967,18 +5235,22 @@
"description": "The ID of the contact"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"name": {
"type": "string",
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"thumbnail": {
"type": "string",
@@ -5030,10 +5302,18 @@
"type": "string",
"enum": [
"text",
+ "input_text",
+ "input_textarea",
+ "input_email",
"input_select",
"cards",
"form",
- "input_csat"
+ "article",
+ "incoming_email",
+ "input_csat",
+ "integrations",
+ "sticker",
+ "voice_call"
],
"description": "The type of the message content"
},
@@ -5052,12 +5332,21 @@
"description": "The content attributes for each content_type",
"properties": {
"in_reply_to": {
- "type": "string",
- "description": "ID of the message this is replying to",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "ID of the message this is replying to"
}
}
},
+ "echo_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The echo ID of the message, used for deduplication"
+ },
"created_at": {
"type": "integer",
"description": "The timestamp when message was created"
@@ -5067,12 +5356,63 @@
"description": "The flag which shows whether the message is private or not"
},
"source_id": {
- "type": "string",
- "description": "The source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The source ID of the message"
},
"sender": {
"$ref": "#/components/schemas/contact_detail"
+ },
+ "attachments": {
+ "type": "array",
+ "description": "The list of attachments associated with the message",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "The ID of the attachment"
+ },
+ "message_id": {
+ "type": "number",
+ "description": "The ID of the message"
+ },
+ "file_type": {
+ "type": "string",
+ "enum": [
+ "image",
+ "video",
+ "audio",
+ "file",
+ "location",
+ "fallback",
+ "share",
+ "story_mention",
+ "contact",
+ "ig_reel"
+ ],
+ "description": "The type of the attached file"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "The ID of the account"
+ },
+ "data_url": {
+ "type": "string",
+ "description": "The URL of the attached file"
+ },
+ "thumb_url": {
+ "type": "string",
+ "description": "The thumbnail URL of the attached file"
+ },
+ "file_size": {
+ "type": "number",
+ "description": "The size of the attached file in bytes"
+ }
+ }
+ }
}
}
},
@@ -5141,15 +5481,28 @@
"contact": {
"$ref": "#/components/schemas/contact_detail"
},
- "agent_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the agent last saw the conversation",
+ "assignee": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/agent"
+ }
+ ],
+ "description": "The agent assigned to the conversation",
"nullable": true
},
+ "agent_last_seen_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the agent last saw the conversation"
+ },
"assignee_last_seen_at": {
- "type": "string",
- "description": "Timestamp when the assignee last saw the conversation",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Timestamp when the assignee last saw the conversation"
}
}
},
@@ -5176,7 +5529,10 @@
"description": "Total number of contacts"
},
"current_page": {
- "type": "string",
+ "type": [
+ "string",
+ "integer"
+ ],
"description": "Current page number"
}
}
@@ -5212,9 +5568,11 @@
"description": "Type of channel"
},
"provider": {
- "type": "string",
- "description": "Provider of the inbox",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Provider of the inbox"
}
}
}
@@ -5236,7 +5594,10 @@
"description": "Country of the contact"
},
"country_code": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Country code of the contact"
},
"created_at_ip": {
@@ -5254,9 +5615,11 @@
]
},
"email": {
- "type": "string",
- "description": "The email address of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The email address of the contact"
},
"id": {
"type": "integer",
@@ -5267,18 +5630,22 @@
"description": "The name of the contact"
},
"phone_number": {
- "type": "string",
- "description": "The phone number of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The phone number of the contact"
},
"blocked": {
"type": "boolean",
"description": "Whether the contact is blocked"
},
"identifier": {
- "type": "string",
- "description": "The identifier of the contact",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The identifier of the contact"
},
"thumbnail": {
"type": "string",
@@ -5289,9 +5656,11 @@
"description": "The custom attributes of the contact"
},
"last_activity_at": {
- "type": "integer",
- "description": "Timestamp of last activity",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "Timestamp of last activity"
},
"created_at": {
"type": "integer",
@@ -5373,9 +5742,11 @@
"description": "Status of the message"
},
"source_id": {
- "type": "string",
- "description": "Source ID of the message",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Source ID of the message"
},
"content_type": {
"type": "string",
@@ -5386,14 +5757,18 @@
"description": "Attributes of the content"
},
"sender_type": {
- "type": "string",
- "description": "Type of the sender",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Type of the sender"
},
"sender_id": {
- "type": "integer",
- "description": "ID of the sender",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the sender"
},
"external_source_ids": {
"type": "object",
@@ -5404,9 +5779,11 @@
"description": "Additional attributes of the message"
},
"processed_message_content": {
- "type": "string",
- "description": "Processed message content",
- "nullable": true
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Processed message content"
},
"sentiment": {
"type": "object",
@@ -5417,9 +5794,11 @@
"description": "Conversation details",
"properties": {
"assignee_id": {
- "type": "integer",
- "description": "ID of the assignee",
- "nullable": true
+ "type": [
+ "integer",
+ "null"
+ ],
+ "description": "ID of the assignee"
},
"unread_count": {
"type": "integer",
@@ -5505,7 +5884,10 @@
"description": "The availability status of the sender"
},
"email": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The email of the sender"
},
"id": {
@@ -5517,7 +5899,10 @@
"description": "The name of the sender"
},
"phone_number": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The phone number of the sender"
},
"blocked": {
@@ -5525,11 +5910,17 @@
"description": "Whether the sender is blocked"
},
"identifier": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "The identifier of the sender"
},
"thumbnail": {
- "type": "string",
+ "type": [
+ "string",
+ "null"
+ ],
"description": "Avatar URL of the contact"
},
"custom_attributes": {
@@ -5615,18 +6006,24 @@
"description": "ID of the account"
},
"conversation_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the conversation"
},
"inbox_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the inbox"
},
"user_id": {
- "type": "number",
- "nullable": true,
+ "type": [
+ "number",
+ "null"
+ ],
"description": "ID of the user/agent"
},
"created_at": {
@@ -5939,6 +6336,7 @@
"Custom Filters",
"Inboxes",
"Integrations",
+ "Labels",
"Messages",
"Profile",
"Reports",