feat: validate OpenAPI spec using Skooma (#13623)

Adds Skooma-based OpenAPI validation so SDK-facing request specs can
assert that documented request and response contracts match real Rails
behavior. This also upgrades the spec to OpenAPI 3.1 and fixes contract
drift uncovered while validating core application and platform
resources.

Closes
None

Why
We want CI to catch OpenAPI drift before it reaches SDK consumers. While
wiring validation in, this PR surfaced several mismatches between the
documented contract and what the Rails endpoints actually accept or
return.

What this change does
- Adds Skooma-backed OpenAPI validation to the request spec flow and a
dedicated OpenAPI validation spec.
- Migrates nullable schema definitions to OpenAPI 3.1-compatible unions.
- Updates core SDK-facing schemas and payloads across accounts,
contacts, conversations, inboxes, messages, teams, reporting events, and
platform account resources.
- Documents concrete runtime cases that were previously missing or
inaccurate, including nested `profile` update payloads, multipart avatar
uploads, required profile update bodies, nullable inbox feature flags,
and message sender types that include both `Captain::Assistant` and
senderless activity-style messages.
- Regenerates the committed Swagger JSON and tag-group artifacts used by
CI sync checks.

Validation
- `bundle exec rake swagger:build`
- `bundle exec rspec spec/swagger/openapi_spec.rb`

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
Shivam Mishra
2026-03-11 07:03:55 +05:30
committed by GitHub
parent dc0e5eb465
commit 9a9398b386
54 changed files with 3216 additions and 1192 deletions

View File

@@ -93,8 +93,8 @@ jobs:
exit 1 exit 1
fi fi
mkdir -p ~/tmp mkdir -p ~/tmp
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar > ~/tmp/openapi-generator-cli-7.19.0.jar
java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json java -jar ~/tmp/openapi-generator-cli-7.19.0.jar validate -i swagger/swagger.json
# Bundle audit # Bundle audit
- run: - run:

View File

@@ -268,6 +268,7 @@ group :development, :test do
gem 'seed_dump' gem 'seed_dump'
gem 'shoulda-matchers' gem 'shoulda-matchers'
gem 'simplecov', '>= 0.21', require: false gem 'simplecov', '>= 0.21', require: false
gem 'skooma'
gem 'spring' gem 'spring'
gem 'spring-watcher-listen' gem 'spring-watcher-listen'
end end

View File

@@ -473,6 +473,12 @@ GEM
hana (~> 1.3) hana (~> 1.3)
regexp_parser (~> 2.0) regexp_parser (~> 2.0)
uri_template (~> 0.7) uri_template (~> 0.7)
json_skooma (0.2.5)
bigdecimal
hana (~> 1.3)
regexp_parser (~> 2.0)
uri-idna (~> 0.2)
zeitwerk (~> 2.6)
judoscale-rails (1.8.2) judoscale-rails (1.8.2)
judoscale-ruby (= 1.8.2) judoscale-ruby (= 1.8.2)
railties railties
@@ -910,6 +916,9 @@ GEM
simplecov_json_formatter (~> 0.1) simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.2) simplecov-html (0.13.2)
simplecov_json_formatter (0.1.4) simplecov_json_formatter (0.1.4)
skooma (0.3.7)
json_skooma (~> 0.2.5)
zeitwerk (~> 2.6)
slack-ruby-client (2.7.0) slack-ruby-client (2.7.0)
faraday (>= 2.0.1) faraday (>= 2.0.1)
faraday-mashify faraday-mashify
@@ -970,6 +979,7 @@ GEM
unicode-emoji (4.0.4) unicode-emoji (4.0.4)
uniform_notifier (1.17.0) uniform_notifier (1.17.0)
uri (1.1.1) uri (1.1.1)
uri-idna (0.3.1)
uri_template (0.7.0) uri_template (0.7.0)
valid_email2 (5.2.6) valid_email2 (5.2.6)
activemodel (>= 3.2) activemodel (>= 3.2)
@@ -1143,6 +1153,7 @@ DEPENDENCIES
sidekiq_alive sidekiq_alive
simplecov (>= 0.21) simplecov (>= 0.21)
simplecov_json_formatter simplecov_json_formatter
skooma
slack-ruby-client (~> 2.7.0) slack-ruby-client (~> 2.7.0)
spring spring
spring-watcher-listen spring-watcher-listen

View File

@@ -25,6 +25,7 @@ RSpec.describe 'Agents API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.parsed_body.size).to eq(account.users.count) expect(response.parsed_body.size).to eq(account.users.count)
end end
@@ -122,6 +123,7 @@ RSpec.describe 'Agents API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(other_agent.reload.name).to eq(params[:name]) expect(other_agent.reload.name).to eq(params[:name])
end end
@@ -171,6 +173,7 @@ RSpec.describe 'Agents API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.parsed_body['email']).to eq(params[:email]) expect(response.parsed_body['email']).to eq(params[:email])
expect(account.users.last.name).to eq('NewUser') expect(account.users.last.name).to eq('NewUser')
end end

View File

