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.
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.
- [ ] 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.
- [ ] Confirm loop prevention, idempotency, and the conflict rule with an end-to-end test.
- [ ] Run an initial full reconciliation before enabling ongoing synchronization.