Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / API reference

API

CRM API (crm)

HTTP endpoints of the crm module under /api/v1/crm: 57 routes with permissions, schemas, status codes, and error codes.

The crm module serves customers, customer parts and their revisions, customer RFQs with lines, line materials and packages, and the CRM inbox. All 57 endpoints sit under /api/v1/crm. For business meaning see the CRM module page.

Group facts

Item Value Source
Base path /api/v1/crm src/cluster_erp/core/module_base.py:37-38, src/cluster_erp/modules/crm/module.py:65
Routers 7 router objects in 7 files; listed in the section Endpoint summary src/cluster_erp/modules/crm/module.py:39
Endpoints 57, counted from the route decorators and add_api_route calls of the routers that register_routes mounts src/cluster_erp/modules/crm/customer_part_revisions/routes.py, src/cluster_erp/modules/crm/customer_parts/routes.py, src/cluster_erp/modules/crm/customers/routes.py ...
Authentication Bearer header or session cookie, resolved by get_current_user; see Authentication and headers src/cluster_erp/modules/auth/guards.py:85-167
Permission guard 57 of 57 routes declare require_permission src/cluster_erp/modules/auth/guards.py:205-240
App entitlement gate require_app("crm") on every mounted router src/cluster_erp/modules/crm/module.py:74
Error format JSON body {"error": {...}}; see Errors src/cluster_erp/server/error_handler.py:33-46

Endpoint summary

One row per sub-module folder. The router prefix is added to the base path.

Sub-module Routers Endpoints Router source
customers router 6 src/cluster_erp/modules/crm/customers/routes.py:28
customer_parts router 6 src/cluster_erp/modules/crm/customer_parts/routes.py:27
customer_part_revisions router 7 src/cluster_erp/modules/crm/customer_part_revisions/routes.py:21
rfqs router 18 src/cluster_erp/modules/crm/rfqs/routes.py:36
rfq_line_items router 6 src/cluster_erp/modules/crm/rfq_line_items/routes.py:20
rfq_line_materials router 6 src/cluster_erp/modules/crm/rfq_line_materials/routes.py:26
inbox router 8 src/cluster_erp/modules/crm/inbox/routes.py:22

Customers endpoints

Customer records. Routers in this module have no prefix of their own; each route path starts with its resource segment.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/customers/ list_customers customer.read none search, active_only, party_id, limit, offset dict 200 (default) src/cluster_erp/modules/crm/customers/routes.py:37
POST /api/v1/crm/customers/ create_customer customer.create CustomerCreate none CustomerRead 201 src/cluster_erp/modules/crm/customers/routes.py:73
GET /api/v1/crm/customers/{customer_id} get_customer customer.read none none CustomerRead 200 (default) src/cluster_erp/modules/crm/customers/routes.py:92
PUT /api/v1/crm/customers/{customer_id} update_customer customer.update CustomerUpdate none CustomerRead 200 (default) src/cluster_erp/modules/crm/customers/routes.py:113
DELETE /api/v1/crm/customers/{customer_id} delete_customer customer.delete none none none 204 src/cluster_erp/modules/crm/customers/routes.py:135
POST /api/v1/crm/customers/bulk-delete bulk_delete_customers customer.bulk_delete BulkDeleteRequest none BulkDeleteResponse 200 (default) src/cluster_erp/modules/crm/customers/routes.py:147

Customer parts endpoints

Customer part records.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/customer-parts/ list_customer_parts customer_part.read none customer_id, rfq_id, search, active_only, limit, offset dict 200 (default) src/cluster_erp/modules/crm/customer_parts/routes.py:47
POST /api/v1/crm/customer-parts/ create_customer_part customer_part.create CustomerPartCreate none CustomerPartRead 201 src/cluster_erp/modules/crm/customer_parts/routes.py:88
GET /api/v1/crm/customer-parts/{customer_part_id} get_customer_part customer_part.read none none CustomerPartRead 200 (default) src/cluster_erp/modules/crm/customer_parts/routes.py:106
PUT /api/v1/crm/customer-parts/{customer_part_id} update_customer_part customer_part.update CustomerPartUpdate none CustomerPartRead 200 (default) src/cluster_erp/modules/crm/customer_parts/routes.py:125
DELETE /api/v1/crm/customer-parts/{customer_part_id} delete_customer_part customer_part.delete none none none 204 src/cluster_erp/modules/crm/customer_parts/routes.py:145
POST /api/v1/crm/customer-parts/bulk-delete bulk_delete_customer_parts customer_part.bulk_delete BulkDeleteRequest none BulkDeleteResponse 200 (default) src/cluster_erp/modules/crm/customer_parts/routes.py:157