@@ -45,6 +45,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
response_body = response.parsed_body response_body = response.parsed_body
contact_emails = response_body['payload'].pluck('email') contact_emails = response_body['payload'].pluck('email')
contact_inboxes_source_ids = response_body['payload'].flat_map { |c| c['contact_inboxes'].pluck('source_id') } contact_inboxes_source_ids = response_body['payload'].flat_map { |c| c['contact_inboxes'].pluck('source_id') }
@@ -331,6 +332,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.body).to include(contact2.email) expect(response.body).to include(contact2.email)
expect(response.body).not_to include(contact1.email) expect(response.body).not_to include(contact1.email)
end end
@@ -443,6 +445,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.body).to include(contact2.email) expect(response.body).to include(contact2.email)
expect(response.body).to include(contact1.email) expect(response.body).to include(contact1.email)
end end
@@ -497,6 +500,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.body).to include(contact.name) expect(response.body).to include(contact.name)
end end
end end
@@ -620,6 +624,7 @@ RSpec.describe 'Contacts API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(contact.reload.name).to eq('Test Blub') expect(contact.reload.name).to eq('Test Blub')
# custom attributes are merged properly without overwriting existing ones # custom attributes are merged properly without overwriting existing ones
expect(contact.custom_attributes).to eq({ 'test' => 'new test', 'test1' => 'test1', 'test2' => 'test2' }) expect(contact.custom_attributes).to eq({ 'test' => 'new test', 'test1' => 'test1', 'test2' => 'test2' })

View File

@@ -31,6 +31,7 @@ RSpec.describe 'Conversation Messages API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(conversation.messages.count).to eq(1) expect(conversation.messages.count).to eq(1)
expect(conversation.messages.first.content).to eq(params[:content]) expect(conversation.messages.first.content).to eq(params[:content])
end end
@@ -182,6 +183,7 @@ RSpec.describe 'Conversation Messages API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:meta][:contact][:id]).to eq(conversation.contact_id) expect(JSON.parse(response.body, symbolize_names: true)[:meta][:contact][:id]).to eq(conversation.contact_id)
end end
end end

View File

@@ -27,6 +27,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
body = JSON.parse(response.body, symbolize_names: true) body = JSON.parse(response.body, symbolize_names: true)
expect(body[:data][:meta][:all_count]).to eq(1) expect(body[:data][:meta][:all_count]).to eq(1)
expect(body[:data][:meta].keys).to include(:all_count, :mine_count, :assigned_count, :unassigned_count) expect(body[:data][:meta].keys).to include(:all_count, :mine_count, :assigned_count, :unassigned_count)
@@ -165,6 +166,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
response_data = JSON.parse(response.body, symbolize_names: true) response_data = JSON.parse(response.body, symbolize_names: true)
expect(response_data.count).to eq(2) expect(response_data.count).to eq(2)
end end
@@ -234,6 +236,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(conversation.display_id) expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(conversation.display_id)
end end
@@ -282,6 +285,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:priority]).to eq('high') expect(JSON.parse(response.body, symbolize_names: true)[:priority]).to eq('high')
end end
@@ -342,6 +346,7 @@ RSpec.describe 'Conversations API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
response_data = JSON.parse(response.body, symbolize_names: true) response_data = JSON.parse(response.body, symbolize_names: true)
expect(response_data[:additional_attributes]).to eq(additional_attributes) expect(response_data[:additional_attributes]).to eq(additional_attributes)
end end
@@ -449,9 +454,11 @@ RSpec.describe 'Conversations API', type: :request do
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_status", post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_status",
headers: agent.create_new_auth_token, headers: agent.create_new_auth_token,
params: { status: 'open' },
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(conversation.reload.status).to eq('open') expect(conversation.reload.status).to eq('open')
end end

View File

@@ -32,6 +32,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(2) expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(2)
end end
@@ -95,6 +96,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(inbox.id) expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(inbox.id)
end end
@@ -383,6 +385,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.body).to include('test.com') expect(response.body).to include('test.com')
end end
@@ -478,6 +481,7 @@ RSpec.describe 'Inboxes API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(inbox.reload.enable_auto_assignment).to be_falsey expect(inbox.reload.enable_auto_assignment).to be_falsey
expect(inbox.reload.portal_id).to eq(portal.id) expect(inbox.reload.portal_id).to eq(portal.id)
expect(response.parsed_body['name']).to eq 'new test inbox' expect(response.parsed_body['name']).to eq 'new test inbox'

View File

@@ -22,6 +22,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.parsed_body.first['id']).to eq(account.teams.first.id) expect(response.parsed_body.first['id']).to eq(account.teams.first.id)
end end
end end
@@ -45,6 +46,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.parsed_body['id']).to eq(team.id) expect(response.parsed_body['id']).to eq(team.id)
end end
end end
@@ -83,6 +85,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(Team.count).to eq(2) expect(Team.count).to eq(2)
end end
end end
@@ -121,6 +124,7 @@ RSpec.describe 'Teams API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(team.reload.name).to eq('new-team') expect(team.reload.name).to eq('new-team')
end end
end end

View File

