docs: land chatwoot parity tracking plan

This commit is contained in:
2026-06-04 20:16:20 +08:00
parent dbc5a1a28f
commit 48a8b851b7
6 changed files with 1645 additions and 20 deletions
+1
View File
@@ -8,6 +8,7 @@ tmp/
# IDE
.idea/
.vscode/
.codegraph/
*.swp
*.swo
+330
View File
@@ -0,0 +1,330 @@
package main
import (
"bufio"
"flag"
"fmt"
"os"
"regexp"
"sort"
"strings"
)
type route struct {
Method string
Path string
Controller string
Source string
}
type sourceDecl struct {
Line int
Text string
}
var criticalRoutes = []route{
{Method: "POST", Path: "/api/v1/accounts/", Controller: "api/v1/accounts#create", Source: "routes.rb:47"},
{Method: "GET", Path: "/api/v1/accounts/:account_id", Controller: "api/v1/accounts#show", Source: "routes.rb:47"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id", Controller: "api/v1/accounts#update", Source: "routes.rb:47"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/update_active_at", Controller: "api/v1/accounts#update_active_at", Source: "routes.rb:49"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/cache_keys", Controller: "api/v1/accounts#cache_keys", Source: "routes.rb:50"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/", Controller: "api/v1/accounts/conversations#index", Source: "routes.rb:134"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/", Controller: "api/v1/accounts/conversations#create", Source: "routes.rb:134"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id", Controller: "api/v1/accounts/conversations#show", Source: "routes.rb:134"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id", Controller: "api/v1/accounts/conversations#update", Source: "routes.rb:134"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id", Controller: "api/v1/accounts/conversations#destroy", Source: "routes.rb:134"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/meta", Controller: "api/v1/accounts/conversations#meta", Source: "routes.rb:136"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/search", Controller: "api/v1/accounts/conversations#search", Source: "routes.rb:137"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/unread_counts", Controller: "api/v1/accounts/conversations/unread_counts#index", Source: "routes.rb:138"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/filter", Controller: "api/v1/accounts/conversations#filter", Source: "routes.rb:139"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/assignments", Controller: "api/v1/accounts/conversations/assignments#create", Source: "routes.rb:148"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/labels", Controller: "api/v1/accounts/conversations/labels#create", Source: "routes.rb:149"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/labels", Controller: "api/v1/accounts/conversations/labels#index", Source: "routes.rb:149"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_status", Controller: "api/v1/accounts/conversations#toggle_status", Source: "routes.rb:158"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_priority", Controller: "api/v1/accounts/conversations#toggle_priority", Source: "routes.rb:159"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/transcript", Controller: "api/v1/accounts/conversations#transcript", Source: "routes.rb:157"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/messages/", Controller: "api/v1/accounts/conversations/messages#index", Source: "routes.rb:142"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/messages/", Controller: "api/v1/accounts/conversations/messages#create", Source: "routes.rb:142"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id", Controller: "api/v1/accounts/conversations/messages#update", Source: "routes.rb:142"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id", Controller: "api/v1/accounts/conversations/messages#destroy", Source: "routes.rb:142"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/translate", Controller: "api/v1/accounts/conversations/messages#translate", Source: "routes.rb:144"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/retry", Controller: "api/v1/accounts/conversations/messages#retry", Source: "routes.rb:145"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/contacts/", Controller: "api/v1/accounts/contacts#index", Source: "routes.rb:197"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/contacts/", Controller: "api/v1/accounts/contacts#create", Source: "routes.rb:197"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/contacts/:contact_id", Controller: "api/v1/accounts/contacts#show", Source: "routes.rb:197"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/contacts/:contact_id", Controller: "api/v1/accounts/contacts#update", Source: "routes.rb:197"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/contacts/:contact_id", Controller: "api/v1/accounts/contacts#destroy", Source: "routes.rb:197"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/contacts/search", Controller: "api/v1/accounts/contacts#search", Source: "routes.rb:201"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/contacts/filter", Controller: "api/v1/accounts/contacts#filter", Source: "routes.rb:202"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/contacts/import", Controller: "api/v1/accounts/contacts#import", Source: "routes.rb:203"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/contacts/export", Controller: "api/v1/accounts/contacts#export", Source: "routes.rb:204"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/contacts/:contact_id/conversations", Controller: "api/v1/accounts/contacts/conversations#index", Source: "routes.rb:211"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/contacts/:contact_id/notes", Controller: "api/v1/accounts/contacts/notes#index", Source: "routes.rb:214"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/contacts/:contact_id/notes", Controller: "api/v1/accounts/contacts/notes#create", Source: "routes.rb:214"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/companies/", Controller: "api/v1/accounts/companies#index", Source: "routes.rb:179"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/companies/", Controller: "api/v1/accounts/companies#create", Source: "routes.rb:179"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/companies/:company_id", Controller: "api/v1/accounts/companies#show", Source: "routes.rb:179"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/companies/:company_id", Controller: "api/v1/accounts/companies#update", Source: "routes.rb:179"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/companies/:company_id", Controller: "api/v1/accounts/companies#destroy", Source: "routes.rb:179"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/companies/search", Controller: "api/v1/accounts/companies#search", Source: "routes.rb:181"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/companies/:company_id/contacts", Controller: "api/v1/accounts/companies/contacts#index", Source: "routes.rb:188"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id", Controller: "api/v1/accounts/companies/contacts#create", Source: "routes.rb:188"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id", Controller: "api/v1/accounts/companies/contacts#destroy", Source: "routes.rb:188"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/search", Controller: "api/v1/accounts/search#index", Source: "routes.rb:170"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/search/conversations", Controller: "api/v1/accounts/search#conversations", Source: "routes.rb:173"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/search/messages", Controller: "api/v1/accounts/search#messages", Source: "routes.rb:174"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/search/contacts", Controller: "api/v1/accounts/search#contacts", Source: "routes.rb:175"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/search/articles", Controller: "api/v1/accounts/search#articles", Source: "routes.rb:176"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/inboxes/", Controller: "api/v1/accounts/inboxes#index", Source: "routes.rb:252"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/inboxes/", Controller: "api/v1/accounts/inboxes#create", Source: "routes.rb:252"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/inboxes/:inbox_id", Controller: "api/v1/accounts/inboxes#show", Source: "routes.rb:252"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/inboxes/:inbox_id", Controller: "api/v1/accounts/inboxes#update", Source: "routes.rb:252"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/inboxes/:inbox_id", Controller: "api/v1/accounts/inboxes#destroy", Source: "routes.rb:252"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/inboxes/:inbox_id/assignable_agents", Controller: "api/v1/accounts/inboxes#assignable_agents", Source: "routes.rb:253"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/inboxes/:inbox_id/campaigns", Controller: "api/v1/accounts/inboxes#campaigns", Source: "routes.rb:254"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/inboxes/:inbox_id/reset_secret", Controller: "api/v1/accounts/inboxes#reset_secret", Source: "routes.rb:262"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/automation_rules/", Controller: "api/v1/accounts/automation_rules#index", Source: "routes.rb:115"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/automation_rules/", Controller: "api/v1/accounts/automation_rules#create", Source: "routes.rb:115"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/automation_rules/:automation_id", Controller: "api/v1/accounts/automation_rules#show", Source: "routes.rb:115"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/automation_rules/:automation_id", Controller: "api/v1/accounts/automation_rules#update", Source: "routes.rb:115"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/automation_rules/:automation_id", Controller: "api/v1/accounts/automation_rules#destroy", Source: "routes.rb:115"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/automation_rules/:automation_id/clone", Controller: "api/v1/accounts/automation_rules#clone", Source: "routes.rb:116"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/macros/", Controller: "api/v1/accounts/macros#index", Source: "routes.rb:118"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/macros/", Controller: "api/v1/accounts/macros#create", Source: "routes.rb:118"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/macros/:macro_id", Controller: "api/v1/accounts/macros#show", Source: "routes.rb:118"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/macros/:macro_id", Controller: "api/v1/accounts/macros#update", Source: "routes.rb:118"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/macros/:macro_id", Controller: "api/v1/accounts/macros#destroy", Source: "routes.rb:118"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/macros/:macro_id/execute", Controller: "api/v1/accounts/macros#execute", Source: "routes.rb:119"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/sla_policies", Controller: "api/v1/accounts/sla_policies#index", Source: "routes.rb:121"},
{Method: "POST", Path: "/api/v1/accounts/:account_id/sla_policies", Controller: "api/v1/accounts/sla_policies#create", Source: "routes.rb:121"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/sla_policies/:id", Controller: "api/v1/accounts/sla_policies#show", Source: "routes.rb:121"},
{Method: "PUT", Path: "/api/v1/accounts/:account_id/sla_policies/:id", Controller: "api/v1/accounts/sla_policies#update", Source: "routes.rb:121"},
{Method: "DELETE", Path: "/api/v1/accounts/:account_id/sla_policies/:id", Controller: "api/v1/accounts/sla_policies#destroy", Source: "routes.rb:121"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/custom_roles/", Controller: "api/v1/accounts/custom_roles#index", Source: "routes.rb:122"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/agent_capacity_policies/", Controller: "api/v1/accounts/agent_capacity_policies#index", Source: "routes.rb:123"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/csat_survey_responses/", Controller: "api/v1/accounts/csat_survey_responses#index", Source: "routes.rb:219"},
{Method: "GET", Path: "/api/v1/accounts/:account_id/csat_survey_responses/metrics", Controller: "api/v1/accounts/csat_survey_responses#metrics", Source: "routes.rb:221"},
}
func main() {
gochatPath := flag.String("gochat", "docs/parity/gochat_routes.txt", "GoChat route dump")
chatwootPath := flag.String("chatwoot", "reference/chatwoot/config/routes.rb", "Chatwoot routes.rb path")
outPath := flag.String("out", "docs/parity/route_parity.md", "route parity markdown output")
chatwootOut := flag.String("chatwoot-out", "docs/parity/chatwoot_routes_static.md", "Chatwoot static route source output")
flag.Parse()
gochatRoutes, err := readRouteDump(*gochatPath)
fatalIf(err)
decls, err := extractChatwootDecls(*chatwootPath)
fatalIf(err)
fatalIf(writeChatwootSource(*chatwootOut, *chatwootPath, decls))
fatalIf(writeParity(*outPath, *gochatPath, *chatwootPath, gochatRoutes))
}
func readRouteDump(path string) (map[string]route, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
routes := map[string]route{}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "TOTAL:") {
continue
}
parts := strings.Fields(line)
if len(parts) < 2 {
continue
}
r := route{Method: parts[0], Path: parts[1]}
routes[key(r.Method, r.Path)] = r
}
return routes, scanner.Err()
}
func extractChatwootDecls(path string) ([]sourceDecl, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
interesting := regexp.MustCompile(`^\s*(namespace|scope|resources?|get|post|put|patch|delete|mount|mount_devise_token_auth_for)\b`)
var out []sourceDecl
scanner := bufio.NewScanner(f)
lineNo := 0
for scanner.Scan() {
lineNo++
line := scanner.Text()
trimmed := strings.TrimSpace(line)
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
continue
}
if interesting.MatchString(line) {
out = append(out, sourceDecl{Line: lineNo, Text: trimmed})
}
}
return out, scanner.Err()
}
func writeChatwootSource(path string, source string, decls []sourceDecl) error {
var b strings.Builder
b.WriteString("# Chatwoot Route Source Declarations\n\n")
b.WriteString("Source: `" + source + "`\n\n")
b.WriteString("Ruby is unavailable in the current workspace, so this file records static route DSL declarations with source lines. It is a repeatable fallback until `bin/rails routes` can run.\n\n")
b.WriteString("| Line | Declaration |\n")
b.WriteString("| --- | --- |\n")
for _, decl := range decls {
b.WriteString(fmt.Sprintf("| %d | `%s` |\n", decl.Line, escapePipes(decl.Text)))
}
return os.WriteFile(path, []byte(b.String()), 0o644)
}
func writeParity(path string, gochatPath string, chatwootPath string, gochatRoutes map[string]route) error {
var exact, methodCompatible, compatible, missing []route
for _, expected := range criticalRoutes {
if _, ok := gochatRoutes[key(expected.Method, expected.Path)]; ok {
exact = append(exact, expected)
continue
}
if hasMethodCompatible(gochatRoutes, expected) {
methodCompatible = append(methodCompatible, expected)
continue
}
if hasParamCompatible(gochatRoutes, expected) {
compatible = append(compatible, expected)
continue
}
missing = append(missing, expected)
}
sortRoutes(exact)
sortRoutes(methodCompatible)
sortRoutes(compatible)
sortRoutes(missing)
var b strings.Builder
b.WriteString("# Route Parity Report\n\n")
b.WriteString("Generated from:\n\n")
b.WriteString("- GoChat route dump: `" + gochatPath + "`\n")
b.WriteString("- Chatwoot route source: `" + chatwootPath + "`\n\n")
b.WriteString("This first report covers frontend-critical API v1 account routes from `reference/chatwoot/config/routes.rb`. Ruby is not installed in the workspace, so Chatwoot routes are sourced from static route declarations instead of `bin/rails routes`.\n\n")
b.WriteString(fmt.Sprintf("Summary: %d exact, %d method-compatible, %d parameter-compatible, %d missing out of %d tracked critical routes.\n\n", len(exact), len(methodCompatible), len(compatible), len(missing), len(criticalRoutes)))
b.WriteString("## Missing Critical Routes\n\n")
writeRouteTable(&b, missing, gochatRoutes, "missing")
b.WriteString("\n## Method-Compatible Routes\n\n")
b.WriteString("These routes exist at the same path but with a compatible HTTP method. Rails resource `update` routes expose both `PATCH` and `PUT`; GoChat currently exposes only one method for some update endpoints. Keep these tracked until both methods are registered or the frontend is proven to call only the implemented method.\n\n")
writeRouteTable(&b, methodCompatible, gochatRoutes, "method-compatible")
b.WriteString("\n## Parameter-Compatible Routes\n\n")
b.WriteString("These routes exist with equivalent method and path shape but different parameter names. They need handler/serializer parity review, and exact external path compatibility must be preserved.\n\n")
writeRouteTable(&b, compatible, gochatRoutes, "parameter-compatible")
b.WriteString("\n## Exact Critical Routes\n\n")
writeRouteTable(&b, exact, gochatRoutes, "exact")
return os.WriteFile(path, []byte(b.String()), 0o644)
}
func writeRouteTable(b *strings.Builder, routes []route, gochatRoutes map[string]route, status string) {
b.WriteString("| Method | Chatwoot Path | GoChat Match | Controller | Source | Status |\n")
b.WriteString("| --- | --- | --- | --- | --- | --- |\n")
if len(routes) == 0 {
b.WriteString("| - | - | - | - | - | none |\n")
return
}
for _, r := range routes {
match := "-"
if status == "exact" {
match = r.Path
} else if status == "method-compatible" {
match = methodCompatibleRoute(gochatRoutes, r)
} else if status == "parameter-compatible" {
match = compatiblePath(gochatRoutes, r)
}
b.WriteString(fmt.Sprintf("| %s | `%s` | `%s` | `%s` | `%s` | %s |\n", r.Method, r.Path, match, r.Controller, r.Source, status))
}
}
func hasMethodCompatible(routes map[string]route, expected route) bool {
return methodCompatibleRoute(routes, expected) != "-"
}
func methodCompatibleRoute(routes map[string]route, expected route) string {
for _, method := range compatibleMethods(expected.Method) {
if _, ok := routes[key(method, expected.Path)]; ok {
return method + " " + expected.Path
}
}
return "-"
}
func compatibleMethods(method string) []string {
switch method {
case "PUT":
return []string{"PATCH"}
case "PATCH":
return []string{"PUT"}
default:
return nil
}
}
func hasParamCompatible(routes map[string]route, expected route) bool {
return compatiblePath(routes, expected) != "-"
}
func compatiblePath(routes map[string]route, expected route) string {
normExpected := normalizeParams(expected.Path)
for _, r := range routes {
if r.Method == expected.Method && normalizeParams(r.Path) == normExpected {
return r.Path
}
}
return "-"
}
func normalizeParams(path string) string {
parts := strings.Split(path, "/")
for i, part := range parts {
if strings.HasPrefix(part, ":") {
parts[i] = ":param"
}
}
return strings.Join(parts, "/")
}
func key(method, path string) string {
return method + " " + path
}
func sortRoutes(routes []route) {
sort.Slice(routes, func(i, j int) bool {
if routes[i].Method != routes[j].Method {
return routes[i].Method < routes[j].Method
}
return routes[i].Path < routes[j].Path
})
}
func escapePipes(s string) string {
return strings.ReplaceAll(s, "|", "\\|")
}
func fatalIf(err error) {
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
+67 -20
View File
@@ -18,9 +18,24 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc
- `go test ./...` passes.
- Route dump succeeds with `TOTAL: 704`.
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
- First tracked frontend-critical API v1 route audit covers 81 Chatwoot routes: 76 exact, 2 method-compatible, 0 parameter-compatible, 3 missing.
- Handler test stability fixes are committed into the baseline before feature parity work continues.
- `.codegraph/` is generated indexing output and is not part of tracked product code.
## Execution Snapshot
| Phase | Name | Status | Blocking gaps |
| --- | --- | --- | --- |
| Phase 0 | Test and route baseline | Done | none |
| Phase 1 | Meilisearch search engine | Review | live Meilisearch integration and document-shape parity still need reference verification |
| Phase 2 | Route and controller parity audit | Doing | Ruby/Bundler unavailable, so Chatwoot route extraction currently uses static `routes.rb` fallback |
| Phase 3 | Data and serializer parity | Planned | needs route-gap priorities from Phase 2 |
| Phase 4 | Enterprise feature completion | Planned | excluded SSO family must stay out of scope; all other enterprise features remain included |
| Phase 5 | Background jobs and integrations | Planned | durable worker choice and job parity are open |
| Phase 6 | Core placeholder burn-down | Planned | placeholders must be converted into real Chatwoot-compatible behavior |
| Phase 7 | Verification harness | Planned | route/JSON/frontend smoke harness not complete |
## Phase 0: Test And Route Baseline
Status: done.
@@ -44,7 +59,7 @@ env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/d
## Phase 1: Meilisearch Search Engine
Status: next.
Status: review.
Source material:
@@ -54,15 +69,15 @@ Source material:
Checklist:
- [ ] Define a stable `SearchEngine` interface for Meilisearch-backed search and indexing.
- [ ] Add search config for engine, host, API key, and index prefix.
- [ ] Implement Meilisearch client wrapper with index bootstrapping and settings.
- [ ] Define per-entity documents for conversations, messages, contacts, companies, articles, and help-center content as required by Chatwoot frontend behavior.
- [ ] Wire create/update/delete hooks from services into indexing.
- [ ] Add batch reindex command for existing data.
- [ ] Keep DB search only as explicit development fallback, not as final production mode.
- [ ] Add tests with a mocked search engine and integration hooks that can run without a live Meilisearch instance.
- [ ] Document required Meilisearch environment variables and local startup flow.
- [x] Define a stable `SearchEngine` interface for Meilisearch-backed search and indexing.
- [x] Add search config for engine, host, API key, and index prefix.
- [x] Implement Meilisearch client wrapper with index bootstrapping and settings.
- [x] Define per-entity documents for conversations, messages, contacts, companies, articles, and help-center content as required by Chatwoot frontend behavior.
- [x] Wire create/update/delete hooks from services into indexing.
- [x] Add batch reindex command for existing data.
- [x] Keep DB search only as explicit development fallback, not as final production mode.
- [x] Add tests with a mocked search engine and integration hooks that can run without a live Meilisearch instance.
- [x] Document required Meilisearch environment variables and local startup flow.
Acceptance:
@@ -104,14 +119,15 @@ Search environment variables:
## Phase 2: Route And Controller Parity Audit
Status: planned.
Status: doing.
Checklist:
- [ ] Dump Chatwoot routes from `reference/chatwoot`.
- [ ] Dump GoChat routes with `cmd/dump_routes`.
- [ ] Build a tracked route parity table covering method, path, controller, auth scope, request params, and response serializer.
- [ ] Prioritize frontend-critical routes used by the Chatwoot web app.
- [x] Dump Chatwoot route source declarations from `reference/chatwoot/config/routes.rb`.
- [x] Dump GoChat routes with `cmd/dump_routes`.
- [x] Build a first tracked route parity table covering method, path, controller, source, and route status.
- [x] Prioritize first frontend-critical API v1 account routes used by the Chatwoot web app.
- [ ] Extend parity table with auth scope, request params, response serializer, and handler implementation status.
- [ ] Patch route names and wildcard params where Gin constraints require different internal names, while preserving external URLs.
- [ ] Add regression tests for route groups that previously conflicted.
@@ -125,13 +141,43 @@ Tracking table:
| ID | Task | Artifact | Status |
| --- | --- | --- | --- |
| P2.1 | Generate Chatwoot route dump from `reference/chatwoot`. | `docs/parity/chatwoot_routes.*` | Todo |
| P2.2 | Generate GoChat route dump with `cmd/dump_routes`. | `docs/parity/gochat_routes.*` | Todo |
| P2.3 | Produce route parity table: method, path, controller/handler, auth, request params, serializer, status. | `docs/parity/route_parity.md` | Todo |
| P2.4 | Mark frontend-critical gaps from Chatwoot web app route usage. | `docs/parity/route_parity.md` | Todo |
| P2.5 | Convert existing placeholders/stubs into tracked feature tasks instead of hidden debt. | this doc and gap report | Todo |
| P2.1 | Generate Chatwoot route dump from `reference/chatwoot`. | `docs/parity/chatwoot_routes_static.md` | Review |
| P2.2 | Generate GoChat route dump with `cmd/dump_routes`. | `docs/parity/gochat_routes.txt` | Done |
| P2.3 | Produce route parity table: method, path, controller/handler, auth, request params, serializer, status. | `docs/parity/route_parity.md` | Review |
| P2.4 | Mark frontend-critical gaps from Chatwoot web app route usage. | `docs/parity/route_parity.md` | Review |
| P2.5 | Convert existing placeholders/stubs into tracked feature tasks instead of hidden debt. | this doc and gap report | Doing |
| P2.6 | Add route boot regression tests for Gin wildcard/param conflicts. | router and handler tests | Todo |
Current Phase 2 route findings:
| Type | Count | Required action |
| --- | --- | --- |
| Exact tracked critical routes | 76 | Keep covered while expanding audit scope. |
| Method-compatible update routes | 2 | Register both Rails-compatible update methods or verify frontend only calls the implemented method. |
| Missing tracked critical routes | 3 | Implement exact Chatwoot external paths before frontend reuse. |
Missing tracked critical routes:
| Method | Path | Chatwoot controller | Required next task |
| --- | --- | --- | --- |
| GET | `/api/v1/accounts/:account_id/contacts/:contact_id/conversations` | `api/v1/accounts/contacts/conversations#index` | Add contact conversation relation endpoint and serializer parity test. |
| POST | `/api/v1/accounts/:account_id/contacts/export` | `api/v1/accounts/contacts#export` | Add POST export route; current GoChat has `GET /contacts/export`, which is not frontend-compatible. |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_priority` | `api/v1/accounts/conversations#toggle_priority` | Add Chatwoot action path; current GoChat has `PATCH /conversations/:conversation_id/priority`. |
Method-compatible routes requiring exact Rails method coverage:
| Expected | Existing GoChat route | Required next task |
| --- | --- | --- |
| `PUT /api/v1/accounts/:account_id/conversations/:conversation_id` | `PATCH /api/v1/accounts/:account_id/conversations/:conversation_id` | Add PUT alias or prove frontend only calls PATCH. |
| `PUT /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | `PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | Add PUT alias or prove frontend only calls PATCH. |
Phase 2 commands:
```bash
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/dump_routes > docs/parity/gochat_routes.txt
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/route_parity
```
## Phase 3: Data And Serializer Parity
Status: planned.
@@ -314,3 +360,4 @@ env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/d
- 2026-06-04: Baseline stabilized and committed as `42cdab8 chore: stabilize chatwoot parity baseline`; `go test ./...` passed and route dump reported `TOTAL: 704`.
- 2026-06-04: Phase 1 search foundation added: Meilisearch config/env defaults, `SearchEngine` contract, Meilisearch HTTP wrapper with bootstrap/settings, DB fallback adapter, document builders, reindex command, and no-live-Meilisearch tests. Verified `go test ./...` in unsandboxed mode because miniredis/httptest need local sockets; route dump still reports `TOTAL: 704`.
- 2026-06-04: Phase 1 indexing hooks wired for conversations, messages, contacts, companies, and articles. Create/update/delete paths now call the service-layer `SearchIndexer` boundary, bootstrap injects the Meilisearch-backed search service, and unit tests cover each entity hook path.
- 2026-06-04: Phase 2 route parity tracking added. Ruby/Bundler are unavailable in this workspace, so `cmd/route_parity` records static Chatwoot route DSL declarations from `reference/chatwoot/config/routes.rb`, consumes `cmd/dump_routes` output, and writes `docs/parity/route_parity.md`. First tracked critical route summary: 76 exact, 2 method-compatible, 0 parameter-compatible, 3 missing out of 81; GoChat route dump remains `TOTAL: 704`.
+426
View File
@@ -0,0 +1,426 @@
# Chatwoot Route Source Declarations
Source: `reference/chatwoot/config/routes.rb`
Ruby is unavailable in the current workspace, so this file records static route DSL declarations with source lines. It is a repeatable fallback until `bin/rails routes` can run.
| Line | Declaration |
| --- | --- |
| 3 | `mount_devise_token_auth_for 'User', at: 'auth', controllers: {` |
| 11 | `post 'resend_confirmation', to: 'auth/resend_confirmations#create'` |
| 19 | `get '/app', to: 'dashboard#index'` |
| 20 | `get '/app/*params', to: 'dashboard#index'` |
| 21 | `get '/app/accounts/:account_id/settings/inboxes/new/twitter', to: 'dashboard#index', as: 'app_new_twitter_inbox'` |
| 22 | `get '/app/accounts/:account_id/settings/inboxes/new/microsoft', to: 'dashboard#index', as: 'app_new_microsoft_inbox'` |
| 23 | `get '/app/accounts/:account_id/settings/inboxes/new/instagram', to: 'dashboard#index', as: 'app_new_instagram_inbox'` |
| 24 | `get '/app/accounts/:account_id/settings/inboxes/new/tiktok', to: 'dashboard#index', as: 'app_new_tiktok_inbox'` |
| 25 | `get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_twitter_inbox_agents'` |
| 26 | `get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_email_inbox_agents'` |
| 27 | `get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_instagram_inbox_agents'` |
| 28 | `get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_tiktok_inbox_agents'` |
| 29 | `get '/app/accounts/:account_id/settings/inboxes/:inbox_id', to: 'dashboard#index', as: 'app_instagram_inbox_settings'` |
| 30 | `get '/app/accounts/:account_id/settings/inboxes/:inbox_id', to: 'dashboard#index', as: 'app_tiktok_inbox_settings'` |
| 31 | `get '/app/accounts/:account_id/settings/inboxes/:inbox_id', to: 'dashboard#index', as: 'app_email_inbox_settings'` |
| 32 | `get '/app/accounts/:account_id/onboarding/inbox-setup', to: 'dashboard#index', as: 'app_onboarding_inbox_setup'` |
| 34 | `resource :widget, only: [:show]` |
| 35 | `namespace :survey do` |
| 36 | `resources :responses, only: [:show]` |
| 38 | `resource :slack_uploads, only: [:show]` |
| 41 | `get '/health', to: 'health#show'` |
| 42 | `get '/api', to: 'api#index'` |
| 43 | `namespace :api, defaults: { format: 'json' } do` |
| 44 | `namespace :v1 do` |
| 47 | `resources :accounts, only: [:create, :show, :update] do` |
| 49 | `post :update_active_at` |
| 50 | `get :cache_keys` |
| 53 | `scope module: :accounts do` |
| 54 | `namespace :actions do` |
| 55 | `resource :contact_merge, only: [:create]` |
| 57 | `resource :bulk_actions, only: [:create]` |
| 58 | `resource :onboarding, only: [:update]` |
| 59 | `resources :agents, only: [:index, :create, :update, :destroy] do` |
| 60 | `post :bulk_create, on: :collection` |
| 62 | `namespace :captain do` |
| 63 | `resource :preferences, only: [:show, :update]` |
| 64 | `resources :assistants do` |
| 66 | `post :playground` |
| 69 | `get :tools` |
| 71 | `resources :inboxes, only: [:index, :create, :destroy], param: :inbox_id` |
| 72 | `resources :scenarios` |
| 74 | `resources :assistant_responses` |
| 75 | `resources :bulk_actions, only: [:create]` |
| 76 | `resources :copilot_threads, only: [:index, :create] do` |
| 77 | `resources :copilot_messages, only: [:index, :create]` |
| 79 | `resources :custom_tools do` |
| 80 | `post :test, on: :collection` |
| 82 | `resources :documents, only: [:index, :show, :create, :destroy] do` |
| 83 | `post :sync, on: :member` |
| 85 | `resource :tasks, only: [], controller: 'tasks' do` |
| 86 | `post :rewrite` |
| 87 | `post :summarize` |
| 88 | `post :reply_suggestion` |
| 89 | `post :label_suggestion` |
| 90 | `post :follow_up` |
| 93 | `resource :saml_settings, only: [:show, :create, :update, :destroy]` |
| 94 | `resources :agent_bots, only: [:index, :create, :show, :update, :destroy] do` |
| 95 | `delete :avatar, on: :member` |
| 96 | `post :reset_access_token, on: :member` |
| 97 | `post :reset_secret, on: :member` |
| 99 | `resources :contact_inboxes, only: [] do` |
| 101 | `post :filter` |
| 104 | `resources :assignable_agents, only: [:index]` |
| 105 | `resource :audit_logs, only: [:show]` |
| 106 | `resources :callbacks, only: [] do` |
| 108 | `post :register_facebook_page` |
| 109 | `get :register_facebook_page` |
| 110 | `post :facebook_pages` |
| 111 | `post :reauthorize_page` |
| 114 | `resources :canned_responses, only: [:index, :create, :update, :destroy]` |
| 115 | `resources :automation_rules, only: [:index, :create, :show, :update, :destroy] do` |
| 116 | `post :clone` |
| 118 | `resources :macros, only: [:index, :create, :show, :update, :destroy] do` |
| 119 | `post :execute, on: :member` |
| 121 | `resources :sla_policies, only: [:index, :create, :show, :update, :destroy]` |
| 122 | `resources :custom_roles, only: [:index, :create, :show, :update, :destroy]` |
| 123 | `resources :agent_capacity_policies, only: [:index, :create, :show, :update, :destroy] do` |
| 124 | `scope module: :agent_capacity_policies do` |
| 125 | `resources :users, only: [:index, :create, :destroy]` |
| 126 | `resources :inbox_limits, only: [:create, :update, :destroy]` |
| 129 | `resources :campaigns, only: [:index, :create, :show, :update, :destroy]` |
| 130 | `resources :dashboard_apps, only: [:index, :show, :create, :update, :destroy]` |
| 131 | `namespace :channels do` |
| 132 | `resource :twilio_channel, only: [:create]` |
| 134 | `resources :conversations, only: [:index, :create, :show, :update, :destroy] do` |
| 136 | `get :meta` |
| 137 | `get :search` |
| 138 | `get :unread_counts, to: 'conversations/unread_counts#index'` |
| 139 | `post :filter` |
| 141 | `scope module: :conversations do` |
| 142 | `resources :messages, only: [:index, :create, :destroy, :update] do` |
| 144 | `post :translate` |
| 145 | `post :retry` |
| 148 | `resources :assignments, only: [:create]` |
| 149 | `resources :labels, only: [:create, :index]` |
| 150 | `resource :participants, only: [:show, :create, :update, :destroy]` |
| 151 | `resource :direct_uploads, only: [:create]` |
| 152 | `resource :draft_messages, only: [:show, :update, :destroy]` |
| 155 | `post :mute` |
| 156 | `post :unmute` |
| 157 | `post :transcript` |
| 158 | `post :toggle_status` |
| 159 | `post :toggle_priority` |
| 160 | `post :toggle_typing_status` |
| 161 | `post :update_last_seen` |
| 162 | `post :unread` |
| 163 | `post :custom_attributes` |
| 164 | `get :attachments` |
| 165 | `get :inbox_assistant` |
| 166 | `get :reporting_events if ChatwootApp.enterprise?` |
| 170 | `resources :search, only: [:index] do` |
| 172 | `get :conversations` |
| 173 | `get :messages` |
| 174 | `get :contacts` |
| 175 | `get :articles` |
| 179 | `resources :companies, only: [:index, :show, :create, :update, :destroy] do` |
| 181 | `get :search` |
| 184 | `post :destroy_custom_attributes` |
| 185 | `delete :avatar` |
| 187 | `scope module: :companies do` |
| 188 | `resources :contacts, only: [:index, :create, :destroy] do` |
| 190 | `get :search` |
| 193 | `resources :conversations, only: [:index]` |
| 194 | `resources :notes, only: [:index]` |
| 197 | `resources :contacts, only: [:index, :show, :update, :create, :destroy] do` |
| 199 | `get :active` |
| 200 | `get :search` |
| 201 | `post :filter` |
| 202 | `post :import` |
| 203 | `post :export` |
| 206 | `get :contactable_inboxes` |
| 207 | `post :destroy_custom_attributes` |
| 208 | `delete :avatar` |
| 210 | `scope module: :contacts do` |
| 211 | `resources :conversations, only: [:index]` |
| 212 | `resources :contact_inboxes, only: [:create]` |
| 213 | `resources :labels, only: [:create, :index]` |
| 214 | `resources :notes` |
| 215 | `get :attachments, to: 'attachments#index'` |
| 216 | `post :call, on: :member, to: 'calls#create' if ChatwootApp.enterprise?` |
| 219 | `resources :csat_survey_responses, only: [:index] do` |
| 221 | `get :metrics` |
| 222 | `get :download` |
| 225 | `patch :update if ChatwootApp.enterprise?` |
| 228 | `resources :applied_slas, only: [:index] do` |
| 230 | `get :metrics` |
| 231 | `get :download` |
| 234 | `resources :reporting_events, only: [:index] if ChatwootApp.enterprise?` |
| 237 | `resources :whatsapp_calls, only: [:show] do` |
| 239 | `post :accept` |
| 240 | `post :reject` |
| 241 | `post :terminate` |
| 242 | `post :upload_recording` |
| 245 | `post :initiate` |
| 250 | `resources :custom_attribute_definitions, only: [:index, :show, :create, :update, :destroy]` |
| 251 | `resources :custom_filters, only: [:index, :show, :create, :update, :destroy]` |
| 252 | `resources :inboxes, only: [:index, :show, :create, :update, :destroy] do` |
| 253 | `get :assignable_agents, on: :member` |
| 254 | `get :campaigns, on: :member` |
| 255 | `get :agent_bot, on: :member` |
| 256 | `post :set_agent_bot, on: :member` |
| 257 | `delete :avatar, on: :member` |
| 258 | `post :sync_templates, on: :member` |
| 259 | `get :health, on: :member` |
| 260 | `post :register_webhook, on: :member` |
| 261 | `post :reset_secret, on: :member` |
| 263 | `resource :conference, only: %i[create destroy], controller: 'conference' do` |
| 264 | `get :token, on: :member` |
| 266 | `post :enable_whatsapp_calling, on: :member` |
| 267 | `post :disable_whatsapp_calling, on: :member` |
| 270 | `resource :csat_template, only: [:show, :create], controller: 'inbox_csat_templates' do` |
| 271 | `post :analyze, on: :collection` |
| 275 | `resources :inbox_members, only: [:create, :show], param: :inbox_id do` |
| 277 | `delete :destroy` |
| 278 | `patch :update` |
| 281 | `resources :labels, only: [:index, :show, :create, :update, :destroy]` |
| 283 | `resources :notifications, only: [:index, :update, :destroy] do` |
| 285 | `post :read_all` |
| 286 | `get :unread_count` |
| 287 | `post :destroy_all` |
| 290 | `post :snooze` |
| 291 | `post :unread` |
| 294 | `resource :notification_settings, only: [:show, :update]` |
| 296 | `resources :teams do` |
| 297 | `resources :team_members, only: [:index, :create] do` |
| 299 | `delete :destroy` |
| 300 | `patch :update` |
| 306 | `resources :assignment_policies do` |
| 307 | `resources :inboxes, only: [:index, :create, :destroy], module: :assignment_policies` |
| 310 | `resources :inboxes, only: [] do` |
| 311 | `resource :assignment_policy, only: [:show, :create, :destroy], module: :inboxes` |
| 314 | `namespace :twitter do` |
| 315 | `resource :authorization, only: [:create]` |
| 318 | `namespace :microsoft do` |
| 319 | `resource :authorization, only: [:create]` |
| 322 | `namespace :google do` |
| 323 | `resource :authorization, only: [:create]` |
| 326 | `namespace :instagram do` |
| 327 | `resource :authorization, only: [:create]` |
| 330 | `namespace :tiktok do` |
| 331 | `resource :authorization, only: [:create]` |
| 334 | `namespace :notion do` |
| 335 | `resource :authorization, only: [:create]` |
| 338 | `namespace :whatsapp do` |
| 339 | `resource :authorization, only: [:create]` |
| 342 | `resources :webhooks, only: [:index, :create, :update, :destroy]` |
| 343 | `namespace :integrations do` |
| 344 | `resources :apps, only: [:index, :show]` |
| 345 | `resources :hooks, only: [:show, :create, :update, :destroy] do` |
| 347 | `post :process_event` |
| 350 | `resource :slack, only: [:create, :update, :destroy], controller: 'slack' do` |
| 352 | `get :list_all_channels` |
| 355 | `resource :dyte, controller: 'dyte', only: [] do` |
| 357 | `post :create_a_meeting` |
| 358 | `post :add_participant_to_meeting` |
| 361 | `resource :shopify, controller: 'shopify', only: [:destroy] do` |
| 363 | `post :auth` |
| 364 | `get :orders` |
| 367 | `resource :linear, controller: 'linear', only: [] do` |
| 369 | `delete :destroy` |
| 370 | `get :teams` |
| 371 | `get :team_entities` |
| 372 | `post :create_issue` |
| 373 | `post :link_issue` |
| 374 | `post :unlink_issue` |
| 375 | `get :search_issue` |
| 376 | `get :linked_issues` |
| 379 | `resource :notion, controller: 'notion', only: [] do` |
| 381 | `delete :destroy` |
| 385 | `resources :portals do` |
| 387 | `patch :archive` |
| 388 | `delete :logo` |
| 389 | `post :send_instructions` |
| 390 | `get :ssl_status` |
| 392 | `resources :categories do` |
| 393 | `post :reorder, on: :collection` |
| 395 | `namespace :articles do` |
| 396 | `resource :bulk_actions, only: [] do` |
| 397 | `post :translate` |
| 398 | `patch :update_status` |
| 399 | `patch :update_category` |
| 400 | `delete :delete_articles` |
| 403 | `resources :articles do` |
| 404 | `post :reorder, on: :collection` |
| 408 | `resources :upload, only: [:create]` |
| 414 | `namespace :integrations do` |
| 415 | `resources :webhooks, only: [:create]` |
| 419 | `post 'auth/saml_login', to: 'auth#saml_login'` |
| 421 | `resource :profile, only: [:show, :update] do` |
| 422 | `delete :avatar, on: :collection` |
| 424 | `post :availability` |
| 425 | `post :auto_offline` |
| 426 | `put :set_active_account` |
| 427 | `post :resend_confirmation` |
| 428 | `post :reset_access_token` |
| 432 | `scope module: 'profile' do` |
| 433 | `resource :mfa, controller: 'mfa', only: [:show, :create, :destroy] do` |
| 434 | `post :verify` |
| 435 | `post :backup_codes` |
| 440 | `resource :notification_subscriptions, only: [:create, :destroy]` |
| 442 | `namespace :widget do` |
| 443 | `resource :direct_uploads, only: [:create]` |
| 444 | `resource :config, only: [:create]` |
| 445 | `resources :campaigns, only: [:index]` |
| 446 | `resources :events, only: [:create]` |
| 447 | `resources :messages, only: [:index, :create, :update]` |
| 448 | `resources :conversations, only: [:index, :create] do` |
| 450 | `post :destroy_custom_attributes` |
| 451 | `post :set_custom_attributes` |
| 452 | `post :update_last_seen` |
| 453 | `post :toggle_typing` |
| 454 | `post :transcript` |
| 455 | `get :toggle_status` |
| 458 | `resource :contact, only: [:show, :update] do` |
| 460 | `post :destroy_custom_attributes` |
| 461 | `patch :set_user` |
| 464 | `resources :inbox_members, only: [:index]` |
| 465 | `resources :labels, only: [:create, :destroy]` |
| 466 | `namespace :integrations do` |
| 467 | `resource :dyte, controller: 'dyte', only: [] do` |
| 469 | `post :add_participant_to_meeting` |
| 476 | `namespace :v2 do` |
| 477 | `resources :accounts, only: [:create] do` |
| 478 | `scope module: :accounts do` |
| 479 | `resources :summary_reports, only: [] do` |
| 481 | `get :agent` |
| 482 | `get :team` |
| 483 | `get :inbox` |
| 484 | `get :label` |
| 485 | `get :channel` |
| 488 | `resources :reports, only: [:index] do` |
| 490 | `get :summary` |
| 491 | `get :bot_summary` |
| 492 | `get :agents` |
| 493 | `get :inboxes` |
| 494 | `get :labels` |
| 495 | `get :teams` |
| 496 | `get :conversations` |
| 497 | `get :conversations_summary` |
| 498 | `get :conversation_traffic` |
| 499 | `get :bot_metrics` |
| 500 | `get :inbox_label_matrix` |
| 501 | `get :first_response_time_distribution` |
| 502 | `get :outgoing_messages_count` |
| 505 | `resource :year_in_review, only: [:show]` |
| 506 | `resources :live_reports, only: [] do` |
| 508 | `get :conversation_metrics` |
| 509 | `get :grouped_conversation_metrics` |
| 518 | `namespace :enterprise, defaults: { format: 'json' } do` |
| 519 | `namespace :api do` |
| 520 | `namespace :v1 do` |
| 521 | `resources :accounts do` |
| 523 | `post :checkout` |
| 524 | `post :subscription` |
| 525 | `get :limits` |
| 526 | `post :toggle_deletion` |
| 527 | `post :topup_checkout` |
| 533 | `post 'webhooks/stripe', to: 'webhooks/stripe#process_payload'` |
| 534 | `post 'webhooks/firecrawl', to: 'webhooks/firecrawl#process_payload'` |
| 540 | `namespace :platform, defaults: { format: 'json' } do` |
| 541 | `namespace :api do` |
| 542 | `namespace :v1 do` |
| 543 | `resources :users, only: [:create, :show, :update, :destroy] do` |
| 545 | `get :login` |
| 546 | `post :token` |
| 549 | `resources :agent_bots, only: [:index, :create, :show, :update, :destroy] do` |
| 550 | `delete :avatar, on: :member` |
| 552 | `resources :accounts, only: [:index, :create, :show, :update, :destroy] do` |
| 553 | `resources :account_users, only: [:index, :create] do` |
| 555 | `delete :destroy` |
| 558 | `resources :email_channel_migrations, only: [:create]` |
| 566 | `namespace :public, defaults: { format: 'json' } do` |
| 567 | `namespace :api do` |
| 568 | `namespace :v1 do` |
| 569 | `resources :inboxes do` |
| 570 | `scope module: :inboxes do` |
| 571 | `resources :contacts, only: [:create, :show, :update] do` |
| 572 | `resources :conversations, only: [:index, :create, :show] do` |
| 574 | `post :toggle_status` |
| 575 | `post :toggle_typing` |
| 576 | `post :update_last_seen` |
| 579 | `resources :messages, only: [:index, :create, :update]` |
| 585 | `resources :csat_survey, only: [:show, :update]` |
| 590 | `get 'hc/:slug', to: 'public/api/v1/portals#show'` |
| 591 | `get 'hc/:slug/sitemap.xml', to: 'public/api/v1/portals#sitemap'` |
| 592 | `get 'hc/:slug/:locale', to: 'public/api/v1/portals#show', as: :public_portal_locale` |
| 593 | `get 'hc/:slug/:locale/search', to: 'public/api/v1/portals/search#index', as: :portal_search` |
| 594 | `get 'hc/:slug/:locale/articles', to: 'public/api/v1/portals/articles#index'` |
| 595 | `get 'hc/:slug/:locale/categories', to: 'public/api/v1/portals/categories#index'` |
| 596 | `get 'hc/:slug/:locale/categories/:category_slug', to: 'public/api/v1/portals/categories#show', as: :public_portal_category` |
| 597 | `get 'hc/:slug/:locale/categories/:category_slug/articles', to: 'public/api/v1/portals/articles#index'` |
| 598 | `get 'hc/:slug/articles/:article_slug.png', to: 'public/api/v1/portals/articles#tracking_pixel'` |
| 599 | `get 'hc/:slug/articles/:article_slug.md', to: 'public/api/v1/portals/articles#show_markdown', as: :public_portal_article_markdown,` |
| 601 | `get 'hc/:slug/articles/:article_slug', to: 'public/api/v1/portals/articles#show', as: :public_portal_article` |
| 605 | `resource :app, only: [:index] do` |
| 606 | `resources :accounts do` |
| 607 | `resources :conversations, only: [:show]` |
| 613 | `mount Facebook::Messenger::Server, at: 'bot'` |
| 614 | `get 'webhooks/twitter', to: 'api/v1/webhooks#twitter_crc'` |
| 615 | `post 'webhooks/twitter', to: 'api/v1/webhooks#twitter_events'` |
| 616 | `post 'webhooks/line/:line_channel_id', to: 'webhooks/line#process_payload'` |
| 617 | `post 'webhooks/telegram/:bot_token', to: 'webhooks/telegram#process_payload'` |
| 618 | `post 'webhooks/sms/:phone_number', to: 'webhooks/sms#process_payload'` |
| 619 | `get 'webhooks/whatsapp/:phone_number', to: 'webhooks/whatsapp#verify'` |
| 620 | `post 'webhooks/whatsapp/:phone_number', to: 'webhooks/whatsapp#process_payload'` |
| 621 | `get 'webhooks/instagram', to: 'webhooks/instagram#verify'` |
| 622 | `post 'webhooks/instagram', to: 'webhooks/instagram#events'` |
| 623 | `post 'webhooks/tiktok', to: 'webhooks/tiktok#events'` |
| 624 | `post 'webhooks/shopify', to: 'webhooks/shopify#events'` |
| 626 | `namespace :twitter do` |
| 627 | `resource :callback, only: [:show]` |
| 630 | `namespace :linear do` |
| 631 | `resource :callback, only: [:show]` |
| 634 | `namespace :shopify do` |
| 635 | `resource :callback, only: [:show]` |
| 638 | `namespace :twilio do` |
| 639 | `resources :callback, only: [:create]` |
| 640 | `resources :delivery_status, only: [:create]` |
| 643 | `post 'voice/call/:phone', to: 'voice#call_twiml', as: :voice_call` |
| 644 | `post 'voice/status/:phone', to: 'voice#status', as: :voice_status` |
| 645 | `post 'voice/conference_status/:phone', to: 'voice#conference_status', as: :voice_conference_status` |
| 646 | `post 'voice/recording_status/:phone', to: 'voice#recording_status', as: :voice_recording_status` |
| 650 | `get 'microsoft/callback', to: 'microsoft/callbacks#show'` |
| 651 | `get 'google/callback', to: 'google/callbacks#show'` |
| 652 | `get 'instagram/callback', to: 'instagram/callbacks#show'` |
| 653 | `get 'tiktok/callback', to: 'tiktok/callbacks#show'` |
| 654 | `get 'notion/callback', to: 'notion/callbacks#show'` |
| 657 | `get '.well-known/assetlinks.json' => 'android_app#assetlinks'` |
| 658 | `get '.well-known/apple-app-site-association' => 'apple_app#site_association'` |
| 659 | `get '.well-known/microsoft-identity-association.json' => 'microsoft#identity_association'` |
| 660 | `get '.well-known/cf-custom-hostname-challenge/:id', to: 'custom_domains#verify'` |
| 669 | `get 'super_admin/logout', to: 'super_admin/devise/sessions#destroy'` |
| 670 | `namespace :super_admin do` |
| 673 | `resource :app_config, only: [:show, :create]` |
| 674 | `resource :push_diagnostics, only: [:show, :create] do` |
| 675 | `post :destroy_subscriptions, on: :collection` |
| 679 | `resources :accounts, only: [:index, :new, :create, :show, :edit, :update, :destroy] do` |
| 680 | `post :seed, on: :member` |
| 681 | `post :reset_cache, on: :member` |
| 683 | `resources :users, only: [:index, :new, :create, :show, :edit, :update, :destroy] do` |
| 684 | `delete :avatar, on: :member, action: :destroy_avatar` |
| 687 | `resources :access_tokens, only: [:index, :show]` |
| 688 | `resources :installation_configs, only: [:index, :new, :create, :show, :edit, :update]` |
| 689 | `resources :agent_bots, only: [:index, :new, :create, :show, :edit, :update, :destroy] do` |
| 690 | `delete :avatar, on: :member, action: :destroy_avatar` |
| 692 | `resources :platform_apps, only: [:index, :new, :create, :show, :edit, :update, :destroy]` |
| 693 | `resources :platform_banners` |
| 694 | `resource :instance_status, only: [:show]` |
| 696 | `resource :settings, only: [:show] do` |
| 697 | `get :refresh, on: :collection` |
| 701 | `resources :account_users, only: [:new, :create, :show, :destroy]` |
| 704 | `mount Sidekiq::Web => '/monitoring/sidekiq'` |
| 708 | `namespace :installation do` |
| 709 | `get 'onboarding', to: 'onboarding#index'` |
| 710 | `post 'onboarding', to: 'onboarding#create'` |
| 715 | `get '/swagger/*path', to: 'swagger#respond'` |
| 716 | `get '/swagger', to: 'swagger#respond'` |
| 720 | `resources :widget_tests, only: [:index] unless Rails.env.production?` |
+705
View File
@@ -0,0 +1,705 @@
CONNECT /webhooks/:channel_type/:identifier
DELETE /api/v1/accounts/:account_id
DELETE /api/v1/accounts/:account_id/agent_bot_inboxes/:agent_bot_inbox_id
DELETE /api/v1/accounts/:account_id/agent_bots/:agent_bot_id
DELETE /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/avatar
DELETE /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/bot_rules/:rule_id
DELETE /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/trigger_configs/:trigger_config_id
DELETE /api/v1/accounts/:account_id/agent_capacity_policies/:id
DELETE /api/v1/accounts/:account_id/agents/:agent_id
DELETE /api/v1/accounts/:account_id/assignment_policies/:policy_id
DELETE /api/v1/accounts/:account_id/assignment_policies/:policy_id/inboxes/:inbox_id
DELETE /api/v1/accounts/:account_id/assignment_policies_v2/:id
DELETE /api/v1/accounts/:account_id/assignment_policies_v2/:id/inboxes/:inbox_id
DELETE /api/v1/accounts/:account_id/assignment_policy/:policy_id
DELETE /api/v1/accounts/:account_id/automation_rules/:automation_id
DELETE /api/v1/accounts/:account_id/campaigns/:campaign_id
DELETE /api/v1/accounts/:account_id/canned_responses/:id
DELETE /api/v1/accounts/:account_id/captain/assistant_responses/:response_id
DELETE /api/v1/accounts/:account_id/captain/assistants/:assistant_id
DELETE /api/v1/accounts/:account_id/captain/assistants/:assistant_id/documents/:document_id
DELETE /api/v1/accounts/:account_id/captain/assistants/:assistant_id/inboxes/:inbox_id
DELETE /api/v1/accounts/:account_id/captain/assistants/:assistant_id/scenarios/:scenario_id
DELETE /api/v1/accounts/:account_id/captain/copilot_threads/:thread_id
DELETE /api/v1/accounts/:account_id/captain/custom_tools/:tool_id
DELETE /api/v1/accounts/:account_id/captain/documents/:document_id
DELETE /api/v1/accounts/:account_id/captain/preferences/
DELETE /api/v1/accounts/:account_id/captain/scenarios/:scenario_id
DELETE /api/v1/accounts/:account_id/channels/facebook_channel/:fb_id
DELETE /api/v1/accounts/:account_id/companies/:company_id
DELETE /api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id
DELETE /api/v1/accounts/:account_id/companies/:company_id/notes/:note_id
DELETE /api/v1/accounts/:account_id/contacts/:contact_id
DELETE /api/v1/accounts/:account_id/contacts/:contact_id/contact_inboxes/:inbox_id
DELETE /api/v1/accounts/:account_id/contacts/:contact_id/custom_attributes
DELETE /api/v1/accounts/:account_id/contacts/:contact_id/custom_attributes/:attribute_name
DELETE /api/v1/accounts/:account_id/contacts/:contact_id/notes/:note_id
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/custom_attributes/:attribute_name
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages/:draft_id
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/labels/:tag_id
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/participants/:user_id
DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/whatsapp_calls/:call_id
DELETE /api/v1/accounts/:account_id/custom_attribute_definitions/:id
DELETE /api/v1/accounts/:account_id/custom_filters/:id
DELETE /api/v1/accounts/:account_id/custom_roles/:id
DELETE /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id
DELETE /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id/widgets/:widget_index
DELETE /api/v1/accounts/:account_id/google_channels/:google_id
DELETE /api/v1/accounts/:account_id/hooks/:id
DELETE /api/v1/accounts/:account_id/inbox_members/:user_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy/:policy_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy_v2/
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/avatar
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/email_channels/:em_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/inbox_limits/:id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_channels/:ig_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_comments/:comment_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/line_channels/:line_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/members/:user_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/tiktok_channels/:tt_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/twilio_sms_channels/:tw_id
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/pre_chat_form
DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/theme_config
DELETE /api/v1/accounts/:account_id/integrations/hooks/:id
DELETE /api/v1/accounts/:account_id/integrations/linear/
DELETE /api/v1/accounts/:account_id/integrations/notion/
DELETE /api/v1/accounts/:account_id/integrations/shopify/
DELETE /api/v1/accounts/:account_id/integrations/slack/
DELETE /api/v1/accounts/:account_id/labels/:tag_id
DELETE /api/v1/accounts/:account_id/macros/:macro_id
DELETE /api/v1/accounts/:account_id/microsoft_channels/:ms_id
DELETE /api/v1/accounts/:account_id/notification_subscriptions/:identifier
DELETE /api/v1/accounts/:account_id/platform_apps/:platform_app_id
DELETE /api/v1/accounts/:account_id/platform_apps/:platform_app_id/permissibles/:permissible_id
DELETE /api/v1/accounts/:account_id/portals/:portal_id
DELETE /api/v1/accounts/:account_id/portals/:portal_id/articles/:article_id
DELETE /api/v1/accounts/:account_id/portals/:portal_id/categories/:category_id
DELETE /api/v1/accounts/:account_id/portals/:portal_id/folders/:folder_id
DELETE /api/v1/accounts/:account_id/portals/:portal_id/logo
DELETE /api/v1/accounts/:account_id/portals/:portal_id/members/:member_id
DELETE /api/v1/accounts/:account_id/saml_settings/:id
DELETE /api/v1/accounts/:account_id/sla_policies/:id
DELETE /api/v1/accounts/:account_id/sla_policies/:id/inboxes/:inbox_id
DELETE /api/v1/accounts/:account_id/tags/:tag_id
DELETE /api/v1/accounts/:account_id/teams/:team_id
DELETE /api/v1/accounts/:account_id/teams/:team_id/team_members/
DELETE /api/v1/accounts/:account_id/twitter_channels/:twitter_id
DELETE /api/v1/accounts/:account_id/users/:user_id
DELETE /api/v1/accounts/:account_id/webhooks/:webhook_id
DELETE /api/v1/auth/logout
DELETE /api/v1/notification_subscriptions/:identifier
DELETE /api/v1/notifications/:id
DELETE /api/v1/notifications/destroy_all
DELETE /api/v1/profile/avatar
DELETE /api/v1/profile/mfa/
DELETE /api/v1/push_subscriptions/:id
DELETE /platform/api/v1/accounts/:account_id
DELETE /platform/api/v1/accounts/:account_id/account_users/:user_id
DELETE /platform/api/v1/agent_bots/:id
DELETE /platform/api/v1/apps/:id
DELETE /platform/api/v1/apps/:id/permissibles/:permissible_id
DELETE /platform/api/v1/banners/:id
DELETE /platform/api/v1/installation_configs/:id
DELETE /platform/api/v1/users/:id
DELETE /webhooks/:channel_type/:identifier
GET /api/v1/accounts/
GET /api/v1/accounts/:account_id
GET /api/v1/accounts/:account_id/agent_bot_inboxes/
GET /api/v1/accounts/:account_id/agent_bot_inboxes/by_bot
GET /api/v1/accounts/:account_id/agent_bots/
GET /api/v1/accounts/:account_id/agent_bots/:agent_bot_id
GET /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/bot_rules/
GET /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/bot_rules/:rule_id
GET /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/trigger_configs/
GET /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/trigger_configs/:trigger_config_id
GET /api/v1/accounts/:account_id/agent_capacity_policies/
GET /api/v1/accounts/:account_id/agent_capacity_policies/:id
GET /api/v1/accounts/:account_id/agents
GET /api/v1/accounts/:account_id/agents/:agent_id
GET /api/v1/accounts/:account_id/applied_slas/download
GET /api/v1/accounts/:account_id/applied_slas/metrics
GET /api/v1/accounts/:account_id/assignable_agents
GET /api/v1/accounts/:account_id/assignment_policies/
GET /api/v1/accounts/:account_id/assignment_policies/:policy_id
GET /api/v1/accounts/:account_id/assignment_policies/:policy_id/inboxes
GET /api/v1/accounts/:account_id/assignment_policies_v2
GET /api/v1/accounts/:account_id/assignment_policies_v2/:id
GET /api/v1/accounts/:account_id/assignment_policies_v2/:id/inboxes
GET /api/v1/accounts/:account_id/assignment_policy
GET /api/v1/accounts/:account_id/audit_logs/
GET /api/v1/accounts/:account_id/audit_logs/:id
GET /api/v1/accounts/:account_id/automation_rules/
GET /api/v1/accounts/:account_id/automation_rules/:automation_id
GET /api/v1/accounts/:account_id/banners
GET /api/v1/accounts/:account_id/cache_keys
GET /api/v1/accounts/:account_id/campaigns/
GET /api/v1/accounts/:account_id/campaigns/:campaign_id
GET /api/v1/accounts/:account_id/canned_responses/
GET /api/v1/accounts/:account_id/canned_responses/:id
GET /api/v1/accounts/:account_id/canned_responses/search
GET /api/v1/accounts/:account_id/captain/assistant_responses/
GET /api/v1/accounts/:account_id/captain/assistant_responses/:response_id
GET /api/v1/accounts/:account_id/captain/assistants/
GET /api/v1/accounts/:account_id/captain/assistants/:assistant_id
GET /api/v1/accounts/:account_id/captain/assistants/:assistant_id/documents/
GET /api/v1/accounts/:account_id/captain/assistants/:assistant_id/documents/:document_id
GET /api/v1/accounts/:account_id/captain/assistants/:assistant_id/inboxes
GET /api/v1/accounts/:account_id/captain/assistants/:assistant_id/scenarios/
GET /api/v1/accounts/:account_id/captain/assistants/:assistant_id/scenarios/:scenario_id
GET /api/v1/accounts/:account_id/captain/assistants/tools
GET /api/v1/accounts/:account_id/captain/copilot/stream
GET /api/v1/accounts/:account_id/captain/copilot_messages/
GET /api/v1/accounts/:account_id/captain/copilot_threads/
GET /api/v1/accounts/:account_id/captain/copilot_threads/:thread_id
GET /api/v1/accounts/:account_id/captain/copilot_threads/:thread_id/copilot_messages/
GET /api/v1/accounts/:account_id/captain/custom_tools/
GET /api/v1/accounts/:account_id/captain/custom_tools/:tool_id
GET /api/v1/accounts/:account_id/captain/documents/
GET /api/v1/accounts/:account_id/captain/documents/:document_id
GET /api/v1/accounts/:account_id/captain/preferences/
GET /api/v1/accounts/:account_id/captain/scenarios/
GET /api/v1/accounts/:account_id/captain/scenarios/:scenario_id
GET /api/v1/accounts/:account_id/captain/tasks/follow_up
GET /api/v1/accounts/:account_id/captain/tasks/label_suggestion
GET /api/v1/accounts/:account_id/channels/facebook_channel/:fb_id
GET /api/v1/accounts/:account_id/channels/facebook_channel/authorization
GET /api/v1/accounts/:account_id/companies/
GET /api/v1/accounts/:account_id/companies/:company_id
GET /api/v1/accounts/:account_id/companies/:company_id/contacts
GET /api/v1/accounts/:account_id/companies/:company_id/conversations
GET /api/v1/accounts/:account_id/companies/:company_id/notes
GET /api/v1/accounts/:account_id/companies/search
GET /api/v1/accounts/:account_id/contact_inboxes/filter
GET /api/v1/accounts/:account_id/contacts/
GET /api/v1/accounts/:account_id/contacts/:contact_id
GET /api/v1/accounts/:account_id/contacts/:contact_id/contact_inboxes
GET /api/v1/accounts/:account_id/contacts/:contact_id/contactable_inboxes
GET /api/v1/accounts/:account_id/contacts/:contact_id/notes
GET /api/v1/accounts/:account_id/contacts/:contact_id/notes/:note_id
GET /api/v1/accounts/:account_id/contacts/active
GET /api/v1/accounts/:account_id/contacts/export
GET /api/v1/accounts/:account_id/contacts/search
GET /api/v1/accounts/:account_id/conversations/
GET /api/v1/accounts/:account_id/conversations/:conversation_id
GET /api/v1/accounts/:account_id/conversations/:conversation_id/attachments
GET /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages/
GET /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages/:draft_id
GET /api/v1/accounts/:account_id/conversations/:conversation_id/labels
GET /api/v1/accounts/:account_id/conversations/:conversation_id/messages/
GET /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id
GET /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/delivery_status/
GET /api/v1/accounts/:account_id/conversations/:conversation_id/participants/
GET /api/v1/accounts/:account_id/conversations/:conversation_id/whatsapp_calls/
GET /api/v1/accounts/:account_id/conversations/:conversation_id/whatsapp_calls/:call_id
GET /api/v1/accounts/:account_id/conversations/meta
GET /api/v1/accounts/:account_id/conversations/search
GET /api/v1/accounts/:account_id/conversations/unread_counts
GET /api/v1/accounts/:account_id/csat_survey_responses/
GET /api/v1/accounts/:account_id/csat_survey_responses/download
GET /api/v1/accounts/:account_id/csat_survey_responses/metrics
GET /api/v1/accounts/:account_id/custom_attribute_definitions/
GET /api/v1/accounts/:account_id/custom_attribute_definitions/:id
GET /api/v1/accounts/:account_id/custom_filters/
GET /api/v1/accounts/:account_id/custom_filters/:id
GET /api/v1/accounts/:account_id/custom_roles/
GET /api/v1/accounts/:account_id/custom_roles/:id
GET /api/v1/accounts/:account_id/dashboard_apps
GET /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id
GET /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id/widgets
GET /api/v1/accounts/:account_id/dashboard_apps/search
GET /api/v1/accounts/:account_id/draft_messages/count
GET /api/v1/accounts/:account_id/draft_messages/search
GET /api/v1/accounts/:account_id/email_channel_migrations/
GET /api/v1/accounts/:account_id/email_channels/
GET /api/v1/accounts/:account_id/google/callback
GET /api/v1/accounts/:account_id/google/oauth
GET /api/v1/accounts/:account_id/google/webhooks
GET /api/v1/accounts/:account_id/google_channels/authorization
GET /api/v1/accounts/:account_id/hooks/
GET /api/v1/accounts/:account_id/hooks/:id
GET /api/v1/accounts/:account_id/inboxes/
GET /api/v1/accounts/:account_id/inboxes/:inbox_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/agent_bot
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/assignable_agents
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy/
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy_v2/
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/campaigns
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/csat_template
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/email_channels/:em_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/health
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_channels/:ig_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_comments/:comment_id/replies
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_comments/media/:media_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/line_channels/:line_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/members
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/out_of_office
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/tiktok_channels/:tt_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/twilio_sms_channels/:tw_id
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/offline_messages
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/pre_chat_form
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/theme_config
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget_config
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/working_hours
GET /api/v1/accounts/:account_id/instagram/callback
GET /api/v1/accounts/:account_id/instagram/oauth
GET /api/v1/accounts/:account_id/instagram/webhooks
GET /api/v1/accounts/:account_id/instagram_channels/
GET /api/v1/accounts/:account_id/integrations/apps/
GET /api/v1/accounts/:account_id/integrations/apps/:id
GET /api/v1/accounts/:account_id/integrations/hooks/
GET /api/v1/accounts/:account_id/integrations/hooks/:id
GET /api/v1/accounts/:account_id/integrations/linear/linked_issues
GET /api/v1/accounts/:account_id/integrations/linear/search_issue
GET /api/v1/accounts/:account_id/integrations/linear/team_entities
GET /api/v1/accounts/:account_id/integrations/linear/teams
GET /api/v1/accounts/:account_id/integrations/shopify/orders
GET /api/v1/accounts/:account_id/integrations/slack/list_all_channels
GET /api/v1/accounts/:account_id/labels/
GET /api/v1/accounts/:account_id/labels/:tag_id
GET /api/v1/accounts/:account_id/labels/:tag_id/conversations
GET /api/v1/accounts/:account_id/line_channels/
GET /api/v1/accounts/:account_id/live_reports/conversation_metrics
GET /api/v1/accounts/:account_id/live_reports/grouped_conversation_metrics
GET /api/v1/accounts/:account_id/macros/
GET /api/v1/accounts/:account_id/macros/:macro_id
GET /api/v1/accounts/:account_id/microsoft/callback
GET /api/v1/accounts/:account_id/microsoft/oauth
GET /api/v1/accounts/:account_id/microsoft/webhooks
GET /api/v1/accounts/:account_id/microsoft_channels/authorization
GET /api/v1/accounts/:account_id/notification_settings/
GET /api/v1/accounts/:account_id/platform_apps/
GET /api/v1/accounts/:account_id/platform_apps/:platform_app_id
GET /api/v1/accounts/:account_id/platform_apps/:platform_app_id/access_tokens
GET /api/v1/accounts/:account_id/platform_apps/:platform_app_id/permissibles
GET /api/v1/accounts/:account_id/platform_apps/search
GET /api/v1/accounts/:account_id/portals/
GET /api/v1/accounts/:account_id/portals/:portal_id
GET /api/v1/accounts/:account_id/portals/:portal_id/articles/
GET /api/v1/accounts/:account_id/portals/:portal_id/articles/:article_id
GET /api/v1/accounts/:account_id/portals/:portal_id/articles/:article_id/edit
GET /api/v1/accounts/:account_id/portals/:portal_id/articles/search
GET /api/v1/accounts/:account_id/portals/:portal_id/articles/status_counts
GET /api/v1/accounts/:account_id/portals/:portal_id/categories/
GET /api/v1/accounts/:account_id/portals/:portal_id/categories/:category_id
GET /api/v1/accounts/:account_id/portals/:portal_id/categories/:category_id/articles
GET /api/v1/accounts/:account_id/portals/:portal_id/folders/
GET /api/v1/accounts/:account_id/portals/:portal_id/folders/:folder_id
GET /api/v1/accounts/:account_id/portals/:portal_id/members/
GET /api/v1/accounts/:account_id/portals/:portal_id/members/:member_id
GET /api/v1/accounts/:account_id/portals/:portal_id/ssl_status
GET /api/v1/accounts/:account_id/reporting_events
GET /api/v1/accounts/:account_id/reports/agents
GET /api/v1/accounts/:account_id/reports/bot_metrics
GET /api/v1/accounts/:account_id/reports/bot_summary
GET /api/v1/accounts/:account_id/reports/conversation_traffic
GET /api/v1/accounts/:account_id/reports/conversations
GET /api/v1/accounts/:account_id/reports/conversations_summary
GET /api/v1/accounts/:account_id/reports/first_response_time_distribution
GET /api/v1/accounts/:account_id/reports/inbox_label_matrix
GET /api/v1/accounts/:account_id/reports/inboxes
GET /api/v1/accounts/:account_id/reports/labels
GET /api/v1/accounts/:account_id/reports/outgoing_messages_count
GET /api/v1/accounts/:account_id/reports/summary
GET /api/v1/accounts/:account_id/reports/teams
GET /api/v1/accounts/:account_id/saml_settings/:id
GET /api/v1/accounts/:account_id/search
GET /api/v1/accounts/:account_id/search/articles
GET /api/v1/accounts/:account_id/search/contacts
GET /api/v1/accounts/:account_id/search/conversations
GET /api/v1/accounts/:account_id/search/messages
GET /api/v1/accounts/:account_id/sla_policies
GET /api/v1/accounts/:account_id/sla_policies/:id
GET /api/v1/accounts/:account_id/sla_policies/:id/inboxes
GET /api/v1/accounts/:account_id/summary_reports/agent
GET /api/v1/accounts/:account_id/summary_reports/channel
GET /api/v1/accounts/:account_id/summary_reports/inbox
GET /api/v1/accounts/:account_id/summary_reports/label
GET /api/v1/accounts/:account_id/summary_reports/team
GET /api/v1/accounts/:account_id/tags/
GET /api/v1/accounts/:account_id/tags/:tag_id
GET /api/v1/accounts/:account_id/tags/:tag_id/conversations
GET /api/v1/accounts/:account_id/teams/
GET /api/v1/accounts/:account_id/teams/:team_id
GET /api/v1/accounts/:account_id/teams/:team_id/team_members/
GET /api/v1/accounts/:account_id/tiktok_channels/
GET /api/v1/accounts/:account_id/twilio_sms_channels/
GET /api/v1/accounts/:account_id/twitter/callback
GET /api/v1/accounts/:account_id/twitter/oauth
GET /api/v1/accounts/:account_id/twitter/webhooks
GET /api/v1/accounts/:account_id/twitter_channels/authorization
GET /api/v1/accounts/:account_id/users
GET /api/v1/accounts/:account_id/web_widgets/offline_messages
GET /api/v1/accounts/:account_id/webhooks
GET /api/v1/accounts/:account_id/webhooks/:webhook_id
GET /api/v1/accounts/all
GET /api/v1/auth/confirm_email
GET /api/v1/auth/mfa/status
GET /api/v1/auth/oauth/authorize
GET /api/v1/ldap/config
GET /api/v1/notifications
GET /api/v1/notifications/unread_count
GET /api/v1/oidc/authorize
GET /api/v1/oidc/callback
GET /api/v1/oidc/config
GET /api/v1/oidc/discovery
GET /api/v1/profile
GET /api/v1/profile/mfa/
GET /api/v1/push_subscriptions
GET /api/v1/saml/login
GET /api/v1/saml/metadata
GET /api/v1/saml/slo
GET /api/v1/sso_sessions/:session_id
GET /api/v1/sso_sessions/user/:user_id
GET /api/v1/sso_sessions/user/:user_id/count
GET /cable
GET /health
GET /platform/api/v1/accounts
GET /platform/api/v1/accounts/:account_id
GET /platform/api/v1/accounts/:account_id/account_users
GET /platform/api/v1/agent_bots
GET /platform/api/v1/agent_bots/:id
GET /platform/api/v1/apps
GET /platform/api/v1/apps/:id
GET /platform/api/v1/apps/:id/access_tokens
GET /platform/api/v1/apps/:id/permissibles
GET /platform/api/v1/apps/search
GET /platform/api/v1/banners
GET /platform/api/v1/banners/:id
GET /platform/api/v1/installation_configs
GET /platform/api/v1/installation_configs/:id
GET /platform/api/v1/users
GET /platform/api/v1/users/:id
GET /platform/api/v1/users/:id/login
GET /platform/api/v1/users/:id/token
GET /platform/api/v1/widget_tests/
GET /platform/api/v1/widget_tests/:type
GET /public/api/v1/conversations/:conversation_uuid/csats
GET /webhooks/:channel_type/:identifier
GET /widget/cable_token
GET /widget/conversations
GET /widget/conversations/:id/messages
GET /widget/widget/:website_token/pre_chat_form
GET /widget/widget/:website_token/theme_config
GET /widget/widget/:website_token/uploads/:upload_uuid
GET /ws
HEAD /webhooks/:channel_type/:identifier
OPTIONS /webhooks/:channel_type/:identifier
PATCH /api/v1/accounts/:account_id/agent_bot_inboxes/:agent_bot_inbox_id/status
PATCH /api/v1/accounts/:account_id/channels/facebook_channel/:fb_id
PATCH /api/v1/accounts/:account_id/contacts/:contact_id/notes/:note_id
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages/:draft_id
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/labels
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/participants/
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/participants/:user_id
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/priority
PATCH /api/v1/accounts/:account_id/csat_survey_responses/:id
PATCH /api/v1/accounts/:account_id/custom_attribute_definitions/:id
PATCH /api/v1/accounts/:account_id/custom_filters/:id
PATCH /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/email_channels/:em_id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/inbox_limits/:id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_channels/:ig_id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/line_channels/:line_id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/members/:user_id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/members/update_multiple
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/tiktok_channels/:tt_id
PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id/twilio_sms_channels/:tw_id
PATCH /api/v1/accounts/:account_id/integrations/slack/
PATCH /api/v1/accounts/:account_id/notification_settings/
PATCH /api/v1/accounts/:account_id/teams/:team_id/team_members/
PATCH /platform/api/v1/accounts/:account_id
PATCH /platform/api/v1/users/:id
PATCH /webhooks/:channel_type/:identifier
PATCH /widget/contact
POST /api/v1/accounts/
POST /api/v1/accounts/:account_id/agent_bot_inboxes/
POST /api/v1/accounts/:account_id/agent_bots/
POST /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/bot_rules/
POST /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/delete_avatar
POST /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/reset_access_token
POST /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/reset_secret
POST /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/reset_token
POST /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/trigger_configs/
POST /api/v1/accounts/:account_id/agent_capacity_policies/
POST /api/v1/accounts/:account_id/agents
POST /api/v1/accounts/:account_id/agents/bulk_assign
POST /api/v1/accounts/:account_id/agents/bulk_create
POST /api/v1/accounts/:account_id/agents/bulk_unassign
POST /api/v1/accounts/:account_id/assignment_policies/
POST /api/v1/accounts/:account_id/assignment_policies/:policy_id/inboxes
POST /api/v1/accounts/:account_id/assignment_policies_v2
POST /api/v1/accounts/:account_id/assignment_policies_v2/:id/inboxes
POST /api/v1/accounts/:account_id/assignment_policy
POST /api/v1/accounts/:account_id/automation_rules/
POST /api/v1/accounts/:account_id/automation_rules/:automation_id/clone
POST /api/v1/accounts/:account_id/automation_rules/:automation_id/toggle_active
POST /api/v1/accounts/:account_id/bulk_actions
POST /api/v1/accounts/:account_id/campaigns/
POST /api/v1/accounts/:account_id/campaigns/:campaign_id/start
POST /api/v1/accounts/:account_id/campaigns/:campaign_id/stop
POST /api/v1/accounts/:account_id/canned_responses/
POST /api/v1/accounts/:account_id/captain/assistant_responses/
POST /api/v1/accounts/:account_id/captain/assistant_responses/process
POST /api/v1/accounts/:account_id/captain/assistants/
POST /api/v1/accounts/:account_id/captain/assistants/:assistant_id/documents/
POST /api/v1/accounts/:account_id/captain/assistants/:assistant_id/inboxes
POST /api/v1/accounts/:account_id/captain/assistants/:assistant_id/playground
POST /api/v1/accounts/:account_id/captain/assistants/:assistant_id/scenarios/
POST /api/v1/accounts/:account_id/captain/bulk_actions/
POST /api/v1/accounts/:account_id/captain/conversation_insights/:conversation_id/analyze_participants
POST /api/v1/accounts/:account_id/captain/conversation_insights/:conversation_id/extract_action_items
POST /api/v1/accounts/:account_id/captain/conversation_insights/:conversation_id/suggest_labels
POST /api/v1/accounts/:account_id/captain/copilot/suggest_replies
POST /api/v1/accounts/:account_id/captain/copilot/summarize
POST /api/v1/accounts/:account_id/captain/copilot/translate
POST /api/v1/accounts/:account_id/captain/copilot_messages/
POST /api/v1/accounts/:account_id/captain/copilot_threads/
POST /api/v1/accounts/:account_id/captain/copilot_threads/:thread_id/copilot_messages/
POST /api/v1/accounts/:account_id/captain/copilot_threads/:thread_id/messages
POST /api/v1/accounts/:account_id/captain/custom_tools/
POST /api/v1/accounts/:account_id/captain/custom_tools/test
POST /api/v1/accounts/:account_id/captain/documents/
POST /api/v1/accounts/:account_id/captain/documents/:document_id/sync
POST /api/v1/accounts/:account_id/captain/preferences/
POST /api/v1/accounts/:account_id/captain/scenarios/
POST /api/v1/accounts/:account_id/captain/tasks/reply_suggestion
POST /api/v1/accounts/:account_id/captain/tasks/reply_suggestion/stream
POST /api/v1/accounts/:account_id/captain/tasks/rewrite
POST /api/v1/accounts/:account_id/captain/tasks/rewrite/stream
POST /api/v1/accounts/:account_id/captain/tasks/summarize
POST /api/v1/accounts/:account_id/captain/tasks/summarize/stream
POST /api/v1/accounts/:account_id/channels/facebook_channel/
POST /api/v1/accounts/:account_id/channels/facebook_channel/oauth_callback
POST /api/v1/accounts/:account_id/channels/facebook_channel/reauthorize
POST /api/v1/accounts/:account_id/companies/
POST /api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id
POST /api/v1/accounts/:account_id/companies/:company_id/notes
POST /api/v1/accounts/:account_id/contact_merge
POST /api/v1/accounts/:account_id/contacts/
POST /api/v1/accounts/:account_id/contacts/:contact_id/contact_inboxes
POST /api/v1/accounts/:account_id/contacts/:contact_id/custom_attributes/
POST /api/v1/accounts/:account_id/contacts/:contact_id/destroy_custom_attributes
POST /api/v1/accounts/:account_id/contacts/:contact_id/notes
POST /api/v1/accounts/:account_id/contacts/filter
POST /api/v1/accounts/:account_id/contacts/import
POST /api/v1/accounts/:account_id/contacts/merge
POST /api/v1/accounts/:account_id/conversations/
POST /api/v1/accounts/:account_id/conversations/:conversation_id/assign
POST /api/v1/accounts/:account_id/conversations/:conversation_id/assignments
POST /api/v1/accounts/:account_id/conversations/:conversation_id/custom_attributes
POST /api/v1/accounts/:account_id/conversations/:conversation_id/custom_attributes/
POST /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages/
POST /api/v1/accounts/:account_id/conversations/:conversation_id/labels
POST /api/v1/accounts/:account_id/conversations/:conversation_id/messages/
POST /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/retry
POST /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/translate
POST /api/v1/accounts/:account_id/conversations/:conversation_id/mute
POST /api/v1/accounts/:account_id/conversations/:conversation_id/participants/
POST /api/v1/accounts/:account_id/conversations/:conversation_id/toggle_status
POST /api/v1/accounts/:account_id/conversations/:conversation_id/toggle_typing_status
POST /api/v1/accounts/:account_id/conversations/:conversation_id/transcript
POST /api/v1/accounts/:account_id/conversations/:conversation_id/unmute
POST /api/v1/accounts/:account_id/conversations/:conversation_id/unread
POST /api/v1/accounts/:account_id/conversations/:conversation_id/update_last_seen
POST /api/v1/accounts/:account_id/conversations/:conversation_id/whatsapp_calls/
POST /api/v1/accounts/:account_id/conversations/filter
POST /api/v1/accounts/:account_id/csat_survey_responses/:id/update_review_notes
POST /api/v1/accounts/:account_id/custom_attribute_definitions/
POST /api/v1/accounts/:account_id/custom_filters/
POST /api/v1/accounts/:account_id/custom_roles/
POST /api/v1/accounts/:account_id/dashboard_apps
POST /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id/widgets
POST /api/v1/accounts/:account_id/direct_uploads
POST /api/v1/accounts/:account_id/email_channel_migrations/
POST /api/v1/accounts/:account_id/email_channels/
POST /api/v1/accounts/:account_id/google/webhooks
POST /api/v1/accounts/:account_id/google_channels/oauth_callback
POST /api/v1/accounts/:account_id/hooks/
POST /api/v1/accounts/:account_id/hooks/:id/process_event
POST /api/v1/accounts/:account_id/inbox_members/
POST /api/v1/accounts/:account_id/inboxes/
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy/
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy_v2/
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/csat_template
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/csat_template/analyze
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/inbox_limits
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_comments/:comment_id/hide
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/instagram_comments/:comment_id/reply
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/members
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/register_webhook
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/reset_secret
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/set_agent_bot
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/sync_templates
POST /api/v1/accounts/:account_id/inboxes/web_widget
POST /api/v1/accounts/:account_id/instagram/webhooks
POST /api/v1/accounts/:account_id/instagram_channels/
POST /api/v1/accounts/:account_id/integrations/hooks/
POST /api/v1/accounts/:account_id/integrations/hooks/:id/process_event
POST /api/v1/accounts/:account_id/integrations/linear/create_issue
POST /api/v1/accounts/:account_id/integrations/linear/link_issue
POST /api/v1/accounts/:account_id/integrations/linear/unlink_issue
POST /api/v1/accounts/:account_id/integrations/shopify/auth
POST /api/v1/accounts/:account_id/integrations/slack/
POST /api/v1/accounts/:account_id/labels/
POST /api/v1/accounts/:account_id/labels/batch_add
POST /api/v1/accounts/:account_id/labels/batch_remove
POST /api/v1/accounts/:account_id/line_channels/
POST /api/v1/accounts/:account_id/macros/
POST /api/v1/accounts/:account_id/macros/:macro_id/clone
POST /api/v1/accounts/:account_id/macros/:macro_id/execute
POST /api/v1/accounts/:account_id/macros/:macro_id/toggle_active
POST /api/v1/accounts/:account_id/microsoft/webhooks
POST /api/v1/accounts/:account_id/microsoft_channels/oauth_callback
POST /api/v1/accounts/:account_id/notification_subscriptions/
POST /api/v1/accounts/:account_id/platform_apps/
POST /api/v1/accounts/:account_id/platform_apps/:platform_app_id/permissibles
POST /api/v1/accounts/:account_id/platform_apps/:platform_app_id/regenerate_access_token
POST /api/v1/accounts/:account_id/portals/
POST /api/v1/accounts/:account_id/portals/:portal_id/archive
POST /api/v1/accounts/:account_id/portals/:portal_id/articles/
POST /api/v1/accounts/:account_id/portals/:portal_id/articles/bulk_actions
POST /api/v1/accounts/:account_id/portals/:portal_id/articles/bulk_delete
POST /api/v1/accounts/:account_id/portals/:portal_id/articles/bulk_update_status
POST /api/v1/accounts/:account_id/portals/:portal_id/articles/reorder
POST /api/v1/accounts/:account_id/portals/:portal_id/categories/
POST /api/v1/accounts/:account_id/portals/:portal_id/categories/reorder
POST /api/v1/accounts/:account_id/portals/:portal_id/folders/
POST /api/v1/accounts/:account_id/portals/:portal_id/members/
POST /api/v1/accounts/:account_id/portals/:portal_id/send_instructions
POST /api/v1/accounts/:account_id/saml_settings/
POST /api/v1/accounts/:account_id/saml_settings/:id/toggle_active
POST /api/v1/accounts/:account_id/sla_policies
POST /api/v1/accounts/:account_id/sla_policies/:id/inboxes
POST /api/v1/accounts/:account_id/tags/
POST /api/v1/accounts/:account_id/teams/
POST /api/v1/accounts/:account_id/teams/:team_id/team_members/
POST /api/v1/accounts/:account_id/tiktok_channels/
POST /api/v1/accounts/:account_id/twilio_sms_channels/
POST /api/v1/accounts/:account_id/twitter/webhooks
POST /api/v1/accounts/:account_id/twitter_channels/oauth_callback
POST /api/v1/accounts/:account_id/update_active_at
POST /api/v1/accounts/:account_id/upload
POST /api/v1/accounts/:account_id/users
POST /api/v1/accounts/:account_id/webhooks
POST /api/v1/auth/login
POST /api/v1/auth/login/mfa
POST /api/v1/auth/mfa/backup_codes
POST /api/v1/auth/mfa/disable
POST /api/v1/auth/mfa/enable
POST /api/v1/auth/mfa/verify
POST /api/v1/auth/oauth/callback
POST /api/v1/auth/refresh
POST /api/v1/auth/register
POST /api/v1/auth/reset_password
POST /api/v1/auth/switch_account
POST /api/v1/ldap/login
POST /api/v1/ldap/test
POST /api/v1/notification_subscriptions
POST /api/v1/notifications/:id/snooze
POST /api/v1/notifications/:id/unread
POST /api/v1/notifications/read_all
POST /api/v1/profile/auto_offline
POST /api/v1/profile/availability
POST /api/v1/profile/mfa/
POST /api/v1/profile/mfa/backup_codes
POST /api/v1/profile/mfa/verify
POST /api/v1/profile/resend_confirmation
POST /api/v1/profile/reset_access_token
POST /api/v1/push_subscriptions
POST /api/v1/saml/acs
POST /api/v1/saml/slo
POST /api/v1/sso_sessions/:session_id/terminate
POST /api/v1/sso_sessions/user/:user_id/terminate_all
POST /platform/api/v1/accounts
POST /platform/api/v1/accounts/:account_id/account_users
POST /platform/api/v1/agent_bots
POST /platform/api/v1/agent_bots/:id/delete_avatar
POST /platform/api/v1/agent_bots/:id/reset
POST /platform/api/v1/agent_bots/:id/reset_secret
POST /platform/api/v1/agent_bots/:id/reset_token
POST /platform/api/v1/apps
POST /platform/api/v1/apps/:id/permissibles
POST /platform/api/v1/apps/:id/regenerate_access_token
POST /platform/api/v1/banners
POST /platform/api/v1/installation_configs
POST /platform/api/v1/users
POST /platform/api/v1/users/:id/login
POST /platform/api/v1/users/:id/token
POST /public/api/v1/conversations/:conversation_uuid/csats
POST /webhooks/:channel_type/:identifier
POST /widget/conversations/:id/toggle_typing
POST /widget/direct_uploads
POST /widget/init
POST /widget/messages
POST /widget/widget/:website_token/offline_message
POST /widget/widget/:website_token/uploads
PUT /api/v1/accounts/:account_id
PUT /api/v1/accounts/:account_id/agent_bots/:agent_bot_id
PUT /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/bot_rules/:rule_id
PUT /api/v1/accounts/:account_id/agent_bots/:agent_bot_id/trigger_configs/:trigger_config_id
PUT /api/v1/accounts/:account_id/agent_capacity_policies/:id
PUT /api/v1/accounts/:account_id/agents/:agent_id
PUT /api/v1/accounts/:account_id/assignment_policies/:policy_id
PUT /api/v1/accounts/:account_id/assignment_policies_v2/:id
PUT /api/v1/accounts/:account_id/assignment_policy/:policy_id
PUT /api/v1/accounts/:account_id/automation_rules/:automation_id
PUT /api/v1/accounts/:account_id/campaigns/:campaign_id
PUT /api/v1/accounts/:account_id/canned_responses/:id
PUT /api/v1/accounts/:account_id/captain/assistant_responses/:response_id
PUT /api/v1/accounts/:account_id/captain/assistants/:assistant_id
PUT /api/v1/accounts/:account_id/captain/assistants/:assistant_id/scenarios/:scenario_id
PUT /api/v1/accounts/:account_id/captain/custom_tools/:tool_id
PUT /api/v1/accounts/:account_id/captain/preferences/
PUT /api/v1/accounts/:account_id/captain/scenarios/:scenario_id
PUT /api/v1/accounts/:account_id/companies/:company_id
PUT /api/v1/accounts/:account_id/contacts/:contact_id
PUT /api/v1/accounts/:account_id/conversations/:conversation_id/whatsapp_calls/:call_id
PUT /api/v1/accounts/:account_id/custom_attribute_definitions/:id
PUT /api/v1/accounts/:account_id/custom_filters/:id
PUT /api/v1/accounts/:account_id/custom_roles/:id
PUT /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id
PUT /api/v1/accounts/:account_id/dashboard_apps/:dashboard_app_id/widgets/:widget_index
PUT /api/v1/accounts/:account_id/hooks/:id
PUT /api/v1/accounts/:account_id/inboxes/:inbox_id
PUT /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy/:policy_id
PUT /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/pre_chat_form
PUT /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/theme_config
PUT /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget_config
PUT /api/v1/accounts/:account_id/inboxes/:inbox_id/working_hours
PUT /api/v1/accounts/:account_id/integrations/hooks/:id
PUT /api/v1/accounts/:account_id/labels/:tag_id
PUT /api/v1/accounts/:account_id/macros/:macro_id
PUT /api/v1/accounts/:account_id/platform_apps/:platform_app_id
PUT /api/v1/accounts/:account_id/portals/:portal_id
PUT /api/v1/accounts/:account_id/portals/:portal_id/articles/:article_id
PUT /api/v1/accounts/:account_id/portals/:portal_id/categories/:category_id
PUT /api/v1/accounts/:account_id/portals/:portal_id/folders/:folder_id
PUT /api/v1/accounts/:account_id/portals/:portal_id/members/:member_id
PUT /api/v1/accounts/:account_id/saml_settings/:id
PUT /api/v1/accounts/:account_id/settings
PUT /api/v1/accounts/:account_id/sla_policies/:id
PUT /api/v1/accounts/:account_id/tags/:tag_id
PUT /api/v1/accounts/:account_id/teams/:team_id
PUT /api/v1/accounts/:account_id/web_widgets/offline_messages/:offline_message_id/convert
PUT /api/v1/accounts/:account_id/web_widgets/offline_messages/:offline_message_id/dismiss
PUT /api/v1/accounts/:account_id/webhooks/:webhook_id
PUT /api/v1/ldap/config
PUT /api/v1/notifications/:id
PUT /api/v1/oidc/config
PUT /api/v1/profile
PUT /api/v1/profile/avatar
PUT /api/v1/profile/set_active_account
PUT /platform/api/v1/agent_bots/:id
PUT /platform/api/v1/agent_bots/:id/avatar
PUT /platform/api/v1/apps/:id
PUT /platform/api/v1/banners/:id
PUT /platform/api/v1/installation_configs/:id
PUT /webhooks/:channel_type/:identifier
TRACE /webhooks/:channel_type/:identifier
TOTAL: 704
+116
View File
@@ -0,0 +1,116 @@
# Route Parity Report
Generated from:
- GoChat route dump: `docs/parity/gochat_routes.txt`
- Chatwoot route source: `reference/chatwoot/config/routes.rb`
This first report covers frontend-critical API v1 account routes from `reference/chatwoot/config/routes.rb`. Ruby is not installed in the workspace, so Chatwoot routes are sourced from static route declarations instead of `bin/rails routes`.
Summary: 76 exact, 2 method-compatible, 0 parameter-compatible, 3 missing out of 81 tracked critical routes.
## Missing Critical Routes
| Method | Chatwoot Path | GoChat Match | Controller | Source | Status |
| --- | --- | --- | --- | --- | --- |
| GET | `/api/v1/accounts/:account_id/contacts/:contact_id/conversations` | `-` | `api/v1/accounts/contacts/conversations#index` | `routes.rb:211` | missing |
| POST | `/api/v1/accounts/:account_id/contacts/export` | `-` | `api/v1/accounts/contacts#export` | `routes.rb:204` | missing |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_priority` | `-` | `api/v1/accounts/conversations#toggle_priority` | `routes.rb:159` | missing |
## Method-Compatible Routes
These routes exist at the same path but with a compatible HTTP method. Rails resource `update` routes expose both `PATCH` and `PUT`; GoChat currently exposes only one method for some update endpoints. Keep these tracked until both methods are registered or the frontend is proven to call only the implemented method.
| Method | Chatwoot Path | GoChat Match | Controller | Source | Status |
| --- | --- | --- | --- | --- | --- |
| PUT | `/api/v1/accounts/:account_id/conversations/:conversation_id` | `PATCH /api/v1/accounts/:account_id/conversations/:conversation_id` | `api/v1/accounts/conversations#update` | `routes.rb:134` | method-compatible |
| PUT | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | `PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | `api/v1/accounts/conversations/messages#update` | `routes.rb:142` | method-compatible |
## Parameter-Compatible Routes
These routes exist with equivalent method and path shape but different parameter names. They need handler/serializer parity review, and exact external path compatibility must be preserved.
| Method | Chatwoot Path | GoChat Match | Controller | Source | Status |
| --- | --- | --- | --- | --- | --- |
| - | - | - | - | - | none |
## Exact Critical Routes
| Method | Chatwoot Path | GoChat Match | Controller | Source | Status |
| --- | --- | --- | --- | --- | --- |
| DELETE | `/api/v1/accounts/:account_id/automation_rules/:automation_id` | `/api/v1/accounts/:account_id/automation_rules/:automation_id` | `api/v1/accounts/automation_rules#destroy` | `routes.rb:115` | exact |
| DELETE | `/api/v1/accounts/:account_id/companies/:company_id` | `/api/v1/accounts/:account_id/companies/:company_id` | `api/v1/accounts/companies#destroy` | `routes.rb:179` | exact |
| DELETE | `/api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id` | `/api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id` | `api/v1/accounts/companies/contacts#destroy` | `routes.rb:188` | exact |
| DELETE | `/api/v1/accounts/:account_id/contacts/:contact_id` | `/api/v1/accounts/:account_id/contacts/:contact_id` | `api/v1/accounts/contacts#destroy` | `routes.rb:197` | exact |
| DELETE | `/api/v1/accounts/:account_id/conversations/:conversation_id` | `/api/v1/accounts/:account_id/conversations/:conversation_id` | `api/v1/accounts/conversations#destroy` | `routes.rb:134` | exact |
| DELETE | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | `api/v1/accounts/conversations/messages#destroy` | `routes.rb:142` | exact |
| DELETE | `/api/v1/accounts/:account_id/inboxes/:inbox_id` | `/api/v1/accounts/:account_id/inboxes/:inbox_id` | `api/v1/accounts/inboxes#destroy` | `routes.rb:252` | exact |
| DELETE | `/api/v1/accounts/:account_id/macros/:macro_id` | `/api/v1/accounts/:account_id/macros/:macro_id` | `api/v1/accounts/macros#destroy` | `routes.rb:118` | exact |
| DELETE | `/api/v1/accounts/:account_id/sla_policies/:id` | `/api/v1/accounts/:account_id/sla_policies/:id` | `api/v1/accounts/sla_policies#destroy` | `routes.rb:121` | exact |
| GET | `/api/v1/accounts/:account_id` | `/api/v1/accounts/:account_id` | `api/v1/accounts#show` | `routes.rb:47` | exact |
| GET | `/api/v1/accounts/:account_id/agent_capacity_policies/` | `/api/v1/accounts/:account_id/agent_capacity_policies/` | `api/v1/accounts/agent_capacity_policies#index` | `routes.rb:123` | exact |
| GET | `/api/v1/accounts/:account_id/automation_rules/` | `/api/v1/accounts/:account_id/automation_rules/` | `api/v1/accounts/automation_rules#index` | `routes.rb:115` | exact |
| GET | `/api/v1/accounts/:account_id/automation_rules/:automation_id` | `/api/v1/accounts/:account_id/automation_rules/:automation_id` | `api/v1/accounts/automation_rules#show` | `routes.rb:115` | exact |
| GET | `/api/v1/accounts/:account_id/cache_keys` | `/api/v1/accounts/:account_id/cache_keys` | `api/v1/accounts#cache_keys` | `routes.rb:50` | exact |
| GET | `/api/v1/accounts/:account_id/companies/` | `/api/v1/accounts/:account_id/companies/` | `api/v1/accounts/companies#index` | `routes.rb:179` | exact |
| GET | `/api/v1/accounts/:account_id/companies/:company_id` | `/api/v1/accounts/:account_id/companies/:company_id` | `api/v1/accounts/companies#show` | `routes.rb:179` | exact |
| GET | `/api/v1/accounts/:account_id/companies/:company_id/contacts` | `/api/v1/accounts/:account_id/companies/:company_id/contacts` | `api/v1/accounts/companies/contacts#index` | `routes.rb:188` | exact |
| GET | `/api/v1/accounts/:account_id/companies/search` | `/api/v1/accounts/:account_id/companies/search` | `api/v1/accounts/companies#search` | `routes.rb:181` | exact |
| GET | `/api/v1/accounts/:account_id/contacts/` | `/api/v1/accounts/:account_id/contacts/` | `api/v1/accounts/contacts#index` | `routes.rb:197` | exact |
| GET | `/api/v1/accounts/:account_id/contacts/:contact_id` | `/api/v1/accounts/:account_id/contacts/:contact_id` | `api/v1/accounts/contacts#show` | `routes.rb:197` | exact |
| GET | `/api/v1/accounts/:account_id/contacts/:contact_id/notes` | `/api/v1/accounts/:account_id/contacts/:contact_id/notes` | `api/v1/accounts/contacts/notes#index` | `routes.rb:214` | exact |
| GET | `/api/v1/accounts/:account_id/contacts/search` | `/api/v1/accounts/:account_id/contacts/search` | `api/v1/accounts/contacts#search` | `routes.rb:201` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/` | `/api/v1/accounts/:account_id/conversations/` | `api/v1/accounts/conversations#index` | `routes.rb:134` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/:conversation_id` | `/api/v1/accounts/:account_id/conversations/:conversation_id` | `api/v1/accounts/conversations#show` | `routes.rb:134` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/:conversation_id/labels` | `/api/v1/accounts/:account_id/conversations/:conversation_id/labels` | `api/v1/accounts/conversations/labels#index` | `routes.rb:149` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/` | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/` | `api/v1/accounts/conversations/messages#index` | `routes.rb:142` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/meta` | `/api/v1/accounts/:account_id/conversations/meta` | `api/v1/accounts/conversations#meta` | `routes.rb:136` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/search` | `/api/v1/accounts/:account_id/conversations/search` | `api/v1/accounts/conversations#search` | `routes.rb:137` | exact |
| GET | `/api/v1/accounts/:account_id/conversations/unread_counts` | `/api/v1/accounts/:account_id/conversations/unread_counts` | `api/v1/accounts/conversations/unread_counts#index` | `routes.rb:138` | exact |
| GET | `/api/v1/accounts/:account_id/csat_survey_responses/` | `/api/v1/accounts/:account_id/csat_survey_responses/` | `api/v1/accounts/csat_survey_responses#index` | `routes.rb:219` | exact |
| GET | `/api/v1/accounts/:account_id/csat_survey_responses/metrics` | `/api/v1/accounts/:account_id/csat_survey_responses/metrics` | `api/v1/accounts/csat_survey_responses#metrics` | `routes.rb:221` | exact |
| GET | `/api/v1/accounts/:account_id/custom_roles/` | `/api/v1/accounts/:account_id/custom_roles/` | `api/v1/accounts/custom_roles#index` | `routes.rb:122` | exact |
| GET | `/api/v1/accounts/:account_id/inboxes/` | `/api/v1/accounts/:account_id/inboxes/` | `api/v1/accounts/inboxes#index` | `routes.rb:252` | exact |
| GET | `/api/v1/accounts/:account_id/inboxes/:inbox_id` | `/api/v1/accounts/:account_id/inboxes/:inbox_id` | `api/v1/accounts/inboxes#show` | `routes.rb:252` | exact |
| GET | `/api/v1/accounts/:account_id/inboxes/:inbox_id/assignable_agents` | `/api/v1/accounts/:account_id/inboxes/:inbox_id/assignable_agents` | `api/v1/accounts/inboxes#assignable_agents` | `routes.rb:253` | exact |
| GET | `/api/v1/accounts/:account_id/inboxes/:inbox_id/campaigns` | `/api/v1/accounts/:account_id/inboxes/:inbox_id/campaigns` | `api/v1/accounts/inboxes#campaigns` | `routes.rb:254` | exact |
| GET | `/api/v1/accounts/:account_id/macros/` | `/api/v1/accounts/:account_id/macros/` | `api/v1/accounts/macros#index` | `routes.rb:118` | exact |
| GET | `/api/v1/accounts/:account_id/macros/:macro_id` | `/api/v1/accounts/:account_id/macros/:macro_id` | `api/v1/accounts/macros#show` | `routes.rb:118` | exact |
| GET | `/api/v1/accounts/:account_id/search` | `/api/v1/accounts/:account_id/search` | `api/v1/accounts/search#index` | `routes.rb:170` | exact |
| GET | `/api/v1/accounts/:account_id/search/articles` | `/api/v1/accounts/:account_id/search/articles` | `api/v1/accounts/search#articles` | `routes.rb:176` | exact |
| GET | `/api/v1/accounts/:account_id/search/contacts` | `/api/v1/accounts/:account_id/search/contacts` | `api/v1/accounts/search#contacts` | `routes.rb:175` | exact |
| GET | `/api/v1/accounts/:account_id/search/conversations` | `/api/v1/accounts/:account_id/search/conversations` | `api/v1/accounts/search#conversations` | `routes.rb:173` | exact |
| GET | `/api/v1/accounts/:account_id/search/messages` | `/api/v1/accounts/:account_id/search/messages` | `api/v1/accounts/search#messages` | `routes.rb:174` | exact |
| GET | `/api/v1/accounts/:account_id/sla_policies` | `/api/v1/accounts/:account_id/sla_policies` | `api/v1/accounts/sla_policies#index` | `routes.rb:121` | exact |
| GET | `/api/v1/accounts/:account_id/sla_policies/:id` | `/api/v1/accounts/:account_id/sla_policies/:id` | `api/v1/accounts/sla_policies#show` | `routes.rb:121` | exact |
| POST | `/api/v1/accounts/` | `/api/v1/accounts/` | `api/v1/accounts#create` | `routes.rb:47` | exact |
| POST | `/api/v1/accounts/:account_id/automation_rules/` | `/api/v1/accounts/:account_id/automation_rules/` | `api/v1/accounts/automation_rules#create` | `routes.rb:115` | exact |
| POST | `/api/v1/accounts/:account_id/automation_rules/:automation_id/clone` | `/api/v1/accounts/:account_id/automation_rules/:automation_id/clone` | `api/v1/accounts/automation_rules#clone` | `routes.rb:116` | exact |
| POST | `/api/v1/accounts/:account_id/companies/` | `/api/v1/accounts/:account_id/companies/` | `api/v1/accounts/companies#create` | `routes.rb:179` | exact |
| POST | `/api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id` | `/api/v1/accounts/:account_id/companies/:company_id/contacts/:contact_id` | `api/v1/accounts/companies/contacts#create` | `routes.rb:188` | exact |
| POST | `/api/v1/accounts/:account_id/contacts/` | `/api/v1/accounts/:account_id/contacts/` | `api/v1/accounts/contacts#create` | `routes.rb:197` | exact |
| POST | `/api/v1/accounts/:account_id/contacts/:contact_id/notes` | `/api/v1/accounts/:account_id/contacts/:contact_id/notes` | `api/v1/accounts/contacts/notes#create` | `routes.rb:214` | exact |
| POST | `/api/v1/accounts/:account_id/contacts/filter` | `/api/v1/accounts/:account_id/contacts/filter` | `api/v1/accounts/contacts#filter` | `routes.rb:202` | exact |
| POST | `/api/v1/accounts/:account_id/contacts/import` | `/api/v1/accounts/:account_id/contacts/import` | `api/v1/accounts/contacts#import` | `routes.rb:203` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/` | `/api/v1/accounts/:account_id/conversations/` | `api/v1/accounts/conversations#create` | `routes.rb:134` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/assignments` | `/api/v1/accounts/:account_id/conversations/:conversation_id/assignments` | `api/v1/accounts/conversations/assignments#create` | `routes.rb:148` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/labels` | `/api/v1/accounts/:account_id/conversations/:conversation_id/labels` | `api/v1/accounts/conversations/labels#create` | `routes.rb:149` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/` | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/` | `api/v1/accounts/conversations/messages#create` | `routes.rb:142` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/retry` | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/retry` | `api/v1/accounts/conversations/messages#retry` | `routes.rb:145` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/translate` | `/api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id/translate` | `api/v1/accounts/conversations/messages#translate` | `routes.rb:144` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_status` | `/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_status` | `api/v1/accounts/conversations#toggle_status` | `routes.rb:158` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/transcript` | `/api/v1/accounts/:account_id/conversations/:conversation_id/transcript` | `api/v1/accounts/conversations#transcript` | `routes.rb:157` | exact |
| POST | `/api/v1/accounts/:account_id/conversations/filter` | `/api/v1/accounts/:account_id/conversations/filter` | `api/v1/accounts/conversations#filter` | `routes.rb:139` | exact |
| POST | `/api/v1/accounts/:account_id/inboxes/` | `/api/v1/accounts/:account_id/inboxes/` | `api/v1/accounts/inboxes#create` | `routes.rb:252` | exact |
| POST | `/api/v1/accounts/:account_id/inboxes/:inbox_id/reset_secret` | `/api/v1/accounts/:account_id/inboxes/:inbox_id/reset_secret` | `api/v1/accounts/inboxes#reset_secret` | `routes.rb:262` | exact |
| POST | `/api/v1/accounts/:account_id/macros/` | `/api/v1/accounts/:account_id/macros/` | `api/v1/accounts/macros#create` | `routes.rb:118` | exact |
| POST | `/api/v1/accounts/:account_id/macros/:macro_id/execute` | `/api/v1/accounts/:account_id/macros/:macro_id/execute` | `api/v1/accounts/macros#execute` | `routes.rb:119` | exact |
| POST | `/api/v1/accounts/:account_id/sla_policies` | `/api/v1/accounts/:account_id/sla_policies` | `api/v1/accounts/sla_policies#create` | `routes.rb:121` | exact |
| POST | `/api/v1/accounts/:account_id/update_active_at` | `/api/v1/accounts/:account_id/update_active_at` | `api/v1/accounts#update_active_at` | `routes.rb:49` | exact |
| PUT | `/api/v1/accounts/:account_id` | `/api/v1/accounts/:account_id` | `api/v1/accounts#update` | `routes.rb:47` | exact |
| PUT | `/api/v1/accounts/:account_id/automation_rules/:automation_id` | `/api/v1/accounts/:account_id/automation_rules/:automation_id` | `api/v1/accounts/automation_rules#update` | `routes.rb:115` | exact |
| PUT | `/api/v1/accounts/:account_id/companies/:company_id` | `/api/v1/accounts/:account_id/companies/:company_id` | `api/v1/accounts/companies#update` | `routes.rb:179` | exact |
| PUT | `/api/v1/accounts/:account_id/contacts/:contact_id` | `/api/v1/accounts/:account_id/contacts/:contact_id` | `api/v1/accounts/contacts#update` | `routes.rb:197` | exact |
| PUT | `/api/v1/accounts/:account_id/inboxes/:inbox_id` | `/api/v1/accounts/:account_id/inboxes/:inbox_id` | `api/v1/accounts/inboxes#update` | `routes.rb:252` | exact |
| PUT | `/api/v1/accounts/:account_id/macros/:macro_id` | `/api/v1/accounts/:account_id/macros/:macro_id` | `api/v1/accounts/macros#update` | `routes.rb:118` | exact |
| PUT | `/api/v1/accounts/:account_id/sla_policies/:id` | `/api/v1/accounts/:account_id/sla_policies/:id` | `api/v1/accounts/sla_policies#update` | `routes.rb:121` | exact |