Skip to content
FOC

ERP to Salesforce

ERP → Salesforce

ERP is the client. Salesforce is the server. Auth is the same OAuth client credentials as onboarding, against /services/data/v67.0. If ERP has no instance URL and no token, the local row is still saved and this call is not made.

POST /api/foc

{
  "item": {
    "focCode": "FOC-UMBRELLA",
    "focName": "Branded Umbrella",
    "description": "Promotional umbrella with OEM branding",
    "uom": "Piece",
    "mrp": 499,
    "procurementCost": 210,
    "currency": "INR"
  }
}

ERP saves the row, then upserts Salesforce, then answers HTTP 201. On a successful first create the body includes "syncStatus": "Synced" and "salesforceRecordId": "a0F000000000001AAA". A failed push still returns 201, with "syncStatus": "Failed".

A create sets isActive to true, origin to ERP Synced when that field is blank, and status to Approved when that field is blank. Currency is stored on the row. The Salesforce body has no currency field.

HTTP error message
400 invalid_json invalid request body
400 validation_error foc code is required
400 validation_error foc name is required
400 validation_error mrp must be greater than 0
400 validation_error procurement cost must be >= 0
422 unprocessable_entity procurement cost must not exceed mrp
409 conflict foc item with this code already exists

PATCH FOC_Master__c by code

The code is in the URL, not the body.

PATCH /services/data/v67.0/sobjects/FOC_Master__c/FOC_Code__c/FOC-UMBRELLA
Authorization: Bearer {access token}
Content-Type: application/json
{
  "FOC_Name__c": "Branded Umbrella",
  "Description__c": "Promotional umbrella with OEM branding",
  "UOM__c": "Piece",
  "MRP__c": 499,
  "Procurement_Cost__c": 210,
  "Is_Active__c": true,
  "Origin__c": "ERP Synced",
  "Status__c": "Approved"
}
Salesforce field Example Where ERP got it
FOC_Code__c FOC-UMBRELLA the URL. External id. Not in the body
FOC_Name__c Branded Umbrella focName
Description__c Promotional umbrella with OEM branding description. Omitted when blank
UOM__c Piece uom, mapped onto the Salesforce picklist
MRP__c 499 mrp
Procurement_Cost__c 210 procurementCost
Is_Active__c true isActive. A create always sends true
Origin__c ERP Synced origin. A blank origin is sent as ERP Synced
Status__c Approved status. A blank status is sent as Approved

uom is matched in lower case. A blank unit, and any unit outside the list, is sent as Piece. Also accepted: pcs, pc, ea, each, and bottle → Piece, pack and bag → Pack, unit → Unit.

A first create is HTTP 201 with an id. ERP stores that id on the item. An update of a code Salesforce already has is HTTP 204 with an empty body. ERP treats that 204 as success. syncStatus stays Synced, and the id stored from the first create is left as it was. See Salesforce → ERP.

The log reference is focCode=FOC-UMBRELLA name="Branded Umbrella" mrp=499.00 procurementCost=210.00 INR. A failure is written to the ERP integration log. ERP does not post an Integration_Log__c for an FOC item.

POST /api/foc/FOC-UMBRELLA/sync-to-salesforce sends the same PATCH again. Success is HTTP 200:

{
  "erpCode": "FOC-UMBRELLA",
  "accountType": "FOC",
  "status": "Synced",
  "salesforceRecordId": "a0F000000000001AAA"
}

A Salesforce error on this retry is HTTP 500 internal_error with message internal server error. A missing code is HTTP 404 not_found with message foc item not found.

POST /api/foc/sync-unsynced runs the same upsert for every item, ordered by the time it was created. The query returns rows already marked Synced, so a second pass sends them again. Salesforce answers 204, and ERP counts those rows as synced. The answer is HTTP 200, for example { "synced": 1, "failed": 0 }.

PATCH /api/foc/FOC-UMBRELLA

The URL is the code. The body has no item wrapper. The code cannot be changed. A blank origin or status leaves the stored value. isActive changes only when the field is present.

{
  "focName": "Branded Umbrella",
  "description": "Promotional umbrella with OEM branding",
  "uom": "Piece",
  "mrp": 499,
  "procurementCost": 180,
  "currency": "INR",
  "isActive": true
}

ERP answers HTTP 200 and sends the same PATCH, with "Procurement_Cost__c": 180. Because Salesforce already has FOC-UMBRELLA, that PATCH is HTTP 204. The local row stays Synced, and salesforceRecordId stays a0F000000000001AAA.

Sending "isActive": false deactivates the item and sends "Is_Active__c": false.