Outbound: Send messages to the network (/ReceiveMessage)#

Although this service is called ReceiveMessage, it allows you to send a message to SOVOS Saphety’s network;
The method name ReceiveMessage is given from the network perspective.
The following example shows how to send a file to the network.
This file is just an example; its content can be any commercial document (Invoice, Debit, Order etc.).

fileText = '<invoice><number>inv001<number><date>2019-04-19</date><value>115.00</value></invoice>'

First read the file content and convert to it Base64. Following is:

fileBase64 = 'PGludm9pY2U+DQo8bnVtYmVyPmludjAwMTxudW1iZXI+DQo8ZGF0ZT4yMDE5LTA0LTE5PC9kYXRlPg0KPHZhbHVlPjExNSwwMDwvdmFsdWU+DQo8L2ludm9pY2U+'

The file content encoded in Base64 is transmitted in the **Base64Data**request property.

The request message#

The request payload has the following properties:

  • Sender
    Your UserId (Partner Id / network identification) as described in Onboarding

  • Receiver
    Saphety WS endpoint:
    QA: urn:netdoc:qa
    PRD: urn:netdoc:prd

  • ContentType
    File content type, ex: application/xml

  • Base64Data
    File contents encoded in Base64

  • MessageId
    A message identifier for control, use a GUID

  • Filename
    The filename being transferred

# Set Environment
#Integration
server_base_adress = "saphetydoc-int.saphety.com/TradeHttp/MessageServiceRest"
#Quality
#server_base_adress = "www-qa.netdocs.com.pt/TradeHttp/MessageServiceRest"
#Production
#server_base_adress = "https://wsrest.netdocs.com.pt/TradeHttp/MessageServiceRest"

This authentication token is obtained using the API Authorization/GetTokenFromLogin as described in Click here to view Authorization API

Preparing the call to ReceiveMessage (send a file to the network)#

The token was obtained in the /GetTokenFromLogin

token ='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vd3d3LnNhcGhldHkuY29tL1RyYWRlIiwibmFtZWlkIjoiUFQ1MDAxMTExMTEiLCJzdWIiOiJQVDUwMDExMTExMSIsInVuaXF1ZV9uYW1lIjoiUFQ1MDAxMTExMTEiLCJqdGkiOiI2ODJjZGRkYzU0NWE0MGI5OTdlNGE4NDM1OGU1NmIyMSIsImV4cCI6MTY4MDQxNDQzMywiaWF0IjoxNjgwMzcxMjMzLCJuYmYiOjE2ODAzNzEyMzMsImF1ZCI6Imh0dHA6Ly93d3cuc2FwaGV0eS5jb20vVHJhZGUifQ.X7zRQ81cylFv-9Qqv3-tdTLCPraPaJrw72N5Du-kqMo'
## Get a JWT token from your username and password
import requests
import json

# service url
service_url = "https://" + server_base_adress + "/ReceiveMessage"

payload = {
    'Sender': 'PT500111111',
    'Receiver': 'urn:netdoc:qa',
    'ContentType': 'application/xml',
    'Base64Data': fileBase64,
    'MessageId': 'de10ebd5-eef5-421e-9ee5-f08f59dfa327',
    'Filename':'invoice001.xml'
}
# Payload goes in json, serialize the payloal object to json
request_data=json.dumps(payload)
# Indicate in header that payload is json
headers = {
    'Authorization': 'Bearer ' + token,
    'Content-type': 'application/json'
}
# POST request to get a token
response = requests.request("POST", service_url, data=request_data, headers=headers)
print(response)
# Serialize the response
json_response = json.loads(response.text)
print(json.dumps(json_response, indent=4))
<Response [200]>
{
    "CorrelationId": "5ee45bcb-b484-4b47-b836-185e1fcaa447",
    "Errors": [],
    "IsValid": true,
    "ResultCode": 200,
    "ResultData": {
        "Messages": [
            {
                "Base64Data": "",
                "ContentType": "application/xml",
                "Direction": "IN",
                "Filename": "invoice001.xml",
                "MessageId": "20230401180927.da212f8d-ffc3-438d-98c2-bb46fb307223@l-tst-fes29",
                "OriginalMessageId": "de10ebd5-eef5-421e-9ee5-f08f59dfa327",
                "Receiver": "urn:netdoc:qa",
                "Sender": "PT500111111"
            }
        ]
    },
    "Warnings": []
}

