How To: Synchronize Customer Verticals with an ERP
Use this guide to implement a reliable two-way synchronization of the Customer Vertical field between Velosity and an ERP. The pattern lets users change a Customer's Vertical in Velosity while preserving the ERP's controlled list of accepted values.
Choose the source of truth
Use the ERP as the source of truth for the valid Vertical list. Assignments on individual customers may originate in Velosity, but every assigned value must be one accepted by the ERP.
Store each Vertical with a stable ERP code and a user-facing label. Send the ERP code in integrations; do not use the display label as the integration key because labels may be renamed.
| Field | Purpose |
|---|---|
erpCode |
Immutable value used in messages to and from the ERP |
name |
Human-readable label displayed in Velosity |
isActive |
Whether the value is selectable for new assignments |
Inactive values should remain visible on existing customers for history, but should not be offered as a new selection.
Use Verticals for margin policy
A Vertical can also define the target margin percentage used by CPQ. This lets the business apply one margin policy to all Customers in an industry segment instead of maintaining the same target on every Customer.
When CPQ evaluates a quote, it uses the active Vertical's target margin first. If that Vertical does not have a target, CPQ falls back to the Customer's gross-margin target. The resolved target and its source are shown in Margin Analysis so the salesperson and approver can see which policy applies.
Treat the five points on either side of the target as a review band. For a 30% target, for example, 25% and 35% are the lower and upper edges of the +/- 5 percentage-point band. The approval behavior is:
| Actual margin compared with target | Result |
|---|---|
| At or above the target, including the upper half of the band | Policy satisfied; no margin approval is required |
| Below the target by 5 percentage points or less | Level 1 margin approval |
| Below the target by more than 5 percentage points | Level 2 margin approval |
The boundary is inclusive at the lower edge: an actual margin exactly 5 percentage points below target remains Level 1. A lower result moves to Level 2. These are percentage-point comparisons, not a relative 5% calculation.
Support the approval flow with PROCESS
An instance can enable Margin Approval via PROCESS and provide startable PROCESS definitions with process types MarginApprovalLevel1 and MarginApprovalLevel2. CPQ selects the definition that matches the shortfall, requires the requester to enter a business justification, and starts the workflow from the quote-line Margin Analysis view.
PROCESS can then route Level 1 and Level 2 requests to different approvers, collect the decision, and retain the policy target, calculated margins, requester justification, and quote-line calculation snapshot with the request. CPQ prevents a duplicate active request for the same calculation. If the quote line changes after submission, the prior request or approval becomes stale and the salesperson must request approval for the new calculation. This keeps an approval tied to the prices and costs the approver reviewed.
1. Synchronize valid values into Velosity
Have the integration retrieve the ERP's Vertical list on a schedule and write it to Velosity's Vertical master-data list. The Customer edit experience should be a dropdown populated from active values in that list.
Do not use the distinct Vertical strings found on Customer records as the allowed-value list. That data is useful for migration and reconciliation only: it may include historic spelling variants, values from deleted customers, or values the ERP does not accept.
Before enabling validation, reconcile existing Customer values with the ERP list. Map each existing value to an ERP code and send unmapped values to a business owner for resolution.
2. Expose the two required read APIs
An integration normally needs both the controlled list and the current Customer assignments.
Valid Vertical values
Expose an authenticated endpoint such as:
GET /v1/integrations/erp/verticals
Example response:
[
{
"id": "8d4dcdd7-f0d9-4dc0-9d13-1ed2a4f45e81",
"erpCode": "AEROSPACE",
"name": "Aerospace",
"isActive": true
}
]
Customer-to-Vertical assignments
A list of labels alone does not let an ERP update the right Customer. For reconciliation, expose a paged, resumable mapping endpoint:
GET /v1/integrations/erp/customers/verticals?updatedSince=2026-08-27T00:00:00Z&cursor=...
Example response:
{
"nextCursor": "opaque-cursor",
"customers": [
{
"customerId": "2a5200a4-96c9-4292-90fd-b78517693191",
"customerNumber": "100123",
"verticalCode": "AEROSPACE",
"updatedUtc": "2026-08-27T18:23:10Z"
}
]
}
Protect these endpoints with a tenant-scoped integration API key. Return only the selected tenant's data.
3. Send a webhook for a user-initiated change
After Velosity successfully saves a Customer whose Vertical actually changed, create an outbound event. Use an event name specific to this field, such as customer.vertical.changed.
{
"eventId": "c9b2b4f5-6c28-4b0c-94bf-7560d316497e",
"eventType": "customer.vertical.changed",
"occurredUtc": "2026-08-27T18:23:10Z",
"source": "velosity",
"customer": {
"id": "2a5200a4-96c9-4292-90fd-b78517693191",
"number": "100123",
"verticalCode": "AEROSPACE"
}
}
Sign the request using an HMAC header and configure the receiving service to verify it. The receiver must deduplicate by eventId and return a successful response only once it has durably accepted the event.
Use an outbox: commit the Customer update and the outbound event in the same database transaction, then send from a background worker with retry and delivery logging. Do not make the user-facing save depend on a synchronous call to the receiving system.
4. Avoid feedback loops and overwrites
Tag each update with its origin and a correlation ID.
- A Velosity user changes a Vertical. Velosity records
source=Velosityand emits an outbound event. - The integration applies the change to the ERP.
- The next ERP import carries the same code and correlation ID. Velosity records this as confirmation and does not emit another event.
- An ERP-originated change is recorded as
source=ERPand does not trigger the outbound Velosity webhook.
Define a conflict rule before release. A sensible initial rule is that a newer user-originated change remains pending until the ERP confirms it; an independent ERP change during that interval is logged as a conflict for review rather than silently overwriting the user's edit.
If the ERP does not have an API
Put middleware between Velosity and the ERP. The middleware owns the adapter to the ERP's available transport, such as scheduled CSV/XML file exchange, SFTP, a database staging table, an EDI feed, RPA, or an ERP-specific connector.
The middleware should:
- Receive and verify Velosity webhooks, then persist them in its own durable queue.
- Translate Velosity's stable
verticalCodeto the ERP's required representation. - Deliver changes using the ERP's available transport and retry transient failures.
- Poll or ingest ERP exports for valid values and customer assignments, then call Velosity's authenticated integration endpoints.
- Maintain idempotency and correlation records so retries and round trips cannot create loops.
- Alert on rejected codes, unmapped customers, and events that remain undelivered beyond an agreed threshold.
This preserves the same integration contract even if the ERP can only exchange nightly files. Webhooks reduce latency when the middleware can receive them, while the paged reconciliation endpoint repairs missed notifications and handles bulk changes.
Release checklist
- [ ] Obtain the canonical ERP Vertical codes, labels, and active status.
- [ ] Agree on and populate each Vertical's target margin percentage.
- [ ] Add and populate the Velosity Vertical master-data list.
- [ ] Map or remediate all legacy Customer Vertical values.
- [ ] Validate Customer edits against active ERP-backed values.
- [ ] Configure the authenticated read APIs and a least-privilege integration key.
- [ ] Configure signed webhook delivery with durable outbox retries.
- [ ] If margin approvals are required, enable Margin Approval via PROCESS and configure the Level 1 and Level 2 definitions and approvers.
- [ ] Confirm loop prevention, idempotency, and the conflict rule with an end-to-end test.
- [ ] Run an initial full reconciliation before enabling ongoing synchronization.