Customer part revisions endpoints

Revisions under a customer part, with activate and supersede.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/customer-parts/{customer_part_id}/revisions list_revisions customer_part_revision.read none none list[CustomerPartRevisionRead] 200 (default) src/cluster_erp/modules/crm/customer_part_revisions/routes.py:24
POST /api/v1/crm/customer-parts/{customer_part_id}/revisions create_revision customer_part_revision.create CustomerPartRevisionCreate none CustomerPartRevisionRead 201 src/cluster_erp/modules/crm/customer_part_revisions/routes.py:39
GET /api/v1/crm/customer-part-revisions/{revision_id} get_revision customer_part_revision.read none none CustomerPartRevisionRead 200 (default) src/cluster_erp/modules/crm/customer_part_revisions/routes.py:56
PUT /api/v1/crm/customer-part-revisions/{revision_id} update_revision customer_part_revision.update CustomerPartRevisionUpdate none CustomerPartRevisionRead 200 (default) src/cluster_erp/modules/crm/customer_part_revisions/routes.py:73
DELETE /api/v1/crm/customer-part-revisions/{revision_id} delete_revision customer_part_revision.delete none none none 204 src/cluster_erp/modules/crm/customer_part_revisions/routes.py:91
POST /api/v1/crm/customer-part-revisions/{revision_id}/activate activate_revision customer_part_revision.activate none none CustomerPartRevisionRead 200 (default) src/cluster_erp/modules/crm/customer_part_revisions/routes.py:103
POST /api/v1/crm/customer-part-revisions/{revision_id}/supersede supersede_revision customer_part_revision.activate none none CustomerPartRevisionRead 200 (default) src/cluster_erp/modules/crm/customer_part_revisions/routes.py:118

Customer RFQs endpoints

RFQ records, completeness check, assign, quote, decline, expire, win, lose, reopen, and the RFQ package.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/rfqs/ list_rfqs rfq.read none search, status, customer_id, limit, offset dict 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:51
POST /api/v1/crm/rfqs/ create_rfq rfq.create RfqCreate none RfqRead 201 src/cluster_erp/modules/crm/rfqs/routes.py:85
GET /api/v1/crm/rfqs/{rfq_id} get_rfq rfq.read none none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:97
PUT /api/v1/crm/rfqs/{rfq_id} update_rfq rfq.update RfqUpdate none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:111
DELETE /api/v1/crm/rfqs/{rfq_id} delete_rfq rfq.delete none none none 204 src/cluster_erp/modules/crm/rfqs/routes.py:126
POST /api/v1/crm/rfqs/bulk-delete bulk_delete_rfqs rfq.bulk_delete BulkDeleteRequest none BulkDeleteResponse 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:138
GET /api/v1/crm/rfqs/{rfq_id}/completeness get_rfq_completeness rfq.read none none dict 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:153
POST /api/v1/crm/rfqs/{rfq_id}/assign assign_rfq rfq.assign RfqAssign none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:170
POST /api/v1/crm/rfqs/{rfq_id}/quote quote_rfq rfq.quote RfqTransition none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:188
POST /api/v1/crm/rfqs/{rfq_id}/decline decline_rfq rfq.decline RfqDecline none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:201
POST /api/v1/crm/rfqs/{rfq_id}/expire expire_rfq rfq.expire RfqTransition none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:214
POST /api/v1/crm/rfqs/{rfq_id}/win win_rfq rfq.win RfqTransition none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:227
POST /api/v1/crm/rfqs/{rfq_id}/lose lose_rfq rfq.lose RfqLose none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:240
POST /api/v1/crm/rfqs/{rfq_id}/reopen reopen_rfq rfq.reopen RfqTransition none RfqRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:253
GET /api/v1/crm/rfqs/{rfq_id}/rfq-package get_rfq_package rfq_package.read none none RfqPackageRead \| None 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:269
POST /api/v1/crm/rfqs/{rfq_id}/rfq-package create_rfq_package rfq_package.create RfqPackageCreate none RfqPackageRead 201 src/cluster_erp/modules/crm/rfqs/routes.py:283
PUT /api/v1/crm/rfq-packages/{package_id} update_rfq_package rfq_package.update RfqPackageUpdate none RfqPackageRead 200 (default) src/cluster_erp/modules/crm/rfqs/routes.py:300
DELETE /api/v1/crm/rfq-packages/{package_id} delete_rfq_package rfq_package.delete none none none 204 src/cluster_erp/modules/crm/rfqs/routes.py:318

