Issue accessing the Epicor API programmatically

I am having an issue accessing the API programmatically.

I am trying to send a POST request to send some data.

I was able to authenticate and send a GET request with no issues, but with the POST request I am getting an error: “The request is invalid.”

I am using the exact same data in both the Epicor REST Swagger UI, but when I run the POST request through Python or PowerShell it gives me the same error.


Inside the Epicor REST Swagger UI, I am making this POST request:

This posts fine and adds the information.

Then, I have the following code written in PowerShell and Python, neither are working:

PowerShell:

    $Bytes = [System.Text.Encoding]::Ascii.GetBytes($Text)
    $EncodedText = [Convert]::ToBase64String($Bytes)
    $header = @{Authorization="Basic $EncodedText"}
    $data_params = @{
      Company="SEI";
      Key1="test";
      XFileRefXFileName="";
      XFileRefXFileDesc="string";
      RowMod="A"
   }

    Invoke-RestMethod https://epicor10/EpicorERPTEST/api/v1/Ice.BO.AttachmentSvc/Attachments -Method Post -ContentType "application/json" -headers $header -body $data_params

Python:

    input_params ={
      "Company": "SEI",
      "RelatedToSchemaName": "Erp",
      "RelatedToFile": "DMRHead",
      "Key1": "test",
      "XFileRefXFileName": "",
      "XFileRefXFileDesc": "string",
      "RowMod": "A"
    }

    post = requests.post('https://epicor10/EpicorERPTEST/api/v1/Ice.BO.AttachmentSvc/Attachments',
                     data=input_params,
                     headers={'Authorization': f'Basic {base64_message}'},
                     verify=False)

I have used the base64 encryption in both languages to make the call, and it works for authentication, so I don’t think the issue is there.

The error I am getting in both cases is:

"odata.error":{
    "code":"","message":{
      "lang":"en-US","value":"The request is invalid."
    },"innererror":{
      "message":"entity : An error has occurred.\r\n","type":"","stacktrace":""
    }
  }

I can replicate this error in the the Swagger REST UI by putting an incorrect value into one of the fields, and the error I get is this:

Response Body:

{
  "odata.error": {
    "code": "",
    "message": {
      "lang": "en-US",
      "value": "The request is invalid."
    },
    "innererror": {
      "message": "entity : An error has occurred.\r\n",
      "type": "",
      "stacktrace": ""
    }
  }
}

Response Code:

400

Response Headers:

{
  "content-length": "221",
  "content-type": "application/json; charset=utf-8",
  "dataserviceversion": "3.0",
  "date": "Tue, 09 Mar 2021 18:12:39 GMT",
  "server": "Microsoft-IIS/10.0",
  "x-powered-by": "ASP.NET"
}

I replicate this error in the UI by placing a string value into a Boolean value instead, where it was expecting ‘true’ or ‘false’ I passed ‘asdf’ and it throws this error.

However in my code I am not passing any improper values, and can pass the exact same parameters I am using in the code in the Swagger UI, and it works.

Is there a step I am missing, or something that needs to be included when using the API programmatically?

I appreciate any help!

Have you tried parsing your json out before sending it to see what it’s sending to the API?

Something is going on when it sends it and either Python or ASP.net is doing something with the Json that the API doesn’t like. That’s my best guess. I had a similar issue with currency and PHP yesterday because json_encode in PHP will convert integers to strings.

My python code I use

def RecordAlarm():
	status = False		
	hd = { 'Content-Type': 'application/json',
		  'Accept': "application/json",
		  'Authorization': 'Basic =hashgibberish',
		  'X-API-KEY': 'apigibberish'
        }
	
	pl = json.dumps({  'ResourceID': 'res'  })

	conn = httplib.HTTPSConnection('yourserv.host')
	try:
		conn.request("POST", "/appserver/api/v2/efx/Comp/Lib/Method", pl, hd)
		response = conn.getresponse()				
		status = (response.status == 200)
	except Exception, err:
		print err
	
	conn.close()	
	return status
1 Like

You’re also missing Key2-Key5 in your payload you are sending. Required even if not used. Check your App Server Log should have more details there.

You need to convert your object in JSON in PowerShell at least:

$data_params = @{
  Company="SEI";
  Key1="test";
  XFileRefXFileName="";
  XFileRefXFileDesc="string";
  RowMod="A"

} | ConvertTo-Json

2 Likes

Key2-Key5, should be optional, and when I am sending the request through the UI I do not include those, and it seems to work fine. I will try adding those to the fields, but I don’t think that is the issue.

After trying to add Key2-Key5 I am still getting the same error.

Ah, this does get me a new error. It is saying:

Invoke-RestMethod : {"HttpStatus":400,"ReasonPhrase":"REST API Exception","ErrorMessage":"PK is not found for ..","ErrorType":"Ice.Common.BusinessObjectException","ErrorDetails":[{"Message":"PK is not found for ..","Type":"Error" ,"Table":"XFileAttch","Program":"Epicor.RESTApi.dll","Method":"ThrowUpdateExtRESTApiException","ColumnNumber":17,"LineNumber":184}]}

This error feels familiar, I will go try to replicate it in the UI and see what I am missing.

Yes, now you have error from inside service. And before it was deserialization problem, your data could not be deserialized into what server expected

1 Like

This worked! Thank you.

The error I was getting was due to missing a parameter. I was missing the parameter in the PowerShell code, but not the python code, so I must have overlooked it.

But the working code is:

    $Bytes = [System.Text.Encoding]::Ascii.GetBytes($Text)
    $EncodedText = [Convert]::ToBase64String($Bytes)
    $header = @{Authorization="Basic $EncodedText"}
    $data_params = @{
      Company="SEI";
      RelatedToSchemaName="Erp";
      RelatedToFile="DMRHead";
      Key1="test";
      XFileRefXFileName="";
      XFileRefXFileDesc="string";
      RowMod="A"
    } | ConvertTo-Json

    Invoke-RestMethod https://epicor10/EpicorERPTEST/api/v1/Ice.BO.AttachmentSvc/Attachments - Method Post -ContentType "application/json" -headers $header -body $data_params

Thanks again!

Edit: Converting to a json, and adding the ContentType header to the python code worked as well.

Here is the working python code:


input_params =json.dumps({
  "Company": "SEI",
  "RelatedToSchemaName": "Erp",
  "RelatedToFile": "DMRHead",
  "Key1": "test",
  "Key2": "test",
  "Key3": "test",
  "Key4": "test",
  "Key5": "test",
  "XFileRefXFileName": "",
  "XFileRefXFileDesc": "string",
  "RowMod": "A"
})

post = requests.post('https://epicor10/EpicorERPTEST/api/v1/Ice.BO.AttachmentSvc/Attachments',
                     data=input_params,
                     headers={'Authorization': f'Basic {base64_message}', 
                              'Content-Type': 'application/json'},
                     verify=False)

1 Like