@@ -149,6 +149,7 @@ RSpec.describe 'Accounts API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.body).to include(account.name) expect(response.body).to include(account.name)
expect(response.body).to include(account.locale) expect(response.body).to include(account.locale)
expect(response.body).to include(account.domain) expect(response.body).to include(account.domain)
@@ -184,22 +185,22 @@ RSpec.describe 'Accounts API', type: :request do
end end
end end
describe 'PUT /api/v1/accounts/{account.id}' do describe 'PATCH /api/v1/accounts/{account.id}' do
let(:account) { create(:account) } let(:account) { create(:account) }
let(:agent) { create(:user, account: account, role: :agent) } let(:agent) { create(:user, account: account, role: :agent) }
let(:admin) { create(:user, account: account, role: :administrator) } let(:admin) { create(:user, account: account, role: :administrator) }
context 'when it is an unauthenticated user' do context 'when it is an unauthenticated user' do
it 'returns unauthorized' do it 'returns unauthorized' do
put "/api/v1/accounts/#{account.id}" patch "/api/v1/accounts/#{account.id}"
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
end end
context 'when it is an unauthorized user' do context 'when it is an unauthorized user' do
it 'returns unauthorized' do it 'returns unauthorized' do
put "/api/v1/accounts/#{account.id}", patch "/api/v1/accounts/#{account.id}",
headers: agent.create_new_auth_token headers: agent.create_new_auth_token
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
@@ -219,11 +220,20 @@ RSpec.describe 'Accounts API', type: :request do
company_size: '1-10' company_size: '1-10'
} }
it 'returns a valid schema' do
patch "/api/v1/accounts/#{account.id}",
params: params,
headers: admin.create_new_auth_token,
as: :json
expect(response).to conform_schema(200)
end
it 'modifies an account' do it 'modifies an account' do
put "/api/v1/accounts/#{account.id}", patch "/api/v1/accounts/#{account.id}",
params: params, params: params,
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(account.reload.name).to eq(params[:name]) expect(account.reload.name).to eq(params[:name])
@@ -242,19 +252,19 @@ RSpec.describe 'Accounts API', type: :request do
it 'updates onboarding step to invite_team if onboarding step is present in account custom attributes' do it 'updates onboarding step to invite_team if onboarding step is present in account custom attributes' do
account.update(custom_attributes: { onboarding_step: 'account_update' }) account.update(custom_attributes: { onboarding_step: 'account_update' })
put "/api/v1/accounts/#{account.id}", patch "/api/v1/accounts/#{account.id}",
params: params, params: params,
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,
as: :json as: :json
expect(account.reload.custom_attributes['onboarding_step']).to eq('invite_team') expect(account.reload.custom_attributes['onboarding_step']).to eq('invite_team')
end end
it 'will not update onboarding step if onboarding step is not present in account custom attributes' do it 'will not update onboarding step if onboarding step is not present in account custom attributes' do
put "/api/v1/accounts/#{account.id}", patch "/api/v1/accounts/#{account.id}",
params: params, params: params,
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,
as: :json as: :json
expect(account.reload.custom_attributes['onboarding_step']).to be_nil expect(account.reload.custom_attributes['onboarding_step']).to be_nil
end end
@@ -262,10 +272,10 @@ RSpec.describe 'Accounts API', type: :request do
it 'Throws error 422' do it 'Throws error 422' do
params[:name] = 'test' * 999 params[:name] = 'test' * 999
put "/api/v1/accounts/#{account.id}", patch "/api/v1/accounts/#{account.id}",
params: params, params: params,
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,
as: :json as: :json
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
json_response = response.parsed_body json_response = response.parsed_body

View File

@@ -21,6 +21,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
json_response = response.parsed_body json_response = response.parsed_body
expect(json_response['id']).to eq(agent.id) expect(json_response['id']).to eq(agent.id)
expect(json_response['email']).to eq(agent.email) expect(json_response['email']).to eq(agent.email)
@@ -50,6 +51,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
json_response = response.parsed_body json_response = response.parsed_body
agent.reload agent.reload
expect(json_response['id']).to eq(agent.id) expect(json_response['id']).to eq(agent.id)
@@ -64,6 +66,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
agent.reload agent.reload
expect(agent.custom_attributes['phone_number']).to eq('+123456789') expect(agent.custom_attributes['phone_number']).to eq('+123456789')
@@ -91,6 +94,7 @@ RSpec.describe 'Profile API', type: :request do
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(agent.reload.valid_password?('Test1234!')).to be true expect(agent.reload.valid_password?('Test1234!')).to be true
end end

View File

@@ -144,6 +144,7 @@ RSpec.describe 'Platform Accounts API', type: :request do
headers: { api_access_token: platform_app.access_token.token }, as: :json headers: { api_access_token: platform_app.access_token.token }, as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response).to conform_schema(200)
expect(response.body).to include(account.name) expect(response.body).to include(account.name)
end end
end end

View File

@@ -75,6 +75,10 @@ RSpec.configure do |config|
config.include ActiveSupport::Testing::TimeHelpers config.include ActiveSupport::Testing::TimeHelpers
config.include ActionCable::TestHelper config.include ActionCable::TestHelper
config.include ActiveJob::TestHelper config.include ActiveJob::TestHelper
# OpenAPI response validation via Skooma
path_to_openapi = Rails.root.join('swagger/swagger.json')
config.include Skooma::RSpec[path_to_openapi], type: :request
end end
Shoulda::Matchers.configure do |config| Shoulda::Matchers.configure do |config|

View File

@@ -0,0 +1,7 @@
require 'rails_helper'
RSpec.describe 'OpenAPI document', type: :request do
it 'is valid against the OpenAPI 3.1.0 meta-schema' do
expect(skooma_openapi_schema).to be_valid_document
end
end

View File

@@ -18,20 +18,23 @@ properties:
example: 'support@example.com' example: 'support@example.com'
# Settings parameters (stored in settings JSONB column) # Settings parameters (stored in settings JSONB column)
auto_resolve_after: auto_resolve_after:
type: integer type:
- integer
- 'null'
minimum: 10 minimum: 10
maximum: 1439856 maximum: 1439856
nullable: true
description: Auto resolve conversations after specified minutes description: Auto resolve conversations after specified minutes
example: 1440 example: 1440
auto_resolve_message: auto_resolve_message:
type: string type:
nullable: true - string
- 'null'
description: Message to send when auto resolving description: Message to send when auto resolving
example: "This conversation has been automatically resolved due to inactivity" example: "This conversation has been automatically resolved due to inactivity"
auto_resolve_ignore_waiting: auto_resolve_ignore_waiting:
type: boolean type:
nullable: true - boolean
- 'null'
description: Whether to ignore waiting conversations for auto resolve description: Whether to ignore waiting conversations for auto resolve
example: false example: false
# Custom attributes parameters (stored in custom_attributes JSONB column) # Custom attributes parameters (stored in custom_attributes JSONB column)

