Merge branch 'develop' into fix-signup-captcha
This commit is contained in:
@@ -22,9 +22,10 @@ class Api::V1::Accounts::ArticlesController < Api::V1::Accounts::BaseController
|
||||
def edit; end
|
||||
|
||||
def create
|
||||
@article = @portal.articles.create!(article_params)
|
||||
params_with_defaults = article_params
|
||||
params_with_defaults[:status] ||= :draft
|
||||
@article = @portal.articles.create!(params_with_defaults)
|
||||
@article.associate_root_article(article_params[:associated_article_id])
|
||||
@article.draft!
|
||||
render json: { error: @article.errors.messages }, status: :unprocessable_entity and return unless @article.valid?
|
||||
end
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class Api::V1::Accounts::WebhooksController < Api::V1::Accounts::BaseController
|
||||
private
|
||||
|
||||
def webhook_params
|
||||
params.require(:webhook).permit(:inbox_id, :url, subscriptions: [])
|
||||
params.require(:webhook).permit(:inbox_id, :name, :url, subscriptions: [])
|
||||
end
|
||||
|
||||
def fetch_webhook
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||
}
|
||||
},
|
||||
"NAME": {
|
||||
"LABEL": "Webhook Name",
|
||||
"PLACEHOLDER": "Enter the name of the webhook"
|
||||
},
|
||||
"END_POINT": {
|
||||
"LABEL": "Webhook URL",
|
||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||
|
||||
+14
@@ -55,6 +55,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
url: this.value.url || '',
|
||||
name: this.value.name || '',
|
||||
subscriptions: this.value.subscriptions || [],
|
||||
supportedWebhookEvents: SUPPORTED_WEBHOOK_EVENTS,
|
||||
};
|
||||
@@ -68,11 +69,15 @@ export default {
|
||||
}
|
||||
);
|
||||
},
|
||||
webhookNameInputPlaceholder() {
|
||||
return this.$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.NAME.PLACEHOLDER');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSubmit() {
|
||||
this.$emit('submit', {
|
||||
url: this.url,
|
||||
name: this.name,
|
||||
subscriptions: this.subscriptions,
|
||||
});
|
||||
},
|
||||
@@ -97,6 +102,15 @@ export default {
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.NAME.LABEL') }}
|
||||
<input
|
||||
v-model="name"
|
||||
type="text"
|
||||
name="name"
|
||||
:placeholder="webhookNameInputPlaceholder"
|
||||
/>
|
||||
</label>
|
||||
<label :class="{ error: v$.url.$error }" class="mb-2">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.SUBSCRIPTIONS.LABEL') }}
|
||||
</label>
|
||||
|
||||
+10
-2
@@ -37,8 +37,16 @@ const subscribedEvents = computed(() => {
|
||||
<template>
|
||||
<tr>
|
||||
<td class="py-4 ltr:pr-4 rtl:pl-4">
|
||||
<div class="font-medium break-words text-n-slate-12">
|
||||
{{ webhook.url }}
|
||||
<div class="flex gap-2 font-medium break-words text-n-slate-12">
|
||||
<template v-if="webhook.name">
|
||||
{{ webhook.name }}
|
||||
<span class="text-n-slate-11">
|
||||
{{ webhook.url }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ webhook.url }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="block mt-1 text-sm text-n-slate-11">
|
||||
<span class="font-medium">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddNameToWebhooks < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :webhooks, :name, :string, null: true
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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:
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user