This guide explains how to send and receive a Request over enmeshed Messages using two Connectors. The first of them, which we will refer to as the Sender, will send the Request. The second, which we will refer to as the Recipient, can decide, whether they want to accept or reject the Request. We’ll go through the steps of validating and creating the Request, sending and receiving it, and finally accepting or rejecting the Request.

This guide assumes that you already have an active Relationship between the two Connectors, e.g. from following the Integration Example or the scenario page Requests via RelationshipTemplates. If that is not the case, either take a look at those guides first or follow the instructions of how to establish a Relationship to another Identity.

In order to send a Message to the Recipient, it is required to know their enmeshed address. To retrieve it, the Sender can query their Relationships and look for the right one.

[
  // ...
  {
    "id": "REL..",
    "status": "Active",
    // ...
    "peer": "did:e:..."
  }
]

Look for the correct Relationship and save its peer property. You are going to need it later.

Check the Request’s validity

Firstly, you should check if your Request is valid. As an example, we use a Request with just an AuthenticationRequestItem, but you can use any Request you want. For an overview of the available RequestItems, check out our Request and Response introduction.

Even though the peer property is optional, it is recommended to specify it whenever possible. This allows additional validation rules to execute. If you are sending a Request via Message, you’ll always know the peer, as it is the recipient of the Message.

{
  "content": {
    "items": [
      {
        "@type": "AuthenticationRequestItem",
        "mustBeAccepted": true,
        "title": "The Sender is asking for an authentication."
      }
    ]
  },
  "peer": "<address of Recipient>"
}

Create the Request

If the previous step was successful, you can create the Request. For this, use the same payload you just validated.

In the response, you can see that the Request currently has the status "Draft". Also, note that the content was extented by the @type property and a generated id, that you didn’t have to specify manually.

Example response:

{
  "id": "REQ...",
  "isOwn": true,
  "peer": "<address of Recipient>",
  "createdAt": "<time of creation>",
  "content": {
    "@type": "Request",
    "id": "REQ...",
    "items": [
      {
        "@type": "AuthenticationRequestItem",
        "mustBeAccepted": true,
        "title": "The Sender is asking for an authentication."
      }
    ]
  },
  "status": "Draft"
}

Save the complete content of the response. You will need it in the next step.

Send the Request

Now let’s transmit the Request to the Recipient. To do so, send a Message using the following payload and make sure to use the content you copied from the response, which has the @type property. This is important for the Request to be processed correctly, since it is possible to send different types of objects via Message.

{
  "recipients": ["<address of Recipient>"],
  "content": {
    // the content you copied from the response in the step before
  }
}

This is where the automation of the enmeshed Runtime steps in and moves the Request from status "Draft" to status "Open". You can observe this behaviour by querying the Request on the Sender Connector.

Fetch the Request

In order to fetch the Message with the Request, you have to synchronize the Recipient Connector. The enmeshed Runtime will read the Message and create a new incoming Request. You can observe this by long polling the incoming Requests and optionally use the query parameters source.reference=<ID of the Message> and status=ManualDecisionRequired to filter for Requests that belong to the Message that contained the Request.

In a productive environment, however, we recommend using the Sync module and waiting for a consumption.incomingRequestReceived Connector Event. To learn more about events, how to use them in the context of enmeshed and which modules are supported by enmeshed to help you automating your business process, check out our Event introduction.

After you received the Request, save its id for the next step.

Answer the Request

Accept

Firstly, let’s consider the case the Recipient wants to accept the Request. For this, use the id of the Request you saved in the previous step. In the payload you have to accept at least all RequestItems where the mustBeAccepted property is set to true. In case of the example Request, the payload is the following:

{
  "items": [
    {
      "accept": true
    }
  ]
}

Please note that if there are multiple RequestItems, some of which may be contained in a RequestItemGroup, these must be accepted in the exact order in which they were specified in the Request.

Reject

Now, let’s consider the case the Recipient wants to reject the Request. For this, use the id of the Request you saved in the previous step. In the payload you have to reject all RequestItems. In case of the example Request, the payload is the following:

{
  "items": [
    {
      "accept": false
    }
  ]
}

Runtime automation

No matter if you accepted or rejected the Request, the response will be similar. You can see that the Request moved to status "Decided". This is where the enmeshed Runtime steps in and handles the Request based on your decision. It will send the Response to the Sender via a Message and move the Request to status "Completed" . This behavior can be observed by querying the Request again after a few seconds.

Sync the Response

The Sender will receive the Response via a Message. For this, you have to synchronize the Sender Connector.

After a few seconds the Request has moved to status "Completed" and the Response is available in the response property of the Request. You can observe this by querying the Request on the Sender Connector.