API with Power Automate and Azure Functions - Error 400

I use Power Automate and Dynamics for many of my tasks and was excited to see API support.

I created an azure function to calculate the MD5 has which seems to be working well:

Python code:

import hashlib
import json
import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:
    req_body = req.get_json()  # Parse the JSON request body

    # Access the 'req' field from the JSON payload
    if 'req' in req_body:
        input_string = req_body['req']
        md5_hash = get_md5_hash(input_string)

        response_data = {
            "req": input_string,
            "md5_hash": md5_hash
        }

        return func.HttpResponse(json.dumps(response_data), headers={"Content-Type": "application/json"})
    else:
        return func.HttpResponse("Invalid request", status_code=400)

def get_md5_hash(input_string: str) -> str:
    md5 = hashlib.md5()
    md5.update(input_string.encode('utf-8'))
    return md5.hexdigest()

I call this function with the string as told, I use GUID() in power automate to generate a new, random submission ID on every run; the submission would look like this: f2364b6e-3b41-478a-84e2-416e1730afb0

Because I need to have the root node “Payload” I struggle with the API. I create the content (copy / paste from the example provided in the API documentation:

JSON Payload

{
  "payload": {
    "Header": {
      "MessageType": "Request",
      "SubmissionNumber": "@{outputs('Submission_No')}",
      "Authentication": {
        "AccNumber": "@{outputs('Account')}",
        "MD5Value": "@{outputs('MD5_Hash_Value')}",
        "ApplicationID": "@{outputs('Application_ID')}"
      }
    },
    "Body": {
      "InvoiceData": {
        "InvoiceType": "INVOICE",
        "ClientID": "1343151",
        "ClientAddress": {
          "Address": "123 Test Street<br/>Manchester<br/>MA1 5TH<br/>United Kingdom",
          "CountryISO": "GB"
        },
        "Currency": "GBP",
        "TermDays": "14",
        "Language": "en",
        "InvoiceLines": {
          "ItemLines": {
            "ItemLine": [
              {
                "ItemID": "0",
                "ItemName": "BC1",
                "ItemDescription": "300 Business Cards (250gsm)",
                "ItemNominalCode": "4000",
                "Tax1": {
                  "TaxName": "VAT",
                  "TaxPercentage": "20.00",
                  "TaxAmount": "20"
                },
                "UnitCost": "100",
                "Qty": "1"
              },
              {
                "ItemID": "0",
                "ItemName": "EMB1",
                "ItemDescription": "Embossing Stamp",
                "ItemNominalCode": "4000",
                "Tax1": {
                  "TaxName": "VAT",
                  "TaxPercentage": "20.00",
                  "TaxAmount": "10"
                },
                "UnitCost": "50",
                "Qty": "1"
              }
            ]
          }
        },
        "Scheduling": {
          "SingleInvoiceData": {
            "IssueDate": "2023-07-07",
            "PurchaseReference": "0095446"
          }
        }
      }
    }
  }
}

I transfer the body through http to another azure function to forward this without injecting a header, body or changing the root node:

import json
import logging
import azure.functions as func
import http.client

def main(req: func.HttpRequest) -> func.HttpResponse:
    try:
        # Read the body of the HTTP request
        req_body = req.get_body().decode('utf-8')

        # Construct the payload for the API
        api_payload = req_body

        # Send the payload to the API
        api_url = "api.quickfile.co.uk:443"
        endpoint = "/1_2/invoice/create"

        connection = http.client.HTTPSConnection(api_url)
        connection.request("POST", endpoint, api_payload)

        response = connection.getresponse()
        
        status_code = response.status
        response_body = response.read().decode('utf-8')

        if status_code == 200:
            response_msg = "Payload sent successfully"
        else:
            response_msg = f"API request failed with status code: {status_code}"

        return func.HttpResponse(
            body=response_msg,
            status_code=status_code,
            headers={"Content-Type": "text/plain"}
        )

    except Exception as e:
        logging.error(str(e))
        return func.HttpResponse("Internal Server Error", status_code=500)

I receive an error 400 from the API and no further information / text.

If I would not need the root node “payload” I could use the default header and body http post function in power automate.

Has anyone solved this to connect the quickfile API with the microsoft power automate world? Happy for any other approach that may be worth exploring.

Hi @goetz

Just to confirm, although the inner elements of the payload are “header” and “body”, they should all be in the body of the request, wrapped in the payload element.

So your entire JSON payload would just be in the body of the request.

Is this what you’re doing at the moment?

1 Like

yes, that is what I am doing; The http post submits the JSON payload as above without any additions or edits.

I also checked the function for the MD5 hash and the MD5 hash should be correct and generated an MD5 hash with other tools matching the one I have.

Looks as of the formatting is using escape characters in the submission but I would assume this should cause an issue:

{\"payload\":{\"Header\":{\"MessageType\":\"Request\",\"SubmissionNumber\":\"074c3842-38d1-4c21-a6ef-############\",\"Authentication\":{\"AccNumber\":\"##############\",\"MD5Value\":\"a40701326d2fac7350b712b9##########\",\"ApplicationID\":\"c14a16c5-d0e3-45e9-8eb2-###########\"}},\"Body\":{\"InvoiceData\":{\"InvoiceType\":\"INVOICE\",\"ClientID\":\"CUS-000101\",\"ClientAddress\":{\"Address\":\"123 Test Street<br/>Manchester<br/>MA1 5TH<br/>United Kingdom\",\"CountryISO\":\"GB\"},\"Currency\":\"GBP\",\"TermDays\":\"14\",\"Language\":\"en\",\"InvoiceLines\":{\"ItemLines\":{\"ItemLine\":[{\"ItemID\":\"0\",\"ItemName\":\"BC1\",\"ItemDescription\":\"300 Business Cards (250gsm)\",\"ItemNominalCode\":\"4000\",\"Tax1\":{\"TaxName\":\"VAT\",\"TaxPercentage\":\"20.00\",\"TaxAmount\":\"20\"},\"UnitCost\":\"100\",\"Qty\":\"1\"},{\"ItemID\":\"0\",\"ItemName\":\"EMB1\",\"ItemDescription\":\"Embossing Stamp\",\"ItemNominalCode\":\"4000\",\"Tax1\":{\"TaxName\":\"VAT\",\"TaxPercentage\":\"20.00\",\"TaxAmount\":\"10\"},\"UnitCost\":\"50\",\"Qty\":\"1\"}]}},\"Scheduling\":{\"SingleInvoiceData\":{\"IssueDate\":\"2023-07-07\",\"PurchaseReference\":\"0095446\"}}}}}}

for a trial I did add to the azure function:

import html

and

    # Remove escape characters from the payload
    req_body = html.unescape(req_body)

But this did resolve it. Still receiving Error Code 400.

Let me send you a private message, and we can take a look at the code in more detail.

1 Like

For anyone who may try to solve this; Azure API Management was easier than the function to integrate quickfile but the original code was working. Only issue I had was the calculation of the hash was wrong, i used the ApplicationID instead of API key.

1 Like