- {{ webhook.url }}
+
+
+ {{ webhook.name }}
+
+ {{ webhook.url }}
+
+
+
+ {{ webhook.url }}
+
diff --git a/app/models/reporting_event.rb b/app/models/reporting_event.rb
index 2f141786b..f083e32a1 100644
--- a/app/models/reporting_event.rb
+++ b/app/models/reporting_event.rb
@@ -35,4 +35,21 @@ class ReportingEvent < ApplicationRecord
belongs_to :user, optional: true
belongs_to :inbox, optional: true
belongs_to :conversation, optional: true
+
+ # Scopes for filtering
+ scope :filter_by_date_range, lambda { |range|
+ where(created_at: range) if range.present?
+ }
+
+ scope :filter_by_inbox_id, lambda { |inbox_id|
+ where(inbox_id: inbox_id) if inbox_id.present?
+ }
+
+ scope :filter_by_user_id, lambda { |user_id|
+ where(user_id: user_id) if user_id.present?
+ }
+
+ scope :filter_by_name, lambda { |name|
+ where(name: name) if name.present?
+ }
end
diff --git a/app/models/webhook.rb b/app/models/webhook.rb
index 105ffdc91..3fafb4354 100644
--- a/app/models/webhook.rb
+++ b/app/models/webhook.rb
@@ -3,6 +3,7 @@
# Table name: webhooks
#
# id :bigint not null, primary key
+# name :string
# subscriptions :jsonb
# url :string
# webhook_type :integer default("account_type")
diff --git a/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder b/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
index fac8fdcf2..5406cf183 100644
--- a/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
+++ b/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
@@ -1,4 +1,5 @@
json.id webhook.id
+json.name webhook.name
json.url webhook.url
json.account_id webhook.account_id
json.subscriptions webhook.subscriptions
diff --git a/config/routes.rb b/config/routes.rb
index 639c51da7..9c6866e1d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -141,6 +141,7 @@ Rails.application.routes.draw do
post :custom_attributes
get :attachments
get :inbox_assistant
+ get :reporting_events if ChatwootApp.enterprise?
end
end
@@ -186,6 +187,7 @@ Rails.application.routes.draw do
get :download
end
end
+ resources :reporting_events, only: [:index] if ChatwootApp.enterprise?
resources :custom_attribute_definitions, only: [:index, :show, :create, :update, :destroy]
resources :custom_filters, only: [:index, :show, :create, :update, :destroy]
resources :inboxes, only: [:index, :show, :create, :update, :destroy] do
diff --git a/db/migrate/20251010143218_add_name_to_webhooks.rb b/db/migrate/20251010143218_add_name_to_webhooks.rb
new file mode 100644
index 000000000..693ecc35a
--- /dev/null
+++ b/db/migrate/20251010143218_add_name_to_webhooks.rb
@@ -0,0 +1,5 @@
+class AddNameToWebhooks < ActiveRecord::Migration[7.1]
+ def change
+ add_column :webhooks, :name, :string, null: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 45165d5c5..0aeea5cc9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1230,6 +1230,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_22_152158) do
t.datetime "updated_at", null: false
t.integer "webhook_type", default: 0
t.jsonb "subscriptions", default: ["conversation_status_changed", "conversation_updated", "conversation_created", "contact_created", "contact_updated", "message_created", "message_updated", "webwidget_triggered"]
+ t.string "name"
t.index ["account_id", "url"], name: "index_webhooks_on_account_id_and_url", unique: true
end
diff --git a/enterprise/app/controllers/api/v1/accounts/reporting_events_controller.rb b/enterprise/app/controllers/api/v1/accounts/reporting_events_controller.rb
new file mode 100644
index 000000000..eb282b0ee
--- /dev/null
+++ b/enterprise/app/controllers/api/v1/accounts/reporting_events_controller.rb
@@ -0,0 +1,30 @@
+class Api::V1::Accounts::ReportingEventsController < Api::V1::Accounts::EnterpriseAccountsController
+ include DateRangeHelper
+
+ RESULTS_PER_PAGE = 25
+
+ before_action :check_admin_authorization?
+ before_action :set_reporting_events, only: [:index]
+ before_action :set_current_page, only: [:index]
+
+ def index
+ @reporting_events = @reporting_events.page(@current_page).per(RESULTS_PER_PAGE)
+ @total_count = @reporting_events.total_count
+ end
+
+ private
+
+ def set_reporting_events
+ @reporting_events = Current.account.reporting_events
+ .includes(:conversation, :user, :inbox)
+ .filter_by_date_range(range)
+ .filter_by_inbox_id(params[:inbox_id])
+ .filter_by_user_id(params[:user_id])
+ .filter_by_name(params[:name])
+ .order(created_at: :desc)
+ end
+
+ def set_current_page
+ @current_page = (params[:page] || 1).to_i
+ end
+end
diff --git a/enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb b/enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb
index c0ecc2a45..f87c06658 100644
--- a/enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb
+++ b/enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb
@@ -11,6 +11,10 @@ module Enterprise::Api::V1::Accounts::ConversationsController
end
end
+ def reporting_events
+ @reporting_events = @conversation.reporting_events.order(created_at: :asc)
+ end
+
def permitted_update_params
super.merge(params.permit(:sla_policy_id))
end
diff --git a/enterprise/app/views/api/v1/accounts/conversations/reporting_events.json.jbuilder b/enterprise/app/views/api/v1/accounts/conversations/reporting_events.json.jbuilder
new file mode 100644
index 000000000..691296522
--- /dev/null
+++ b/enterprise/app/views/api/v1/accounts/conversations/reporting_events.json.jbuilder
@@ -0,0 +1,3 @@
+json.array! @reporting_events do |reporting_event|
+ json.partial! 'api/v1/models/reporting_event', formats: [:json], reporting_event: reporting_event
+end
diff --git a/enterprise/app/views/api/v1/accounts/reporting_events/index.json.jbuilder b/enterprise/app/views/api/v1/accounts/reporting_events/index.json.jbuilder
new file mode 100644
index 000000000..ae8531955
--- /dev/null
+++ b/enterprise/app/views/api/v1/accounts/reporting_events/index.json.jbuilder
@@ -0,0 +1,11 @@
+json.payload do
+ json.array! @reporting_events do |reporting_event|
+ json.partial! 'api/v1/models/reporting_event', formats: [:json], reporting_event: reporting_event
+ end
+end
+
+json.meta do
+ json.count @total_count
+ json.current_page @current_page
+ json.total_pages @reporting_events.total_pages
+end
diff --git a/enterprise/app/views/api/v1/models/_reporting_event.json.jbuilder b/enterprise/app/views/api/v1/models/_reporting_event.json.jbuilder
new file mode 100644
index 000000000..f8e5f08ba
--- /dev/null
+++ b/enterprise/app/views/api/v1/models/_reporting_event.json.jbuilder
@@ -0,0 +1,12 @@
+json.id reporting_event.id
+json.name reporting_event.name
+json.value reporting_event.value
+json.value_in_business_hours reporting_event.value_in_business_hours
+json.event_start_time reporting_event.event_start_time
+json.event_end_time reporting_event.event_end_time
+json.account_id reporting_event.account_id
+json.inbox_id reporting_event.inbox_id
+json.user_id reporting_event.user_id
+json.conversation_id reporting_event.conversation_id
+json.created_at reporting_event.created_at
+json.updated_at reporting_event.updated_at
diff --git a/spec/controllers/api/v1/accounts/articles_controller_spec.rb b/spec/controllers/api/v1/accounts/articles_controller_spec.rb
index 42fd062dc..e74be76e2 100644
--- a/spec/controllers/api/v1/accounts/articles_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/articles_controller_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'Api::V1::Accounts::Articles', type: :request do
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('MyTitle')
- expect(json_response['payload']['status']).to eql('draft')
+ expect(json_response['payload']['status']).to eql('published')
expect(json_response['payload']['position']).to be(3)
end
@@ -59,10 +59,30 @@ RSpec.describe 'Api::V1::Accounts::Articles', type: :request do
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('MyTitle')
- expect(json_response['payload']['status']).to eql('draft')
+ expect(json_response['payload']['status']).to eql('published')
expect(json_response['payload']['position']).to be(3)
end
+ it 'creates article as draft when status is not provided' do
+ article_params = {
+ article: {
+ category_id: category.id,
+ description: 'test description',
+ title: 'DraftTitle',
+ slug: 'draft-title',
+ content: 'This is my draft content.',
+ author_id: agent.id
+ }
+ }
+ post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
+ params: article_params,
+ headers: admin.create_new_auth_token
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+ expect(json_response['payload']['title']).to eql('DraftTitle')
+ expect(json_response['payload']['status']).to eql('draft')
+ end
+
it 'associate to the root article' do
root_article = create(:article, category: category, slug: 'root-article', portal: portal, account_id: account.id, author_id: agent.id,
associated_article_id: nil)
diff --git a/spec/controllers/api/v1/accounts/webhook_controller_spec.rb b/spec/controllers/api/v1/accounts/webhook_controller_spec.rb
index 3a68d8921..86f4d4e7e 100644
--- a/spec/controllers/api/v1/accounts/webhook_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/webhook_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
RSpec.describe 'Webhooks API', type: :request do
let(:account) { create(:account) }
let(:inbox) { create(:inbox, account: account) }
- let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com') }
+ let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com', name: 'My Webhook') }
let(:administrator) { create(:user, account: account, role: :administrator) }
let(:agent) { create(:user, account: account, role: :agent) }
@@ -49,6 +49,16 @@ RSpec.describe 'Webhooks API', type: :request do
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
end
+ it 'creates webhook with name' do
+ post "/api/v1/accounts/#{account.id}/webhooks",
+ params: { account_id: account.id, inbox_id: inbox.id, url: 'https://hello.com', name: 'My Webhook' },
+ headers: administrator.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:success)
+
+ expect(response.parsed_body['payload']['webhook']['name']).to eql 'My Webhook'
+ end
+
it 'throws error when invalid url provided' do
post "/api/v1/accounts/#{account.id}/webhooks",
params: { account_id: account.id, inbox_id: inbox.id, url: 'javascript:alert(1)' },
@@ -103,11 +113,12 @@ RSpec.describe 'Webhooks API', type: :request do
context 'when it is an authenticated admin user' do
it 'updates webhook' do
put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
- params: { url: 'https://hello.com' },
+ params: { url: 'https://hello.com', name: 'Another Webhook' },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
+ expect(response.parsed_body['payload']['webhook']['name']).to eql 'Another Webhook'
end
end
end
diff --git a/spec/enterprise/controllers/api/v1/accounts/conversations_controller_spec.rb b/spec/enterprise/controllers/api/v1/accounts/conversations_controller_spec.rb
index bbb3f1eb3..472dc959b 100644
--- a/spec/enterprise/controllers/api/v1/accounts/conversations_controller_spec.rb
+++ b/spec/enterprise/controllers/api/v1/accounts/conversations_controller_spec.rb
@@ -102,4 +102,146 @@ RSpec.describe 'Conversations API', type: :request do
end
end
end
+
+ describe 'GET /api/v1/accounts/{account.id}/conversations/:id/reporting_events' do
+ let(:conversation) { create(:conversation, account: account) }
+ let(:inbox) { conversation.inbox }
+ let(:agent) { administrator }
+
+ before do
+ # Create reporting events for this conversation
+ @event1 = create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'first_response',
+ value: 120,
+ created_at: 3.hours.ago)
+
+ @event2 = create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'reply_time',
+ value: 45,
+ created_at: 2.hours.ago)
+
+ @event3 = create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'resolution',
+ value: 300,
+ created_at: 1.hour.ago)
+
+ # Create an event for a different conversation (should not be included)
+ other_conversation = create(:conversation, account: account)
+ create(:reporting_event,
+ account: account,
+ conversation: other_conversation,
+ inbox: other_conversation.inbox,
+ user: agent,
+ name: 'other_conversation_event',
+ value: 60)
+ end
+
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/reporting_events",
+ as: :json
+
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
+ context 'when it is an authenticated user with conversation access' do
+ it 'returns all reporting events for the conversation' do
+ get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/reporting_events",
+ headers: administrator.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ # Should return array directly (no pagination)
+ expect(json_response).to be_an(Array)
+ expect(json_response.size).to eq(3)
+
+ # Check they are sorted by created_at asc (oldest first)
+ expect(json_response.first['name']).to eq('first_response')
+ expect(json_response.last['name']).to eq('resolution')
+
+ # Verify it doesn't include events from other conversations
+ event_names = json_response.map { |e| e['name'] }
+ expect(event_names).not_to include('other_conversation_event')
+ end
+
+ it 'returns empty array when conversation has no reporting events' do
+ conversation_without_events = create(:conversation, account: account)
+
+ get "/api/v1/accounts/#{account.id}/conversations/#{conversation_without_events.display_id}/reporting_events",
+ headers: administrator.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response).to be_an(Array)
+ expect(json_response).to be_empty
+ end
+ end
+
+ context 'when agent has limited access' do
+ let(:limited_agent) { create(:user, account: account, role: :agent) }
+
+ it 'returns unauthorized for unassigned conversation without permission' do
+ get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/reporting_events",
+ headers: limited_agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:unauthorized)
+ end
+
+ it 'returns reporting events when agent is assigned to the conversation' do
+ conversation.update!(assignee: limited_agent)
+ # Also create inbox member for the agent
+ create(:inbox_member, user: limited_agent, inbox: conversation.inbox)
+
+ get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/reporting_events",
+ headers: limited_agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response).to be_an(Array)
+ expect(json_response.size).to eq(3)
+ end
+ end
+
+ context 'when agent has team access' do
+ let(:team_agent) { create(:user, account: account, role: :agent) }
+ let(:team) { create(:team, account: account) }
+
+ before do
+ create(:team_member, team: team, user: team_agent)
+ conversation.update!(team: team)
+ end
+
+ it 'allows accessing conversation reporting events via team membership' do
+ get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/reporting_events",
+ headers: team_agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response).to be_an(Array)
+ expect(json_response.size).to eq(3)
+ end
+ end
+ end
end
diff --git a/spec/enterprise/controllers/api/v1/accounts/reporting_events_controller_spec.rb b/spec/enterprise/controllers/api/v1/accounts/reporting_events_controller_spec.rb
new file mode 100644
index 000000000..6b3ffc4ba
--- /dev/null
+++ b/spec/enterprise/controllers/api/v1/accounts/reporting_events_controller_spec.rb
@@ -0,0 +1,217 @@
+require 'rails_helper'
+
+RSpec.describe 'Enterprise Reporting Events API', type: :request do
+ let!(:account) { create(:account) }
+ let!(:admin) { create(:user, account: account, role: :administrator) }
+ let!(:agent) { create(:user, account: account, role: :agent) }
+ let!(:inbox) { create(:inbox, account: account) }
+ let!(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: agent) }
+
+ describe 'GET /api/v1/accounts/{account.id}/reporting_events' do
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ as: :json
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
+ context 'when it is an authenticated normal agent user' do
+ it 'returns unauthorized' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ headers: agent.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
+ context 'when it is an authenticated admin user' do
+ before do
+ create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'first_response',
+ value: 120,
+ created_at: 3.days.ago)
+ create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'resolution',
+ value: 300,
+ created_at: 2.days.ago)
+ create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'reply_time',
+ value: 45,
+ created_at: 1.day.ago)
+ end
+
+ it 'fetches reporting events with pagination' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ # Check structure and pagination
+ expect(json_response).to have_key('payload')
+ expect(json_response).to have_key('meta')
+ expect(json_response['meta']['count']).to eq(3)
+
+ # Check events are sorted by created_at desc (newest first)
+ events = json_response['payload']
+ expect(events.size).to eq(3)
+ expect(events.first['name']).to eq('reply_time')
+ expect(events.last['name']).to eq('first_response')
+ end
+
+ it 'filters reporting events by date range using since and until' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ params: { since: 2.5.days.ago.to_time.to_i.to_s, until: 1.5.days.ago.to_time.to_i.to_s },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['meta']['count']).to eq(1)
+ expect(json_response['payload'].first['name']).to eq('resolution')
+ end
+
+ it 'filters reporting events by inbox_id' do
+ other_inbox = create(:inbox, account: account)
+ other_conversation = create(:conversation, account: account, inbox: other_inbox)
+ create(:reporting_event,
+ account: account,
+ conversation: other_conversation,
+ inbox: other_inbox,
+ user: agent,
+ name: 'other_inbox_event')
+
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ params: { inbox_id: inbox.id },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['meta']['count']).to eq(3)
+ expect(json_response['payload'].map { |e| e['name'] }).not_to include('other_inbox_event')
+ end
+
+ it 'filters reporting events by user_id (agent)' do
+ other_agent = create(:user, account: account, role: :agent)
+ create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: other_agent,
+ name: 'other_agent_event')
+
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ params: { user_id: agent.id },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['meta']['count']).to eq(3)
+ expect(json_response['payload'].map { |e| e['name'] }).not_to include('other_agent_event')
+ end
+
+ it 'filters reporting events by name' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ params: { name: 'first_response' },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['meta']['count']).to eq(1)
+ expect(json_response['payload'].first['name']).to eq('first_response')
+ end
+
+ it 'supports combining multiple filters' do
+ # Create more test data
+ other_conversation = create(:conversation, account: account, inbox: inbox, assignee: agent)
+ create(:reporting_event,
+ account: account,
+ conversation: other_conversation,
+ inbox: inbox,
+ user: agent,
+ name: 'first_response',
+ value: 90,
+ created_at: 2.days.ago)
+
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ params: {
+ inbox_id: inbox.id,
+ user_id: agent.id,
+ name: 'first_response',
+ since: 4.days.ago.to_time.to_i.to_s,
+ until: Time.zone.now.to_time.to_i.to_s
+ },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['meta']['count']).to eq(2)
+ expect(json_response['payload'].map { |e| e['name'] }).to all(eq('first_response'))
+ end
+
+ context 'with pagination' do
+ before do
+ # Create more events to test pagination
+ 30.times do |i|
+ create(:reporting_event,
+ account: account,
+ conversation: conversation,
+ inbox: inbox,
+ user: agent,
+ name: "event_#{i}",
+ created_at: i.hours.ago)
+ end
+ end
+
+ it 'returns 25 events per page by default' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['payload'].size).to eq(25)
+ expect(json_response['meta']['count']).to eq(33) # 30 + 3 original events
+ expect(json_response['meta']['current_page']).to eq(1)
+ end
+
+ it 'supports page navigation' do
+ get "/api/v1/accounts/#{account.id}/reporting_events",
+ params: { page: 2 },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ json_response = response.parsed_body
+
+ expect(json_response['payload'].size).to eq(8) # Remaining events
+ expect(json_response['meta']['current_page']).to eq(2)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/factories/reporting_events.rb b/spec/factories/reporting_events.rb
index 1db6a87df..aff731ba1 100644
--- a/spec/factories/reporting_events.rb
+++ b/spec/factories/reporting_events.rb
@@ -1,11 +1,13 @@
FactoryBot.define do
factory :reporting_event do
- name { 'MyString' }
+ name { 'first_response' }
value { 1.5 }
value_in_business_hours { 1 }
- account_id { 1 }
- inbox_id { 1 }
- user_id { 1 }
- conversation_id { 1 }
+ account
+ inbox { association :inbox, account: account }
+ user { association :user, account: account }
+ conversation { association :conversation, account: account, inbox: inbox }
+ event_start_time { 2.hours.ago }
+ event_end_time { 1.hour.ago }
end
end
diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb
index 42acc2be6..a4a875c84 100644
--- a/spec/factories/webhooks.rb
+++ b/spec/factories/webhooks.rb
@@ -3,6 +3,7 @@ FactoryBot.define do
account_id { 1 }
inbox_id { 1 }
url { 'https://api.chatwoot.com' }
+ name { 'My Webhook' }
subscriptions do
%w[
conversation_status_changed
diff --git a/swagger/definitions/index.yml b/swagger/definitions/index.yml
index b244deb7f..c24831f84 100644
--- a/swagger/definitions/index.yml
+++ b/swagger/definitions/index.yml
@@ -248,3 +248,9 @@ contact_conversations_response:
$ref: ./resource/contact_conversations_response.yml
contactable_inboxes_response:
$ref: ./resource/contactable_inboxes_response.yml
+reporting_event:
+ $ref: ./resource/reporting_event.yml
+reporting_event_meta:
+ $ref: ./resource/reporting_event_meta.yml
+reporting_events_list_response:
+ $ref: ./resource/reporting_events_list_response.yml
diff --git a/swagger/definitions/request/webhooks/create_update_payload.yml b/swagger/definitions/request/webhooks/create_update_payload.yml
index 2f4a718e4..485d532e4 100644
--- a/swagger/definitions/request/webhooks/create_update_payload.yml
+++ b/swagger/definitions/request/webhooks/create_update_payload.yml
@@ -4,6 +4,9 @@ properties:
type: string
description: The url where the events should be sent
example: https://example.com/webhook
+ name:
+ type: string
+ description: The name of the webhook
subscriptions:
type: array
items:
diff --git a/swagger/definitions/resource/reporting_event.yml b/swagger/definitions/resource/reporting_event.yml
new file mode 100644
index 000000000..85cf71b8c
--- /dev/null
+++ b/swagger/definitions/resource/reporting_event.yml
@@ -0,0 +1,47 @@
+type: object
+properties:
+ id:
+ type: number
+ description: ID of the reporting event
+ name:
+ type: string
+ description: Name of the event (e.g., first_response, resolution, reply_time)
+ value:
+ type: number
+ format: double
+ description: Value of the metric in seconds
+ value_in_business_hours:
+ type: number
+ format: double
+ description: Value of the metric in seconds, calculated only for business hours
+ event_start_time:
+ type: string
+ format: date-time
+ description: The timestamp when the event started
+ event_end_time:
+ type: string
+ format: date-time
+ description: The timestamp when the event ended
+ account_id:
+ type: number
+ description: ID of the account
+ conversation_id:
+ type: number
+ nullable: true
+ description: ID of the conversation
+ inbox_id:
+ type: number
+ nullable: true
+ description: ID of the inbox
+ user_id:
+ type: number
+ nullable: true
+ description: ID of the user/agent
+ created_at:
+ type: string
+ format: date-time
+ description: The timestamp when the reporting event was created
+ updated_at:
+ type: string
+ format: date-time
+ description: The timestamp when the reporting event was last updated
diff --git a/swagger/definitions/resource/reporting_event_meta.yml b/swagger/definitions/resource/reporting_event_meta.yml
new file mode 100644
index 000000000..5d2646c51
--- /dev/null
+++ b/swagger/definitions/resource/reporting_event_meta.yml
@@ -0,0 +1,11 @@
+type: object
+properties:
+ count:
+ type: integer
+ description: Total number of reporting events
+ current_page:
+ type: integer
+ description: Current page number
+ total_pages:
+ type: integer
+ description: Total number of pages
diff --git a/swagger/definitions/resource/reporting_events_list_response.yml b/swagger/definitions/resource/reporting_events_list_response.yml
new file mode 100644
index 000000000..847c5336a
--- /dev/null
+++ b/swagger/definitions/resource/reporting_events_list_response.yml
@@ -0,0 +1,10 @@
+type: object
+properties:
+ meta:
+ $ref: '#/components/schemas/reporting_event_meta'
+ description: Metadata about the reporting events list response
+ payload:
+ type: array
+ items:
+ $ref: '#/components/schemas/reporting_event'
+ description: List of reporting events
diff --git a/swagger/definitions/resource/webhook.yml b/swagger/definitions/resource/webhook.yml
index a9881b8e4..da5cb112a 100644
--- a/swagger/definitions/resource/webhook.yml
+++ b/swagger/definitions/resource/webhook.yml
@@ -6,6 +6,9 @@ properties:
url:
type: string
description: The url to which the events will be send
+ name:
+ type: string
+ description: The name of the webhook
subscriptions:
type: array
items:
diff --git a/swagger/paths/application/conversation/reporting_events.yml b/swagger/paths/application/conversation/reporting_events.yml
new file mode 100644
index 000000000..f19ccbe8b
--- /dev/null
+++ b/swagger/paths/application/conversation/reporting_events.yml
@@ -0,0 +1,29 @@
+tags:
+ - Conversations
+operationId: get-conversation-reporting-events
+summary: Conversation Reporting Events
+security:
+ - userApiKey: []
+description: Get reporting events for a specific conversation. This endpoint returns events such as first response time, resolution time, and other metrics for the conversation, sorted by creation time in ascending order.
+responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/reporting_event'
+ description: Array of reporting events for the conversation
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
+ '404':
+ description: Conversation not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/application/reporting_events/index.yml b/swagger/paths/application/reporting_events/index.yml
new file mode 100644
index 000000000..d55c99545
--- /dev/null
+++ b/swagger/paths/application/reporting_events/index.yml
@@ -0,0 +1,47 @@
+tags:
+ - Reports
+operationId: get-account-reporting-events
+summary: Account Reporting Events
+security:
+ - userApiKey: []
+description: Get paginated reporting events for the account. This endpoint returns reporting events such as first response time, resolution time, and other metrics. Only administrators can access this endpoint. Results are paginated with 25 items per page.
+parameters:
+ - $ref: '#/components/parameters/page'
+ - in: query
+ name: since
+ schema:
+ type: string
+ description: The timestamp from where events should start (Unix timestamp in seconds)
+ - in: query
+ name: until
+ schema:
+ type: string
+ description: The timestamp from where events should stop (Unix timestamp in seconds)
+ - in: query
+ name: inbox_id
+ schema:
+ type: number
+ description: Filter events by inbox ID
+ - in: query
+ name: user_id
+ schema:
+ type: number
+ description: Filter events by user/agent ID
+ - in: query
+ name: name
+ schema:
+ type: string
+ description: Filter events by event name (e.g., first_response, resolution, reply_time)
+responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/reporting_events_list_response'
+ '403':
+ description: Access denied - Only administrators can access this endpoint
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bad_request_error'
diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml
index b2fcb4594..d5126a8d1 100644
--- a/swagger/paths/index.yml
+++ b/swagger/paths/index.yml
@@ -389,6 +389,15 @@
post:
$ref: ./application/conversation/labels/create.yml
+# Conversation Reporting Events
+
+/api/v1/accounts/{account_id}/conversations/{conversation_id}/reporting_events:
+ parameters:
+ - $ref: '#/components/parameters/account_id'
+ - $ref: '#/components/parameters/conversation_id'
+ get:
+ $ref: ./application/conversation/reporting_events.yml
+
# Inboxes
/api/v1/accounts/{account_id}/inboxes:
$ref: ./application/inboxes/index.yml
@@ -535,6 +544,13 @@
### Reports
+# Account Reporting Events
+/api/v1/accounts/{account_id}/reporting_events:
+ parameters:
+ - $ref: '#/components/parameters/account_id'
+ get:
+ $ref: ./application/reporting_events/index.yml
+
# List
/api/v2/accounts/{account_id}/reports:
parameters:
diff --git a/swagger/swagger.json b/swagger/swagger.json
index 9bb9ff95a..8d539c259 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -5140,6 +5140,65 @@
}
}
},
+ "/api/v1/accounts/{account_id}/conversations/{conversation_id}/reporting_events": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ },
+ {
+ "$ref": "#/components/parameters/conversation_id"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Conversations"
+ ],
+ "operationId": "get-conversation-reporting-events",
+ "summary": "Conversation Reporting Events",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get reporting events for a specific conversation. This endpoint returns events such as first response time, resolution time, and other metrics for the conversation, sorted by creation time in ascending order.",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "Array of reporting events for the conversation"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access denied",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Conversation not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v1/accounts/{account_id}/inboxes": {
"get": {
"tags": [
@@ -7311,6 +7370,93 @@
}
}
},
+ "/api/v1/accounts/{account_id}/reporting_events": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Reports"
+ ],
+ "operationId": "get-account-reporting-events",
+ "summary": "Account Reporting Events",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get paginated reporting events for the account. This endpoint returns reporting events such as first response time, resolution time, and other metrics. Only administrators can access this endpoint. Results are paginated with 25 items per page.",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/page"
+ },
+ {
+ "in": "query",
+ "name": "since",
+ "schema": {
+ "type": "string"
+ },
+ "description": "The timestamp from where events should start (Unix timestamp in seconds)"
+ },
+ {
+ "in": "query",
+ "name": "until",
+ "schema": {
+ "type": "string"
+ },
+ "description": "The timestamp from where events should stop (Unix timestamp in seconds)"
+ },
+ {
+ "in": "query",
+ "name": "inbox_id",
+ "schema": {
+ "type": "number"
+ },
+ "description": "Filter events by inbox ID"
+ },
+ {
+ "in": "query",
+ "name": "user_id",
+ "schema": {
+ "type": "number"
+ },
+ "description": "Filter events by user/agent ID"
+ },
+ {
+ "in": "query",
+ "name": "name",
+ "schema": {
+ "type": "string"
+ },
+ "description": "Filter events by event name (e.g., first_response, resolution, reply_time)"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/reporting_events_list_response"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access denied - Only administrators can access this endpoint",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v2/accounts/{account_id}/reports": {
"parameters": [
{
@@ -8981,6 +9127,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -10560,6 +10710,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -12066,6 +12220,100 @@
"description": "List of contactable inboxes for the contact"
}
}
+ },
+ "reporting_event": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "ID of the reporting event"
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the event (e.g., first_response, resolution, reply_time)"
+ },
+ "value": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds"
+ },
+ "value_in_business_hours": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds, calculated only for business hours"
+ },
+ "event_start_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event started"
+ },
+ "event_end_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event ended"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "ID of the account"
+ },
+ "conversation_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the conversation"
+ },
+ "inbox_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the inbox"
+ },
+ "user_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the user/agent"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was created"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was last updated"
+ }
+ }
+ },
+ "reporting_event_meta": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "description": "Total number of reporting events"
+ },
+ "current_page": {
+ "type": "integer",
+ "description": "Current page number"
+ },
+ "total_pages": {
+ "type": "integer",
+ "description": "Total number of pages"
+ }
+ }
+ },
+ "reporting_events_list_response": {
+ "type": "object",
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/reporting_event_meta"
+ },
+ "payload": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "List of reporting events"
+ }
+ }
}
},
"parameters": {
diff --git a/swagger/tag_groups/application_swagger.json b/swagger/tag_groups/application_swagger.json
index 600df4597..2fd0cbdee 100644
--- a/swagger/tag_groups/application_swagger.json
+++ b/swagger/tag_groups/application_swagger.json
@@ -3683,6 +3683,65 @@
}
}
},
+ "/api/v1/accounts/{account_id}/conversations/{conversation_id}/reporting_events": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ },
+ {
+ "$ref": "#/components/parameters/conversation_id"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Conversations"
+ ],
+ "operationId": "get-conversation-reporting-events",
+ "summary": "Conversation Reporting Events",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get reporting events for a specific conversation. This endpoint returns events such as first response time, resolution time, and other metrics for the conversation, sorted by creation time in ascending order.",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "Array of reporting events for the conversation"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access denied",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Conversation not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v1/accounts/{account_id}/inboxes": {
"get": {
"tags": [
@@ -5854,6 +5913,93 @@
}
}
},
+ "/api/v1/accounts/{account_id}/reporting_events": {
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/account_id"
+ }
+ ],
+ "get": {
+ "tags": [
+ "Reports"
+ ],
+ "operationId": "get-account-reporting-events",
+ "summary": "Account Reporting Events",
+ "security": [
+ {
+ "userApiKey": []
+ }
+ ],
+ "description": "Get paginated reporting events for the account. This endpoint returns reporting events such as first response time, resolution time, and other metrics. Only administrators can access this endpoint. Results are paginated with 25 items per page.",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/page"
+ },
+ {
+ "in": "query",
+ "name": "since",
+ "schema": {
+ "type": "string"
+ },
+ "description": "The timestamp from where events should start (Unix timestamp in seconds)"
+ },
+ {
+ "in": "query",
+ "name": "until",
+ "schema": {
+ "type": "string"
+ },
+ "description": "The timestamp from where events should stop (Unix timestamp in seconds)"
+ },
+ {
+ "in": "query",
+ "name": "inbox_id",
+ "schema": {
+ "type": "number"
+ },
+ "description": "Filter events by inbox ID"
+ },
+ {
+ "in": "query",
+ "name": "user_id",
+ "schema": {
+ "type": "number"
+ },
+ "description": "Filter events by user/agent ID"
+ },
+ {
+ "in": "query",
+ "name": "name",
+ "schema": {
+ "type": "string"
+ },
+ "description": "Filter events by event name (e.g., first_response, resolution, reply_time)"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/reporting_events_list_response"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access denied - Only administrators can access this endpoint",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bad_request_error"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v2/accounts/{account_id}/reports": {
"parameters": [
{
@@ -7488,6 +7634,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -9067,6 +9217,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -10573,6 +10727,100 @@
"description": "List of contactable inboxes for the contact"
}
}
+ },
+ "reporting_event": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "ID of the reporting event"
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the event (e.g., first_response, resolution, reply_time)"
+ },
+ "value": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds"
+ },
+ "value_in_business_hours": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds, calculated only for business hours"
+ },
+ "event_start_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event started"
+ },
+ "event_end_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event ended"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "ID of the account"
+ },
+ "conversation_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the conversation"
+ },
+ "inbox_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the inbox"
+ },
+ "user_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the user/agent"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was created"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was last updated"
+ }
+ }
+ },
+ "reporting_event_meta": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "description": "Total number of reporting events"
+ },
+ "current_page": {
+ "type": "integer",
+ "description": "Current page number"
+ },
+ "total_pages": {
+ "type": "integer",
+ "description": "Total number of pages"
+ }
+ }
+ },
+ "reporting_events_list_response": {
+ "type": "object",
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/reporting_event_meta"
+ },
+ "payload": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "List of reporting events"
+ }
+ }
}
},
"parameters": {
diff --git a/swagger/tag_groups/client_swagger.json b/swagger/tag_groups/client_swagger.json
index 16c1d5bc7..cf356e609 100644
--- a/swagger/tag_groups/client_swagger.json
+++ b/swagger/tag_groups/client_swagger.json
@@ -1934,6 +1934,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -3513,6 +3517,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -5019,6 +5027,100 @@
"description": "List of contactable inboxes for the contact"
}
}
+ },
+ "reporting_event": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "ID of the reporting event"
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the event (e.g., first_response, resolution, reply_time)"
+ },
+ "value": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds"
+ },
+ "value_in_business_hours": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds, calculated only for business hours"
+ },
+ "event_start_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event started"
+ },
+ "event_end_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event ended"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "ID of the account"
+ },
+ "conversation_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the conversation"
+ },
+ "inbox_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the inbox"
+ },
+ "user_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the user/agent"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was created"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was last updated"
+ }
+ }
+ },
+ "reporting_event_meta": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "description": "Total number of reporting events"
+ },
+ "current_page": {
+ "type": "integer",
+ "description": "Current page number"
+ },
+ "total_pages": {
+ "type": "integer",
+ "description": "Total number of pages"
+ }
+ }
+ },
+ "reporting_events_list_response": {
+ "type": "object",
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/reporting_event_meta"
+ },
+ "payload": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "List of reporting events"
+ }
+ }
}
},
"parameters": {
diff --git a/swagger/tag_groups/other_swagger.json b/swagger/tag_groups/other_swagger.json
index c8a5294d3..ed1073d0b 100644
--- a/swagger/tag_groups/other_swagger.json
+++ b/swagger/tag_groups/other_swagger.json
@@ -1349,6 +1349,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -2928,6 +2932,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -4434,6 +4442,100 @@
"description": "List of contactable inboxes for the contact"
}
}
+ },
+ "reporting_event": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "ID of the reporting event"
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the event (e.g., first_response, resolution, reply_time)"
+ },
+ "value": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds"
+ },
+ "value_in_business_hours": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds, calculated only for business hours"
+ },
+ "event_start_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event started"
+ },
+ "event_end_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event ended"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "ID of the account"
+ },
+ "conversation_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the conversation"
+ },
+ "inbox_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the inbox"
+ },
+ "user_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the user/agent"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was created"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was last updated"
+ }
+ }
+ },
+ "reporting_event_meta": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "description": "Total number of reporting events"
+ },
+ "current_page": {
+ "type": "integer",
+ "description": "Current page number"
+ },
+ "total_pages": {
+ "type": "integer",
+ "description": "Total number of pages"
+ }
+ }
+ },
+ "reporting_events_list_response": {
+ "type": "object",
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/reporting_event_meta"
+ },
+ "payload": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "List of reporting events"
+ }
+ }
}
},
"parameters": {
diff --git a/swagger/tag_groups/platform_swagger.json b/swagger/tag_groups/platform_swagger.json
index f816b8c94..1bf31a212 100644
--- a/swagger/tag_groups/platform_swagger.json
+++ b/swagger/tag_groups/platform_swagger.json
@@ -2110,6 +2110,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -3689,6 +3693,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -5195,6 +5203,100 @@
"description": "List of contactable inboxes for the contact"
}
}
+ },
+ "reporting_event": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number",
+ "description": "ID of the reporting event"
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the event (e.g., first_response, resolution, reply_time)"
+ },
+ "value": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds"
+ },
+ "value_in_business_hours": {
+ "type": "number",
+ "format": "double",
+ "description": "Value of the metric in seconds, calculated only for business hours"
+ },
+ "event_start_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event started"
+ },
+ "event_end_time": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the event ended"
+ },
+ "account_id": {
+ "type": "number",
+ "description": "ID of the account"
+ },
+ "conversation_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the conversation"
+ },
+ "inbox_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the inbox"
+ },
+ "user_id": {
+ "type": "number",
+ "nullable": true,
+ "description": "ID of the user/agent"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was created"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The timestamp when the reporting event was last updated"
+ }
+ }
+ },
+ "reporting_event_meta": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "description": "Total number of reporting events"
+ },
+ "current_page": {
+ "type": "integer",
+ "description": "Current page number"
+ },
+ "total_pages": {
+ "type": "integer",
+ "description": "Total number of pages"
+ }
+ }
+ },
+ "reporting_events_list_response": {
+ "type": "object",
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/reporting_event_meta"
+ },
+ "payload": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/reporting_event"
+ },
+ "description": "List of reporting events"
+ }
+ }
}
},
"parameters": {