Skip to content
Chapter

Distributor onboarding

Distributor onboarding

Distributor onboarding is the path that turns an approved prospect into a Sold To and a Bill To. Salesforce collects the prospect and runs the approval. ERP assigns the codes and is the system of record for the master afterwards.

Four records are involved.

Record Where Role in this flow
Distributor_Onboarding__c Salesforce The prospect, the approval, and the link to the Temp Account
Account, record type Temp Salesforce The row Salesforce sends to ERP. It has no Sold To code yet
Sold To ERP, then Salesforce The distributor. ERP assigns Sold_To_Code__c and upgrades the Temp Account into this record type
Bill To ERP, then Salesforce The billing account under that Sold To. ERP creates it

ERP owns the codes. Salesforce does not invent DIST001 or BILL001. It sends the prospect, waits for the codes, and stores the Sold To code that comes back.

The JSON is on two pages: Salesforce → ERP and ERP → Salesforce. What stays saved when a later call fails is on Failures and retry.

Sample distributor

Every example uses this prospect. Codes assume no earlier DIST or BILL sequence exists in ERP or in Salesforce.

Item Value
Prospect name Sharma Distributors
Contact Meena Rao
Phone 9900112233
Email meena.sharma@example.com
GSTIN 29ABCDE1234F1Z5
PAN ABCDE1234F
Street 21 Residency Road
City Bengaluru
State Karnataka
Pincode 560025
Territory code TER-KA-BLR-01
Onboarding record Id a0X000000000001AAA
Temp Account Id, later the Sold To Id 001000000000001AAA
Bill To Account Id 001000000000002AAA
Sold To code DIST001
Bill To code BILL001
Sold To row id 7c9e6679-7425-40de-944b-e07fc1f90ae7
Bill To row id 3fa85f64-5717-4562-b3fc-2c963f66afa6
Onboarding reference ONB-2026-0001

DIST is the first four letters of the last significant word in "Sharma Distributors". BILL comes from the Bill To name "Sharma Distributors - Billing". The number is a three-digit sequence for that prefix. The onboarding reference is ONB-{year}-{count}, zero-padded to four digits. Each code is checked in Salesforce and skipped if that code is already on an Account. Up to 50 candidates are tried.

How the systems connect

Salesforce calls ERP with the Named Credential ERP_Named_Credential. ERP calls Salesforce with OAuth client credentials against REST API v67.0.

Salesforce calls ERP

ERP_Integration_Setting.Distributor_Sync is the onboarding push. ErpCallbackService is the record-id callback.

Setting Onboarding push Record ID callback
Call POST callout:ERP_Named_Credential/webhook/onboarding POST callout:ERP_Named_Credential/api/accounts/salesforce-callback
Header Content-Type: application/json Content-Type: application/json
Timeout 15000 ms 15000 ms
Retries Max_Retries__c = 0. One attempt 3 retries after the first attempt (retry count 0 through 3)
Object Account Account
Sync status field ERP_Sync_Status__c ERP_Sync_Status__c
Sync timestamp field ERP_Last_Sync_Timestamp__c stamped on a successful callback
Log operation Update Create, or Retry when retryCount > 0

The Named Credential supplies the ERP base URL and the credential Salesforce attaches. The path above is appended to that base. A local ERP listens on http://localhost:8080, so a developer org typically points the Named Credential there.

ERP also accepts the same handlers on a second path:

Live path Salesforce uses Alias Handler
POST /webhook/onboarding POST /api/distributors/onboarding ReceiveOnboarding
POST /api/accounts/salesforce-callback POST /webhook/salesforce-callback SalesforceCallback

The alias under /webhook/salesforce-callback is the older path. New callback traffic uses /api/accounts/salesforce-callback.

ERP calls Salesforce

When an instance URL and a token provider (OAuth client id and secret, or a static access token) are set, ERP uses the HTTP client:

POST {instance}/services/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id={id}&client_secret={secret}

Account calls then go to /services/data/v67.0/sobjects/Account and /services/data/v67.0/sobjects/Account/{id}. Record type ids are resolved by developer name (Sold_To, Bill_To) and cached. They are not hardcoded.

If neither an instance URL nor a token provider is configured, NewSalesforceClient returns MockSalesforceClient. Local Sold To and Bill To rows are still created, and POST /webhook/onboarding still returns the codes. Nothing is written to a Salesforce org. The bodies on ERP → Salesforce are the HTTP client, which is the path a connected org runs.

Log types

The same hop is outbound for the caller and inbound for the receiver.

Hop Salesforce log type ERP log type
Temp Account push Outbound (Distributor_Sync) Inbound
Sold To upgrade and Bill To create Inbound REST Outbound
Record ID callback Outbound (ErpCallbackService) Callback