View File

@@ -1,7 +1,6 @@
type: object type: object
required: required:
- source_id - source_id
- inbox_id
properties: properties:
source_id: source_id:
type: string type: string

View File

@@ -26,9 +26,7 @@ properties:
type: object type: object
description: Cache keys for the account description: Cache keys for the account
features: features:
type: array type: object
items:
type: string
description: Enabled features for the account description: Enabled features for the account
settings: settings:
type: object type: object
@@ -48,16 +46,24 @@ properties:
description: Custom attributes of the account description: Custom attributes of the account
properties: properties:
plan_name: plan_name:
type: string type:
- string
- 'null'
description: Subscription plan name description: Subscription plan name
subscribed_quantity: subscribed_quantity:
type: number type:
- number
- 'null'
description: Subscribed quantity description: Subscribed quantity
subscription_status: subscription_status:
type: string type:
- string
- 'null'
description: Subscription status description: Subscription status
subscription_ends_on: subscription_ends_on:
type: string type:
- string
- 'null'
format: date format: date
description: Subscription end date description: Subscription end date
industry: industry:

View File

@@ -3,7 +3,9 @@ allOf:
- type: object - type: object
properties: properties:
latest_chatwoot_version: latest_chatwoot_version:
type: string type:
- string
- 'null'
description: Latest version of Chatwoot available description: Latest version of Chatwoot available
example: "3.0.0" example: "3.0.0"
subscribed_features: subscribed_features:

View File

@@ -31,5 +31,7 @@ properties:
type: string type: string
description: The thumbnail of the agent description: The thumbnail of the agent
custom_role_id: custom_role_id:
type: integer type:
- integer
- 'null'
description: The custom role id of the agent description: The custom role id of the agent

View File

@@ -38,8 +38,9 @@ properties:
type: integer type: integer
description: Version number of the audit log entry description: Version number of the audit log entry
comment: comment:
type: string type:
nullable: true - string
- 'null'
description: Optional comment associated with the audit log entry description: Optional comment associated with the audit log entry
request_uuid: request_uuid:
type: string type: string
@@ -48,6 +49,7 @@ properties:
type: integer type: integer
description: Unix timestamp when the audit log entry was created description: Unix timestamp when the audit log entry was created
remote_address: remote_address:
type: string type:
nullable: true - string
- 'null'
description: IP address from which the action was performed description: IP address from which the action was performed

View File

@@ -31,9 +31,10 @@ properties:
type: string type: string
description: Status of the message description: Status of the message
source_id: source_id:
type: string type:
- string
- 'null'
description: Source ID of the message description: Source ID of the message
nullable: true
content_type: content_type:
type: string type: string
description: Type of the content description: Type of the content
@@ -41,13 +42,15 @@ properties:
type: object type: object
description: Attributes of the content description: Attributes of the content
sender_type: sender_type:
type: string type:
- string
- 'null'
description: Type of the sender description: Type of the sender
nullable: true
sender_id: sender_id:
type: integer type:
- integer
- 'null'
description: ID of the sender description: ID of the sender
nullable: true
external_source_ids: external_source_ids:
type: object type: object
description: External source IDs description: External source IDs
@@ -55,9 +58,10 @@ properties:
type: object type: object
description: Additional attributes of the message description: Additional attributes of the message
processed_message_content: processed_message_content:
type: string type:
- string
- 'null'
description: Processed message content description: Processed message content
nullable: true
sentiment: sentiment:
type: object type: object
description: Sentiment analysis of the message description: Sentiment analysis of the message
@@ -66,9 +70,10 @@ properties:
description: Conversation details description: Conversation details
properties: properties:
assignee_id: assignee_id:
type: integer type:
- integer
- 'null'
description: ID of the assignee description: ID of the assignee
nullable: true
unread_count: unread_count:
type: integer type: integer
description: Count of unread messages description: Count of unread messages

View File

@@ -11,7 +11,9 @@ properties:
type: string type: string
description: Country of the contact description: Country of the contact
country_code: country_code:
type: string type:
- string
- 'null'
description: Country code of the contact description: Country code of the contact
created_at_ip: created_at_ip:
type: string type: string
@@ -26,16 +28,18 @@ properties:
type: integer type: integer
description: The ID of the contact description: The ID of the contact
identifier: identifier:
type: string type:
- string
- 'null'
description: The identifier of the contact description: The identifier of the contact
nullable: true
name: name:
type: string type: string
description: The name of the contact description: The name of the contact
phone_number: phone_number:
type: string type:
- string
- 'null'
description: The phone number of the contact description: The phone number of the contact
nullable: true
thumbnail: thumbnail:
type: string type: string
description: The thumbnail of the contact description: The thumbnail of the contact

View File

@@ -22,6 +22,7 @@ properties:
type: string type: string
description: Type of channel description: Type of channel
provider: provider:
type: string type:
- string
- 'null'
description: Provider of the inbox description: Provider of the inbox
nullable: true

View File

