Introduction

In this tutorial we will create a contract between a transport company and a producer of fragile goods for the transportation of said fragile goods.

The delicate cargo will include an accelerometer, which will continuously monitor and store the amount of shock the cargo is exposed to, to be fed into the contract on arrival.

The contract will then deduct an agreed-upon amount for every reading that exceeds an agreed-upon threshold.

1.Contract, Signatory & Clause

Let's start by creating a contract, adding a signatory (other than yourself), and adding the fragile-goods clause to the contract:

  • Contracts -> New Contract
  • Edit Title -> Enter Contract Title
  • Add Signatory
  • Add Clause -> fragile-goods


2. Create Trigger flow

Next we'll create a trigger flow that converts an array of accelerometer readings POSTed to the flow trigger into the full clause trigger payload, documented here as:

{
    "$class": "io.clause.demo.fragileGoods.DeliveryUpdate",
    "startTime": TIMESTAMP,
    "finishTime": TIMESTAMP,
    "status": "ARRIVED",
    "accelerometerReadings": [
        READING1,
        READING2,
        ...
    ]
}

We will generate this trigger payload from the input payload using a JSONata step with the following expression (the full JSONata referene can be found here):

{
    "$class": "io.clause.demo.fragileGoods.DeliveryUpdate",
    "startTime": $now(),
    "finishTime": $now(),
    "status": "ARRIVED",
    "accelerometerReadings": step[0].output
}

Note the use of step[0].output to reference the trigger payload. In other examples, we will use the step array more extensively, to also reference the output of previous steps in the flow.

  • Edit Clause
  • Add additional trigger flow
  • Flow Name
  • Trigger Type -> HTTP
  • Add Step -> JSONata
  • JSONata Expression
  • Save


To trigger the flow, first take note of the trigger url and the authentication token in the flow dialog (viewed by editing the trigger flow)

  • Edit Flow

Next, test that you can trigger the flow by making an HTTP POST request to the trigger url retrieved above, with the token set as Bearer token in the Authorization header. 

Example using curl: 

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TRIGGER_FLOW_TOKEN" -d '{"request":[0.6,-0.7,0.4]}' TRIGGER_FLOW_URL

NB: Note that the input payload has to be sent as the request attribute of the POST body. Sending the bare array as POST body will also work, but not when used in conjunction with contract testing, which requires other attributes like contract status to also be sent in the POST body. Make it a habit to always use the request attribute.

This should result in the following response:

{
  "response": {
    "$class": "io.clause.demo.fragileGoods.PayOut",
    "amount": {
      "$class": "org.accordproject.money.MonetaryAmount",
      "doubleValue": 990,
      "currencyCode": "USD"
    },
    "transactionId": "9bf0b153-99e8-42eb-b41d-f0d30f5817cb",
    "timestamp": "2019-10-21T12:13:22.567Z",
    "test": true,
    "message": "Contract 'untitled' (5dad837799b2a6001b8aa35a) has not been signed by all signatories.\nThis response should only be used for testing your API.\n\nOnce the contract has been signed by all signatories:\n- Obligations emitted by clauses will be processed\n- Clauses will maintain state between requests"
  }
}



Let's pause for a moment and analyse what had just happened:

Take the time and review the fragile-goods contract template logic. You'll notice that the template by default pays out 1000 USD for a successful delivery, but it also deducts 5 USD for every accelerometer reading outside of the range of -0.5, 0.5 (up to a maximum of 200 USD).

Because two of the readings we sent in the array we're outside of the -0.5, 0.5 range, 10 USD was deducted from the total (1000 USD), resulting in a calculated payout of 990 USD.

This is all completely hypothetical though, as the contract has not been signed yet, indicated by the "test": true flag in the trigger response, as well as the long "message" attribute stating the fact explicitly.

You can see the fact that the smart clause has been triggered in the contract timeline.

If you click on details, you can view the payload it has been triggered with, the response, and any obligations that might have been emitted.

3. Create Action Flow

Before we get the contract signed and active, let's first add an action flow to notify us by email whenever the contract gets triggered, and notify us how much was paid out. To this effect, we will configured the email body to reference the paid amount and currency code from the emitted obligation as such:

{{step[0].output.amount.doubleValue}} {{step[0].output.amount.currencyCode}} has been paid out
  • Edit Clause
  • Add additional action flow
  • Flow Name
  • Add Step -> Email
  • Email step input attributes
  • Save

4. Request Signatures

Click on Request Signatures, and follow the dialog to sign the contract and request a signature fro the second signatory. Once the contract has been signed by both parties, its status should be running.

5. Trigger the Flow

Now repeat the trigger you sent to the flow earlier, after creating it:

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TRIGGER_FLOW_TOKEN" -d '{"request":[0.6,-0.7,0.4]}' TRIGGER_FLOW_URL

This time, the payload should look slightly different:

{
  "response": {
    "$class": "io.clause.demo.fragileGoods.PayOut",
    "amount": {
      "$class": "org.accordproject.money.MonetaryAmount",
      "doubleValue": 990,
      "currencyCode": "USD"
    },
    "transactionId": "8e871f54-b106-4e9a-b556-eaa30851c598",
    "timestamp": "2019-10-21T13:27:11.771Z"
  }
}

Notice the missing test and message attributes?

Also, the following mail should be in the inbox of the email address that was configured in the Email Action Step:


6. Conclusion

While this is a very basic example, it illustrates how to use flow expressions to reference values from trigger payloads (in the case of trigger flows) and obligations (in the case of action flows), by referencing step[0] (the flow input).

Next, we'll look at a more complex flow example that demonstrates the use of step[n] where n > 0 to access outputs of user-defined steps in the flow.