Sequence

Finance approval of Distributor_Onboarding__c is the start. The onboarding record must move to status Approved while Temp_Account__c is still blank. Distributor_Onboarding_After_Save_Flow then creates one Temp Account and stores its Id on the onboarding record. If that insert fails, the flow rolls the approval back and the onboarding record stays at KYC In Progress.

The Temp Account is filled from the onboarding record:

Temp Account field Copied from
Name Prospect_Name__c
GST_Registration_Number__c GST_Registration_Number__c
PAN_Number__c PAN_Number__c
BillingStreet, BillingCity, BillingPostalCode Address__Street__s, Address__City__s, Address__PostalCode__s
BillingStateCode, BillingCountryCode Address__StateCode__s, Address__CountryCode__s
Contact_Name__c Contact_Name__c
Contact_Phone__c Mobile__c
Email__c Email__c
Territory__c Proposed_Territory__c
Distributor_Onboarding__c the onboarding record Id
Account_Status__c Active
ERP_Sync_Status__c Pending
Record type Temp

Bank fields are not copied onto the Temp Account. The three bank payload mappings are also inactive, so bank details are not on the wire. The mapping rows are on Salesforce → ERP.

sequenceDiagram
  participant SF as Salesforce
  participant ERP
  SF->>SF: Finance approval creates Temp Account
  SF->>ERP: POST /webhook/onboarding
  ERP->>ERP: Create Sold To and Bill To
  ERP->>SF: PATCH Temp Account to Sold To
  ERP->>SF: POST Bill To Account
  ERP-->>SF: 200 with soldToCode and billToCodes
  SF->>ERP: POST /api/accounts/salesforce-callback
  1. Temp Account insert. Id 001000000000001AAA now exists. Record type is Temp. Sold To code is blank. ERP_Sync_Status__c is Pending.
  2. Temp_AfterSave sees a new Temp Account. The flow starts only for record type Temp. On insert (ISNEW()) it calls ErpOutboundSyncInvocable with integration name Distributor_Sync and that Account Id. This is the onboarding POST. The older Account_AfterSave flow is obsolete and does not run. Temp accounts do not enter Account_AfterSave_Shared, so this insert does not send a record-id callback.
  3. ERP validates and saves. It creates Sold To DIST001 and Bill To BILL001 in its own database, with onboarding reference ONB-2026-0001. The Salesforce Id is kept on the onboarding row. It is not yet stored on the Sold To. That happens on the callback.
  4. ERP upgrades the Temp Account. PATCH /services/data/v67.0/sobjects/Account/001000000000001AAA changes the record type to Sold To and writes Sold_To_Code__c = DIST001. See Sold To upgrade. SoldTo_AfterSave then calls Account_AfterSave_Shared, which queues the Sold To callback because the prior record type was Temp.
  5. ERP creates the Bill To. POST /services/data/v67.0/sobjects/Account inserts record type Bill To, parented by Sold To code DIST001. Salesforce returns 001000000000002AAA. See Bill To create. That insert queues the Bill To callback.
  6. ERP answers the original push. HTTP 200 with soldToCode, billToCodes, recordTypeUpgrade, erpReference, and status. Salesforce writes soldToCode to Account.ERP_Record_ID__c and resolves recordTypeUpgrade (Sold To) to the Sold To RecordTypeId. It sets ERP_Sync_Status__c to Synced. The code write replaces the internal id that the PATCH had put in ERP_Record_ID__c. The record type write is the same Sold To type the PATCH already set, when the PATCH succeeded.
  7. Callbacks run. Each queued job posts the Account Id to POST /api/accounts/salesforce-callback. ERP stores 001000000000001AAA on Sold To DIST001 and copies it onto the Bill To as the parent Salesforce Id. It stores 001000000000002AAA on Bill To BILL001. See Record ID callback.

The PATCH and the Bill To insert happen inside the onboarding request, before step 6 returns. The callbacks are queued by those Salesforce saves and run after the request, as separate queueable jobs.

After step Known in Salesforce Known in ERP
1 Temp Account Id, onboarding Id nothing yet
3 unchanged Sold To code, Bill To code, onboarding reference, Temp Account Id on the onboarding row
4 Temp Account is now Sold To, Sold_To_Code__c is set same, plus the PATCH succeeded
5 Bill To Id exists Bill To still has no Salesforce Id until step 7
6 ERP_Record_ID__c on the Sold To Account is DIST001, sync status Synced unchanged
7 callback sync status Synced salesforceRecordId on Sold To and Bill To, parent Salesforce Id on the Bill To

Once DIST001 and BILL001 exist, the next chapter is Account lifecycle: edits, another Bill To, and freeze, unfreeze, deactivate, and activate.