@@ -11,7 +11,9 @@ properties:
type: string type: string
description: Country of the contact description: Country of the contact
country_code: country_code:
type: string type:
- string
- 'null'
description: Country code of the contact description: Country code of the contact
created_at_ip: created_at_ip:
type: string type: string
@@ -21,9 +23,10 @@ properties:
description: Availability status of the contact description: Availability status of the contact
enum: ["online", "offline"] enum: ["online", "offline"]
email: email:
type: string type:
- string
- 'null'
description: The email address of the contact description: The email address of the contact
nullable: true
id: id:
type: integer type: integer
description: The ID of the contact description: The ID of the contact
@@ -31,16 +34,18 @@ properties:
type: string type: string
description: The name of the contact description: The name of the contact
phone_number: phone_number:
type: string type:
- string
- 'null'
description: The phone number of the contact description: The phone number of the contact
nullable: true
blocked: blocked:
type: boolean type: boolean
description: Whether the contact is blocked description: Whether the contact is blocked
identifier: identifier:
type: string type:
- string
- 'null'
description: The identifier of the contact description: The identifier of the contact
nullable: true
thumbnail: thumbnail:
type: string type: string
description: The thumbnail of the contact description: The thumbnail of the contact
@@ -48,9 +53,10 @@ properties:
type: object type: object
description: The custom attributes of the contact description: The custom attributes of the contact
last_activity_at: last_activity_at:
type: integer type:
- integer
- 'null'
description: Timestamp of last activity description: Timestamp of last activity
nullable: true
created_at: created_at:
type: integer type: integer
description: Timestamp when contact was created description: Timestamp when contact was created

View File

@@ -4,5 +4,7 @@ properties:
type: integer type: integer
description: Total number of contacts description: Total number of contacts
current_page: current_page:
type: string type:
- string
- integer
description: Current page number description: Current page number

View File

@@ -43,7 +43,9 @@ properties:
type: boolean type: boolean
description: Whether the conversation is muted description: Whether the conversation is muted
snoozed_until: snoozed_until:
type: number type:
- number
- 'null'
description: The time at which the conversation will be unmuted description: The time at which the conversation will be unmuted
status: status:
type: string type: string
@@ -56,29 +58,38 @@ properties:
type: number type: number
description: The time at which conversation was updated description: The time at which conversation was updated
timestamp: timestamp:
type: string type: number
description: The time at which conversation was created description: The time at which conversation was created
first_reply_created_at: first_reply_created_at:
type: number type:
- number
- 'null'
description: The time at which the first reply was created description: The time at which the first reply was created
unread_count: unread_count:
type: number type: number
description: The number of unread messages description: The number of unread messages
last_non_activity_message: last_non_activity_message:
type: object oneOf:
$ref: '#/components/schemas/message' - $ref: '#/components/schemas/message'
- type: 'null'
description: The last non activity message description: The last non activity message
last_activity_at: last_activity_at:
type: number type: number
description: The last activity at of the conversation description: The last activity at of the conversation
priority: priority:
type: string type:
- string
- 'null'
description: The priority of the conversation description: The priority of the conversation
waiting_since: waiting_since:
type: number type:
- number
- 'null'
description: The time at which the conversation was waiting description: The time at which the conversation was waiting
sla_policy_id: sla_policy_id:
type: number type:
- number
- 'null'
description: The ID of the SLA policy description: The ID of the SLA policy
applied_sla: applied_sla:
type: object type: object

View File

@@ -51,10 +51,12 @@ properties:
description: The agent assigned to the conversation description: The agent assigned to the conversation
nullable: true nullable: true
agent_last_seen_at: agent_last_seen_at:
type: string type:
- string
- 'null'
description: Timestamp when the agent last saw the conversation description: Timestamp when the agent last saw the conversation
nullable: true
assignee_last_seen_at: assignee_last_seen_at:
type: string type:
- string
- 'null'
description: Timestamp when the assignee last saw the conversation description: Timestamp when the assignee last saw the conversation
nullable: true

View File

@@ -13,7 +13,9 @@ properties:
type: string type: string
description: The availability status of the sender description: The availability status of the sender
email: email:
type: string type:
- string
- 'null'
description: The email of the sender description: The email of the sender
id: id:
type: number type: number
@@ -22,16 +24,22 @@ properties:
type: string type: string
description: The name of the sender description: The name of the sender
phone_number: phone_number:
type: string type:
- string
- 'null'
description: The phone number of the sender description: The phone number of the sender
blocked: blocked:
type: boolean type: boolean
description: Whether the sender is blocked description: Whether the sender is blocked
identifier: identifier:
type: string type:
- string
- 'null'
description: The identifier of the sender description: The identifier of the sender
thumbnail: thumbnail:
type: string type:
- string
- 'null'
description: Avatar URL of the contact description: Avatar URL of the contact
custom_attributes: custom_attributes:
type: object type: object

View File