RFQ line items endpoints

Line items under an RFQ.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/rfqs/{rfq_id}/line-items list_line_items rfq_line_item.read none search list[RfqLineItemRead] 200 (default) src/cluster_erp/modules/crm/rfq_line_items/routes.py:23
POST /api/v1/crm/rfqs/{rfq_id}/line-items create_line_item rfq_line_item.create RfqLineItemCreate none RfqLineItemRead 201 src/cluster_erp/modules/crm/rfq_line_items/routes.py:39
GET /api/v1/crm/line-items/{line_item_id} get_line_item rfq_line_item.read none none RfqLineItemRead 200 (default) src/cluster_erp/modules/crm/rfq_line_items/routes.py:56
PUT /api/v1/crm/line-items/{line_item_id} update_line_item rfq_line_item.update RfqLineItemUpdate none RfqLineItemRead 200 (default) src/cluster_erp/modules/crm/rfq_line_items/routes.py:73
DELETE /api/v1/crm/line-items/{line_item_id} delete_line_item rfq_line_item.delete none none none 204 src/cluster_erp/modules/crm/rfq_line_items/routes.py:91
POST /api/v1/crm/line-items/bulk-delete bulk_delete_line_items rfq_line_item.bulk_delete BulkDeleteRequest none BulkDeleteResponse 200 (default) src/cluster_erp/modules/crm/rfq_line_items/routes.py:103

RFQ line materials endpoints

Materials under a line item, including an import from a BOM.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/line-items/{line_item_id}/materials list_line_materials rfq_line_material.read none none list[RfqLineMaterialRead] 200 (default) src/cluster_erp/modules/crm/rfq_line_materials/routes.py:29
POST /api/v1/crm/line-items/{line_item_id}/materials create_line_material rfq_line_material.create RfqLineMaterialCreate none RfqLineMaterialRead 201 src/cluster_erp/modules/crm/rfq_line_materials/routes.py:44
POST /api/v1/crm/line-items/{line_item_id}/materials/from-bom import_line_materials_from_bom rfq_line_material.create none none dict 200 (default) src/cluster_erp/modules/crm/rfq_line_materials/routes.py:65
PUT /api/v1/crm/line-materials/{material_id} update_line_material rfq_line_material.update RfqLineMaterialUpdate none RfqLineMaterialRead 200 (default) src/cluster_erp/modules/crm/rfq_line_materials/routes.py:86
DELETE /api/v1/crm/line-materials/{material_id} delete_line_material rfq_line_material.delete none none none 204 src/cluster_erp/modules/crm/rfq_line_materials/routes.py:108
POST /api/v1/crm/line-materials/bulk-delete bulk_delete_line_materials rfq_line_material.delete BulkDeleteRequest none BulkDeleteResponse 200 (default) src/cluster_erp/modules/crm/rfq_line_materials/routes.py:123

Inbox endpoints

Inbox messages, manual match to a record, and spam marking.