The response from the server is a generic message response as explained in Response messages from server.
In this case the ResultData property is a list of Message objects.
The Message represent the objects created on trade for a given comunication.
The MessageId is Trade’s key on the message.
The OriginalMessageId is the senders OriginalMessageId, allowing a correllation between the senders and Trade’s message identification.

Inbound: Receive messages from the network (/GetMessageData)#

The network reception services acts like a queue for your incoming messages.
It is a pool system and you have to retrieve the messages that have been sent to you.
You need to performer the following steps:

  1. Get the list of inbound messages (these messages can be any document type, ORDERS, INVOICE, DESADV, STATUS, etc);
    For each message you will obtain the message identifier (Message ID).
    This is done using the service ListQueuedMessageIds.

  2. With the previous Message ID, you can obtain your message content. This is done using the service GetMessageData.

  3. After downloading a message, you need to mark it as Processed, so that message is removed from your queue. This is done using the service ChangeQueuedToProcessed

Get a list of your inbound messages (/ListQueuedMessageIds)#

This service is called with a simple GET with the following url parameters:

print('https://' + server_base_adress + '/ListQueuedMessageIds?Receiver={receiver}')
https://saphetydoc-int.saphety.com/TradeHttp/MessageServiceRest/ListQueuedMessageIds?Receiver={receiver}

Where {receiver} is your UserId in the network (PartnerId) as defined in Onboarding.
This will list all messages that are available to download.
This service also support additional fields capabilities such as the “Sender”. Consult the Swagger documentation to more details.
Sample request:

receiver = 'PT500111111' 
# Build the url
service_url = 'https://' + server_base_adress + '/ListQueuedMessageIds?Receiver=' + receiver;
# Use GET to send the request
response = requests.request("GET", service_url, headers=headers)
# Serializethe response
json_response = json.loads(response.text)
# The result is cutted for better readability
json_response["ResultData"]["MessageIds"] = json_response["ResultData"]["MessageIds"][:2];
print(json.dumps(json_response, indent=4))
{
    "CorrelationId": "5f09eb98-4c3a-46c2-954b-467934e98824",
    "Errors": [],
    "IsValid": true,
    "ResultCode": 200,
    "ResultData": {
        "MessageIds": [
            {
                "MessageId": "20230102180311.912cc122-e47d-4b22-b26d-e4d8eb9940e2@l-tst-fes29",
                "Receiver": "PT500111111",
                "Sender": "5600000002186",
                "Status": "QUEUE"
            },
            {
                "MessageId": "20230329185038.9e365423-485b-469a-a992-425d589c0118@l-tst-fes29",
                "Receiver": "PT500111111",
                "Sender": "5600000002186",
                "Status": "QUEUE"
            }
        ]
    },
    "Warnings": []
}

The previous response indicate you have 2 messages available to download with the Message Id:

for message in json_response["ResultData"]["MessageIds"]:
    print(json.dumps(message["MessageId"], indent=4))
"20230102180311.912cc122-e47d-4b22-b26d-e4d8eb9940e2@l-tst-fes29"
"20230329185038.9e365423-485b-469a-a992-425d589c0118@l-tst-fes29"

Downloading a message (/GetMessageData)#

To retrieve the message content, you need to call the GetMessageData as following:

print('https://' + server_base_adress + '/GetMessageData?Receiver={receiver}&MessageId={messageId}&Sender={sender}')
https://saphetydoc-int.saphety.com/TradeHttp/MessageServiceRest/GetMessageData?Receiver={receiver}&MessageId={messageId}&Sender={sender}
receiver = 'PT500111111'
messageId = '20230102180311.912cc122-e47d-4b22-b26d-e4d8eb9940e2@l-tst-fes29'
sender = '5600000002186'
# Build the url
service_url = 'https://' + server_base_adress + '/GetMessageData?Receiver=' + receiver + '&MessageId=' + messageId + '&Sender=' + sender;
# Use GET to send the request
response = requests.request("GET", service_url, headers=headers)
# Serializethe response
json_response = json.loads(response.text)
print(json.dumps(json_response, indent=4))
{
    "CorrelationId": "8c9fc0fa-d0f0-4c1d-bc2b-25b22542d559",
    "Errors": [],
    "IsValid": true,
    "ResultCode": 200,
    "ResultData": {
        "Base64Data": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtc2c6bWVzc2FnZSBpZD0iYTExMmI4ZWEtNjk4Mi0xMWVkLWExZWItMDI0MmFjMTIwMDAyIiBjcmVhdGlvbkRhdGVUaW1lPSIyMDIzLTAxLTAyVDE4OjAxOjAwIiB4bWxuczptc2c9InVybjpuZXRkb2NzOnNjaGVtYXM6bWVzc2FnZSI+DQogIDxzZW5kZXI+DQogICAgPGlkIGVudGl0eUlkVHlwZUNvZGVkPSJWQVQiPjUwMDExMTExMTwvaWQ+DQogICAgPGlkIGVudGl0eUlkVHlwZUNvZGVkPSJHTE4iPjU2MDExMTExMTExMTg8L2lkPg0KICAgIDxuYW1lPlNhbXBsZSBzdXBwbGllcjwvbmFtZT4NCiAgICA8YWRkcmVzc0luZm9ybWF0aW9uPg0KICAgICAgPGFkZHJlc3M+UnVhIGRvIEZvcm5lY2Vkb3IgRXhlbXBsbzwvYWRkcmVzcz4NCiAgICAgIDxjaXR5PkNpdHkgbmV3PC9jaXR5Pg0KICAgICAgPHBvc3RhbENvZGU+DQogICAgICAgIDx6aXA+MTAwMC0wMDA8L3ppcD4NCiAgICAgICAgPGFyZWE+QXJlYTE8L2FyZWE+DQogICAgICA8L3Bvc3RhbENvZGU+DQogICAgICA8Y291bnRyeUNvZGU+UFQ8L2NvdW50cnlDb2RlPg0KICAgIDwvYWRkcmVzc0luZm9ybWF0aW9uPg0KICA8L3NlbmRlcj4NCiAgPHJlY2VpdmVyPg0KICAgIDxpZCBlbnRpdHlJZFR5cGVDb2RlZD0iVkFUIj41Mzc4NzgyMDM8L2lkPg0KICAgIDxuYW1lPkJhdGF0YXM8L25hbWU+DQogICAgPGFkZHJlc3NJbmZvcm1hdGlvbj4NCiAgICAgIDxhZGRyZXNzPlJ1YSBUZXN0ZSBkbyB0ZXN0ZTwvYWRkcmVzcz4NCiAgICAgIDxjaXR5Pkxpc2JvYTwvY2l0eT4NCiAgICAgIDxwb3N0YWxDb2RlPg0KICAgICAgICA8emlwPjEwMDA8L3ppcD4NCiAgICAgICAgPGFyZWE+MTAwPC9hcmVhPg0KICAgICAgPC9wb3N0YWxDb2RlPg0KICAgICAgPGNvdW50cnlDb2RlPlBUPC9jb3VudHJ5Q29kZT4NCiAgICA8L2FkZHJlc3NJbmZvcm1hdGlvbj4NCiAgPC9yZWNlaXZlcj4NCjxkb2M6ZG9jdW1lbnRTdGF0dXMgZG9jdW1lbnROdW1iZXI9IlRNLTY1IiBkb2N1bWVudERhdGU9IjIwMjMtMDEtMDIiIHNjaGVtYVZlcnNpb249IjEuMSIgcHVycG9zZT0iT1JJR0lOQUwiIHhtbG5zOmRvYz0idXJuOm5ldGRvY3M6c2NoZW1hczpkb2N1bWVudCI+DQogIDxvcmlnaW5hbERvY3VtZW50UmVmZXJlbmNlPg0KICAgIDxvcmlnaW5hbFNlbmRlcj4NCiAgICAgIDxpZCBlbnRpdHlJZFR5cGVDb2RlZD0iVkFUIj41MDAxMTExMTE8L2lkPg0KICAgICAgPGlkIGVudGl0eUlkVHlwZUNvZGVkPSJHTE4iPjU2MDExMTExMTExMTg8L2lkPg0KICAgICAgPG5hbWU+U2FtcGxlIHN1cHBsaWVyPC9uYW1lPg0KICAgICAgPGFkZHJlc3NJbmZvcm1hdGlvbj4NCiAgICAgICAgPGFkZHJlc3M+UnVhIGRvIEZvcm5lY2Vkb3IgRXhlbXBsbzwvYWRkcmVzcz4NCiAgICAgICAgPGNpdHk+Q2l0eSBuZXc8L2NpdHk+DQogICAgICAgIDxwb3N0YWxDb2RlPg0KICAgICAgICAgIDx6aXA+MTAwMC0wMDA8L3ppcD4NCiAgICAgICAgICA8YXJlYT5BcmVhMTwvYXJlYT4NCiAgICAgICAgPC9wb3N0YWxDb2RlPg0KICAgICAgICA8Y291bnRyeUNvZGU+UFQ8L2NvdW50cnlDb2RlPg0KICAgICAgPC9hZGRyZXNzSW5mb3JtYXRpb24+DQogICAgPC9vcmlnaW5hbFNlbmRlcj4NCiAgICA8b3JpZ2luYWxEb2N1bWVudCB0eXBlPSJVTktOT1dOIiByZWZlcmVuY2VkRG9jdW1lbnREYXRlPSIyMDE5LTAxLTE2IiByZWZlcmVuY2VkRG9jdW1lbnRJZD0iYTExMmI4ZWEtNjk4Mi0xMWVkLWExZWItMDI0MmFjMTIwMDAyIj5UTS02NTwvb3JpZ2luYWxEb2N1bWVudD4NCiAgICA8b3JpZ2luYWxNZXNzYWdlSWQ+YWE3ZWRiOTQtNTMwZC0zYTFmLWI5NzktZDg4NDljM2VjMDAxPC9vcmlnaW5hbE1lc3NhZ2VJZD4NCiAgPC9vcmlnaW5hbERvY3VtZW50UmVmZXJlbmNlPg0KICA8c3RhdHVzSW5mb3JtYXRpb24+PC9zdGF0dXNJbmZvcm1hdGlvbj4NCjwvZG9jOmRvY3VtZW50U3RhdHVzPjwvbXNnOm1lc3NhZ2U+",
        "ContentType": "application/xml",
        "Filename": "STATUS-MESSAGE-Accepted-202301021801-eb92698f-5a81-4d6c-9245-000687e7201b.xml",
        "MessageId": "20230102180311.912cc122-e47d-4b22-b26d-e4d8eb9940e2@l-tst-fes29",
        "Receiver": "PT500111111",
        "Sender": "5600000002186",
        "Status": "QUEUE"
    },
    "Warnings": []
}

The ContentType indicate the file type being download (ex: XML, Text, CSV, etc) and the content itself is encoded in Base64 in the Base64Data.

Marking the message as Processed (/ChangeQueuedToProcessed)#

After retrieving the documents from your queue, it is required to mark then as processed. This operation removes the document from the queue.

service_url = "https://" + server_base_adress + "/ChangeQueuedToProcessed"
payload = {
    'Sender': sender,
    'Receiver': receiver,
    'MessageId': messageId
}
# Payload goes in json, serialize the payloal object to json
request_data=json.dumps(payload)
# Indicate in header that payload is json
headers = {
    'Authorization': 'Basic ' + token,
    'Content-type': 'application/json'
}
# POST request to get a token
response = requests.request("POST", service_url, data=request_data, headers=headers)
# Serializethe response
json_response = json.loads(response.text)
print(json.dumps(json_response, indent=4))
{
    "CorrelationId": "ce86d850-86e1-42ad-a0c2-4622184665a4",
    "Errors": [
        {
            "Code": null,
            "Description": "The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. ",
            "ExplanationValues": [],
            "Field": null
        }
    ],
    "IsValid": false,
    "ResultCode": 500,
    "ResultData": null,
    "Warnings": []
}