@@ -28,16 +28,22 @@ properties:
type: string type: string
description: Script used to load the website widget description: Script used to load the website widget
welcome_title: welcome_title:
type: string type:
- string
- 'null'
description: Welcome title to be displayed on the widget description: Welcome title to be displayed on the widget
welcome_tagline: welcome_tagline:
type: string type:
- string
- 'null'
description: Welcome tagline to be displayed on the widget description: Welcome tagline to be displayed on the widget
greeting_enabled: greeting_enabled:
type: boolean type: boolean
description: The flag which shows whether greeting is enabled description: The flag which shows whether greeting is enabled
greeting_message: greeting_message:
type: string type:
- string
- 'null'
description: A greeting message when the user starts the conversation description: A greeting message when the user starts the conversation
channel_id: channel_id:
type: number type: number
@@ -55,7 +61,9 @@ properties:
type: object type: object
description: Configuration settings for auto assignment description: Configuration settings for auto assignment
out_of_office_message: out_of_office_message:
type: string type:
- string
- 'null'
description: Message to show when agents are out of office description: Message to show when agents are out of office
working_hours: working_hours:
type: array type: array
@@ -70,16 +78,24 @@ properties:
type: boolean type: boolean
description: Whether the inbox is closed for the entire day description: Whether the inbox is closed for the entire day
open_hour: open_hour:
type: number type:
- number
- 'null'
description: Hour when inbox opens (0-23) description: Hour when inbox opens (0-23)
open_minutes: open_minutes:
type: number type:
- number
- 'null'
description: Minutes of the hour when inbox opens (0-59) description: Minutes of the hour when inbox opens (0-59)
close_hour: close_hour:
type: number type:
- number
- 'null'
description: Hour when inbox closes (0-23) description: Hour when inbox closes (0-23)
close_minutes: close_minutes:
type: number type:
- number
- 'null'
description: Minutes of the hour when inbox closes (0-59) description: Minutes of the hour when inbox closes (0-59)
open_all_day: open_all_day:
type: boolean type: boolean
@@ -88,7 +104,9 @@ properties:
type: string type: string
description: Timezone configuration for the inbox description: Timezone configuration for the inbox
callback_webhook_url: callback_webhook_url:
type: string type:
- string
- 'null'
description: Webhook URL for callbacks description: Webhook URL for callbacks
allow_messages_after_resolved: allow_messages_after_resolved:
type: boolean type: boolean
@@ -100,26 +118,38 @@ properties:
type: string type: string
description: Type of sender name to display (e.g., friendly) description: Type of sender name to display (e.g., friendly)
business_name: business_name:
type: string type:
- string
- 'null'
description: Business name associated with the inbox description: Business name associated with the inbox
hmac_mandatory: hmac_mandatory:
type: boolean type: boolean
description: Whether HMAC verification is mandatory description: Whether HMAC verification is mandatory
selected_feature_flags: selected_feature_flags:
type: object type:
- array
- 'null'
description: Selected feature flags for the inbox description: Selected feature flags for the inbox
items:
type: string
reply_time: reply_time:
type: string type: string
description: Expected reply time description: Expected reply time
messaging_service_sid: messaging_service_sid:
type: string type:
- string
- 'null'
description: Messaging service SID for SMS providers description: Messaging service SID for SMS providers
phone_number: phone_number:
type: string type:
- string
- 'null'
description: Phone number associated with the inbox description: Phone number associated with the inbox
medium: medium:
type: string type: string
description: Medium of communication (e.g., sms, email) description: Medium of communication (e.g., sms, email)
provider: provider:
type: string type:
- string
- 'null'
description: Provider of the channel description: Provider of the channel

View File

@@ -17,37 +17,49 @@ properties:
description: The ID of the conversation description: The ID of the conversation
message_type: message_type:
type: integer type: integer
enum: [0, 1, 2] enum: [0, 1, 2, 3]
description: The type of the message description: The type of the message
created_at: created_at:
type: integer type: integer
description: The time at which message was created description: The time at which message was created
updated_at: updated_at:
type: integer type:
- integer
- string
description: The time at which message was updated description: The time at which message was updated
private: private:
type: boolean type: boolean
description: The flags which shows whether the message is private or not description: The flags which shows whether the message is private or not
status: status:
type: string type:
enum: ["sent", "delivered", "read", "failed"] - string
- 'null'
enum: ["sent", "delivered", "read", "failed", null]
description: The status of the message description: The status of the message
source_id: source_id:
type: string type:
- string
- 'null'
description: The source ID of the message description: The source ID of the message
content_type: content_type:
type: string type:
enum: ["text", "input_select", "cards", "form"] - string
- 'null'
enum: ["text", "input_text", "input_textarea", "input_email", "input_select", "cards", "form", "article", "incoming_email", "input_csat", "integrations", "sticker", "voice_call", null]
description: The type of the template message description: The type of the template message
content_attributes: content_attributes:
type: object type: object
description: The content attributes for each content_type description: The content attributes for each content_type
sender_type: sender_type:
type: string type:
enum: ["contact", "agent", "agent_bot"] - string
- 'null'
enum: ["Contact", "User", "AgentBot", "Captain::Assistant", null]
description: The type of the sender description: The type of the sender
sender_id: sender_id:
type: number type:
- number
- 'null'
description: The ID of the sender description: The ID of the sender
external_source_ids: external_source_ids:
type: object type: object
@@ -56,16 +68,24 @@ properties:
type: object type: object
description: The additional attributes of the message description: The additional attributes of the message
processed_message_content: processed_message_content:
type: string type:
- string
- 'null'
description: The processed message content description: The processed message content
sentiment: sentiment:
type: object type:
- object
- 'null'
description: The sentiment of the message description: The sentiment of the message
conversation: conversation:
type: object type:
- object
- 'null'
description: The conversation object description: The conversation object
attachment: attachment:
type: object type:
- object
- 'null'
description: The file object attached to the image description: The file object attached to the image
sender: sender:
type: object type: object

View File