Method Path Handler Permission Request Query Response Status Source
GET /api/v1/crm/inbox/ list_inbox_messages inbox_message.read none search, match_status, rfq_id, limit, offset dict 200 (default) src/cluster_erp/modules/crm/inbox/routes.py:25
POST /api/v1/crm/inbox/ create_inbox_message inbox_message.create InboxMessageCreate none InboxMessageRead 201 src/cluster_erp/modules/crm/inbox/routes.py:51
GET /api/v1/crm/inbox/{message_id} get_inbox_message inbox_message.read none none InboxMessageRead 200 (default) src/cluster_erp/modules/crm/inbox/routes.py:63
PUT /api/v1/crm/inbox/{message_id} update_inbox_message inbox_message.update InboxMessageUpdate none InboxMessageRead 200 (default) src/cluster_erp/modules/crm/inbox/routes.py:77
DELETE /api/v1/crm/inbox/{message_id} delete_inbox_message inbox_message.delete none none none 204 src/cluster_erp/modules/crm/inbox/routes.py:92
POST /api/v1/crm/inbox/bulk-delete bulk_delete_inbox_messages inbox_message.bulk_delete BulkDeleteRequest none BulkDeleteResponse 200 (default) src/cluster_erp/modules/crm/inbox/routes.py:104
POST /api/v1/crm/inbox/{message_id}/match manual_match_message inbox_message.match InboxManualMatch none InboxMessageRead 200 (default) src/cluster_erp/modules/crm/inbox/routes.py:119
POST /api/v1/crm/inbox/{message_id}/spam mark_spam inbox_message.spam none none InboxMessageRead 200 (default) src/cluster_erp/modules/crm/inbox/routes.py:134

Error codes

The table lists the error codes that code under src/cluster_erp/modules/crm/ raises, found by a syntax-tree scan for AppError(...), the factories in src/cluster_erp/core/errors.py (not_found, conflict, protected, permission_denied, privilege_escalation, check_version), and HTTPException(...). A status of 400 is the AppError default (src/cluster_erp/core/errors.py:23). Guard errors (401, 403), the entitlement codes, and validation errors (422) apply to every route and are listed on Errors.

Code HTTP status Raised in First site
CONCURRENCY_VERSION_CONFLICT 409 rfq_line_materials, rfqs src/cluster_erp/modules/crm/rfq_line_materials/services.py:161
CRM_RFQ_BOM_MATERIALS_EMPTY 422 rfq_line_materials src/cluster_erp/modules/crm/rfq_line_materials/services.py:119
CRM_RFQ_LINE_NO_PRODUCT 422 rfq_line_materials src/cluster_erp/modules/crm/rfq_line_materials/services.py:108
RESOURCE_CONFLICT 409 rfqs src/cluster_erp/modules/crm/rfqs/services.py:576
RESOURCE_NOT_FOUND 404 customer_part_revisions, customer_parts, customers, inbox, rfq_line_items, rfq_line_materials, rfqs src/cluster_erp/modules/crm/customer_part_revisions/routes.py:69
RFQ_ARIBA_DUE_DATE_IMMUTABLE 400 rfqs src/cluster_erp/modules/crm/rfqs/services.py:225
RFQ_DUPLICATE_SUBJECT 409 rfqs src/cluster_erp/modules/crm/rfqs/services.py:521
RFQ_INCOMPLETE 409 rfqs src/cluster_erp/modules/crm/rfqs/services.py:340
RFQ_INVALID_STATUS 409 rfqs src/cluster_erp/modules/crm/rfqs/services.py:291

Events emitted

The table lists the contract classes that code under src/cluster_erp/modules/crm/ passes directly to EventBus.emit, found by a syntax-tree scan. Events built in a variable first are not counted. The contracts are described in Contracts reference.

Contract Sites First site
CustomerCreated 1 src/cluster_erp/modules/crm/customers/services.py:118
CustomerUpdated 1 src/cluster_erp/modules/crm/customers/services.py:186
PartyRoleSet 2 src/cluster_erp/modules/crm/customers/services.py:137
RfqAssigned 1 src/cluster_erp/modules/crm/rfqs/services.py:321
RfqDeclined 1 src/cluster_erp/modules/crm/rfqs/services.py:434
RfqExpired 1 src/cluster_erp/modules/crm/rfqs/services.py:451
RfqLost 1 src/cluster_erp/modules/crm/rfqs/services.py:487
RfqPackageCompleted 1 src/cluster_erp/modules/crm/rfqs/services.py:612
RfqReceived 1 src/cluster_erp/modules/crm/rfqs/services.py:192
RfqUpdated 1 src/cluster_erp/modules/crm/rfqs/services.py:253
RfqWon 1 src/cluster_erp/modules/crm/rfqs/services.py:468

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13