@@ -18,7 +18,7 @@ properties:
description: "The type of the message (0: incoming, 1: outgoing, 2: activity, 3: template)" description: "The type of the message (0: incoming, 1: outgoing, 2: activity, 3: template)"
content_type: content_type:
type: string type: string
enum: ["text", "input_select", "cards", "form", "input_csat"] enum: ["text", "input_text", "input_textarea", "input_email", "input_select", "cards", "form", "article", "incoming_email", "input_csat", "integrations", "sticker", "voice_call"]
description: The type of the message content description: The type of the message content
status: status:
type: string type: string
@@ -29,13 +29,15 @@ properties:
description: The content attributes for each content_type description: The content attributes for each content_type
properties: properties:
in_reply_to: in_reply_to:
type: string type:
- string
- 'null'
description: ID of the message this is replying to description: ID of the message this is replying to
nullable: true
echo_id: echo_id:
type: string type:
- string
- 'null'
description: The echo ID of the message, used for deduplication description: The echo ID of the message, used for deduplication
nullable: true
created_at: created_at:
type: integer type: integer
description: The timestamp when message was created description: The timestamp when message was created
@@ -43,9 +45,10 @@ properties:
type: boolean type: boolean
description: The flag which shows whether the message is private or not description: The flag which shows whether the message is private or not
source_id: source_id:
type: string type:
- string
- 'null'
description: The source ID of the message description: The source ID of the message
nullable: true
sender: sender:
$ref: '#/components/schemas/contact_detail' $ref: '#/components/schemas/contact_detail'
description: The sender of the message (only for incoming messages) description: The sender of the message (only for incoming messages)

View File

@@ -4,16 +4,19 @@ properties:
type: integer type: integer
description: Total number of articles description: Total number of articles
archived_articles_count: archived_articles_count:
type: integer type:
nullable: true - integer
- 'null'
description: Number of archived articles description: Number of archived articles
published_count: published_count:
type: integer type:
nullable: true - integer
- 'null'
description: Number of published articles description: Number of published articles
draft_articles_count: draft_articles_count:
type: integer type:
nullable: true - integer
- 'null'
description: Number of draft articles description: Number of draft articles
categories_count: categories_count:
type: integer type: integer

View File

@@ -26,16 +26,19 @@ properties:
type: number type: number
description: ID of the account description: ID of the account
conversation_id: conversation_id:
type: number type:
nullable: true - number
- 'null'
description: ID of the conversation description: ID of the conversation
inbox_id: inbox_id:
type: number type:
nullable: true - number
- 'null'
description: ID of the inbox description: ID of the inbox
user_id: user_id:
type: number type:
nullable: true - number
- 'null'
description: ID of the user/agent description: ID of the user/agent
created_at: created_at:
type: string type: string

View File

@@ -13,16 +13,19 @@ items:
type: number type: number
description: Number of conversations resolved by the agent during the date range description: Number of conversations resolved by the agent during the date range
avg_resolution_time: avg_resolution_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) to resolve conversations. Null if no data available. description: Average time (in seconds) to resolve conversations. Null if no data available.
avg_first_response_time: avg_first_response_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) for the first response. Null if no data available. description: Average time (in seconds) for the first response. Null if no data available.
avg_reply_time: avg_reply_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) between replies. Null if no data available. description: Average time (in seconds) between replies. Null if no data available.
example: example:
- id: 1 - id: 1

View File

@@ -13,16 +13,19 @@ items:
type: number type: number
description: Number of conversations resolved in the inbox during the date range description: Number of conversations resolved in the inbox during the date range
avg_resolution_time: avg_resolution_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) to resolve conversations. Null if no data available. description: Average time (in seconds) to resolve conversations. Null if no data available.
avg_first_response_time: avg_first_response_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) for the first response. Null if no data available. description: Average time (in seconds) for the first response. Null if no data available.
avg_reply_time: avg_reply_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) between replies. Null if no data available. description: Average time (in seconds) between replies. Null if no data available.
example: example:
- id: 1 - id: 1

View File

@@ -13,16 +13,19 @@ items:
type: number type: number
description: Number of conversations resolved by the team during the date range description: Number of conversations resolved by the team during the date range
avg_resolution_time: avg_resolution_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) to resolve conversations. Null if no data available. description: Average time (in seconds) to resolve conversations. Null if no data available.
avg_first_response_time: avg_first_response_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) for the first response. Null if no data available. description: Average time (in seconds) for the first response. Null if no data available.
avg_reply_time: avg_reply_time:
type: number type:
nullable: true - number
- 'null'
description: Average time (in seconds) between replies. Null if no data available. description: Average time (in seconds) between replies. Null if no data available.
example: example:
- id: 1 - id: 1

View File

@@ -7,7 +7,9 @@ properties:
type: string type: string
description: The name of the team description: The name of the team
description: description:
type: string type:
- string
- 'null'
description: The description about the team description: The description about the team
allow_auto_assign: allow_auto_assign:
type: boolean type: boolean

View File

@@ -13,17 +13,21 @@ properties:
confirmed: confirmed:
type: boolean type: boolean
display_name: display_name:
type: string type:
nullable: true - string
- 'null'
message_signature: message_signature:
type: string type:
nullable: true - string
- 'null'
email: email:
type: string type: string
hmac_identifier: hmac_identifier:
type: string type: string
inviter_id: inviter_id:
type: number type:
- number
- 'null'
name: name:
type: string type: string
provider: provider:
@@ -38,8 +42,9 @@ properties:
uid: uid:
type: string type: string
type: type:
type: string type:
nullable: true - string
- 'null'
custom_attributes: custom_attributes:
type: object type: object
description: Available for users who are created through platform APIs and has custom attributes associated. description: Available for users who are created through platform APIs and has custom attributes associated.
@@ -55,7 +60,9 @@ properties:
status: status:
type: string type: string
active_at: active_at:
type: string type:
- string
- 'null'
format: date-time format: date-time
role: role:
type: string type: string
@@ -71,8 +78,10 @@ properties:
auto_offline: auto_offline:
type: boolean type: boolean
custom_role_id: custom_role_id:
type: number type:
nullable: true - number
- 'null'
custom_role: custom_role:
type: object type:
nullable: true - object
- 'null'

View File

@@ -1,4 +1,4 @@
openapi: '3.0.4' openapi: '3.1.0'
info: info:
title: Chatwoot title: Chatwoot
description: This is the API documentation for Chatwoot server. description: This is the API documentation for Chatwoot server.

View File

@@ -38,10 +38,14 @@ responses:
assignee: assignee:
$ref: '#/components/schemas/agent' $ref: '#/components/schemas/agent'
agent_last_seen_at: agent_last_seen_at:
type: string type:
- string
- 'null'
format: date-time format: date-time
assignee_last_seen_at: assignee_last_seen_at:
type: string type:
- string
- 'null'
format: date-time format: date-time
payload: payload:
type: array type: array

View File

@@ -25,6 +25,10 @@ requestBody:
responses: responses:
'200': '200':
description: Success description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/conversation'
'401': '401':
description: Unauthorized description: Unauthorized
content: content:

View File

@@ -33,3 +33,38 @@ get:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/bad_request_error' $ref: '#/components/schemas/bad_request_error'
post:
tags:
- Inboxes
operationId: inboxCreation
summary: Create an inbox
description: You can create more than one website inbox in each account
security:
- userApiKey: []
parameters:
- $ref: '#/components/parameters/account_id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/inbox_create_payload'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/inbox'
'404':
description: Inbox not found
content:
application/json:
schema:
$ref: '#/components/schemas/bad_request_error'
'403':
description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/bad_request_error'

View File

@@ -1,3 +1,38 @@
get:
tags:
- Inboxes
operationId: GetInbox
summary: Get an inbox
security:
- userApiKey: []
description: Get an inbox available in the current account
parameters:
- $ref: '#/components/parameters/account_id'
- name: id
in: path
schema:
type: number
description: ID of the inbox
required: true
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/inbox'
'404':
description: Inbox not found
content:
application/json:
schema:
$ref: '#/components/schemas/bad_request_error'
'403':
description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/bad_request_error'
patch: patch:
tags: tags:
- Inboxes - Inboxes
@@ -26,8 +61,6 @@ patch:
content: content:
application/json: application/json:
schema: schema:
type: object
description: 'Updated inbox object'
$ref: '#/components/schemas/inbox' $ref: '#/components/schemas/inbox'
'404': '404':
description: Inbox not found description: Inbox not found

View File

@@ -167,7 +167,7 @@
# ------------ Application API routes ------------# # ------------ Application API routes ------------#
# Accounts # Accounts
/api/v1/accounts/{id}: /api/v1/accounts/{account_id}:
parameters: parameters:
- $ref: '#/components/parameters/account_id' - $ref: '#/components/parameters/account_id'
get: get:
@@ -413,10 +413,6 @@
# Inboxes # Inboxes
/api/v1/accounts/{account_id}/inboxes: /api/v1/accounts/{account_id}/inboxes:
$ref: ./application/inboxes/index.yml $ref: ./application/inboxes/index.yml
/api/v1/accounts/{account_id}/inboxes/{id}/:
$ref: ./application/inboxes/show.yml
/api/v1/accounts/{account_id}/inboxes/:
$ref: ./application/inboxes/create.yml
/api/v1/accounts/{account_id}/inboxes/{id}: /api/v1/accounts/{account_id}/inboxes/{id}:
$ref: ./application/inboxes/update.yml $ref: ./application/inboxes/update.yml
/api/v1/accounts/{account_id}/inboxes/{id}/agent_bot: /api/v1/accounts/{account_id}/inboxes/{id}/agent_bot:

View File

@@ -19,3 +19,80 @@ get:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/bad_request_error' $ref: '#/components/schemas/bad_request_error'
put:
tags:
- Profile
operationId: updateProfile
summary: Update user profile
description: Update the user profile details
security:
- userApiKey: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- profile
properties:
profile:
type: object
properties:
name:
type: string
email:
type: string
display_name:
type: string
message_signature:
type: string
phone_number:
type: string
current_password:
type: string
password:
type: string
password_confirmation:
type: string
ui_settings:
type: object
multipart/form-data:
schema:
type: object
required:
- profile
properties:
profile:
type: object
properties:
name:
type: string
email:
type: string
display_name:
type: string
message_signature:
type: string
phone_number:
type: string
current_password:
type: string
password:
type: string
password_confirmation:
type: string
avatar:
type: string
format: binary
ui_settings:
type: object
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/user'
'401':
description: Unauthorized

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
openapi: '3.0.4' openapi: '3.1.0'
info: info:
title: Chatwoot - Application API title: Chatwoot - Application API
description: Application API endpoints for Chatwoot description: Application API endpoints for Chatwoot

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
openapi: '3.0.4' openapi: '3.1.0'
info: info:
title: Chatwoot - Client API title: Chatwoot - Client API
description: Client API endpoints for Chatwoot description: Client API endpoints for Chatwoot

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
openapi: '3.0.4' openapi: '3.1.0'
info: info:
title: Chatwoot - Other APIs title: Chatwoot - Other APIs
description: Other API endpoints for Chatwoot description: Other API endpoints for Chatwoot

View File

@@ -1,4 +1,4 @@
openapi: '3.0.4' openapi: '3.1.0'
info: info:
title: Chatwoot - Platform API title: Chatwoot - Platform API
description: Platform API endpoints for Chatwoot description: Platform API endpoints for Chatwoot

File diff suppressed because it is too large Load Diff