Transactions

The scope of this tutorial is to make your first transactions and have an overview of the capabilities of Canyan Rating and how to use its functionalities with your system.

After performing an authorization and gathering the prioritized list of carriers to use a transaction is run. There are two different modalities that can be used to record a transaction:

  • begin/end transaction methods
  • record transaction

The usage should be based on the preferences and requirements of the system the Rating Engine is integrated with. Normally the begin/end transaction is used when a push notification to end an ongoing transaction is required. Having a list of ongoing transaction in the Rating Engine is useful for fraud protection and limiting usage of the services like concurrent transactions.

The record transaction method instead could be used to record a transaction that does not lasts over a time period or to perform a rating calculation from a list of transactions not covered in real time by the Rating Engine. For example a list of CDRs that needs to be rated and produced by a system that does not integrate the Rating Engine.

Prerequisites

The test environment should be set up and running successfully as described in Running Canyan Rating section. You should have a basic set of data populated in your Canyan Rating instance as described in the Inserting Data Tutorial. The following commands and requests relay on the same data inserted in the above tutorial. If you populated different data you should change the commands in this tutorial accordingly.

It is assumed that the API is running on localhost:8000 and the Agent on localhost:8080.

Begin Transaction

Let's start opening a new transaction for a call towards Italy performed by the account 100:

curl "http://localhost:8080/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "mutation {
    beginTransaction(
        transaction_tag: \"transaction1\",
        account_tag: \"100\",
        source: \"sip:10.0.0.1:5060\",
        destination: \"39040123123\"
    ) {
        ok
    }
  }"
}
EOF

The response should give us a confirmation like this:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "beginTransaction": { 
      "ok": True 
    }
  }
}

Now if we request the API for the account's 100 running transactions we should see our transaction1 in the list:

curl "http://localhost:8000/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "{
  allAccounts(filter: { account_tag:\"100\" }) {
    account_tag
    name
    type
    balance
    pricelist_tags
    running_transactions {
      transaction_tag
      source
      destination
      carrier_ip
      in_progress
      inbound
      timestamp_begin
      timestamp_end
    }
  }
}"
}
EOF

Response:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "allAccounts": [
      {
        "account_tag": "100",
        "name": "My first account",
        "type": "PREPAID",
        "balance": 100,
        "pricelist_tags": [
          "pricelist2"
        ],
        "running_transactions": [
          {
            "transaction_tag": "transaction1",
            "source": "sip:10.0.0.1:5060",
            "destination": "39040123123",
            "carrier_ip": "localhost:5061",
            "destination_rate": 20,
            "in_progress": true,
            "inbound": false,
            "timestamp_begin": "2019-08-15T21:26:17Z",
            "timestamp_end": ""
          }
        ]
      }
    ]
  }
}

transaction1 is there!

End Transaction

Using the beginTransaction method, once the user ended the call, we need to signal it to the Rating Engine. We use the endTransaction method like this:

curl "http://localhost:8080/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "mutation {
    endTransaction(
        transaction_tag: \"transaction1\",
        account_tag: \"100\"
    ) {
        ok
    }
  }"
}
EOF

The response is confirming the end of the open transaction.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "endTransaction": { 
      "ok": True 
    }
  },
  "errors": null
}

If we now redo the query on the account we can notice two different scenarios.

If the transaction is not processed it will still be in the running transactions with a timestamp end set and the in_progress field set to false and the balance still intact. Every calculation of the current user balance takes in consideration also the running transactions.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "allAccounts": [
      {
        "account_tag": "100",
        "name": "My first account",
        "type": "PREPAID",
        "balance": 100,
        "pricelist_tags": [
          "pricelist2"
        ],
        "running_transactions": [
          {
            "transaction_tag": "transaction1",
            "source": "sip:10.0.0.1:5060",
            "destination": "39040123123",
            "carrier_ip": "localhost:5061",
            "destination_rate": 20,
            "in_progress": true,
            "inbound": false,
            "timestamp_begin": "2019-08-15T21:26:17Z",
            "timestamp_end": "2019-08-15T21:46:17Z"
          }
        ]
      }
    ]
  }
}

The second scenario is that the transaction has been processed, there is no more a running transaction in the account info and the balance of the account has been diminished.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "allAccounts": [
      {
        "account_tag": "100",
        "name": "My first account",
        "type": "PREPAID",
        "balance": 80,
        "pricelist_tags": [
          "pricelist2"
        ],
        "running_transactions": []
      }
    ]
  }
}

In this case, the transaction has been saved and it is listed with the following requests to the API:

curl "http://localhost:8000/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "{Transaction(
    transaction_tag: \"transaction1\", 
    account_tag: \"100\"
  ) {
    id
    transaction_tag
    account_tag
    source
    source_ip
    destination
    destination_rate {
      pricelist_tag
      carrier_tag
      prefix
      connect_fee
      rate
      rate_increment
      interval_start
    }
    carrier_ip
    authorized
    timestamp_auth
    timestamp_begin
    timestamp_end
    inbound
    failed
    duration
    fee
  }
}"
}
EOF

Record Transaction

If you need to write the transaction directly and avoid making the two requests startTransaction and endTransaction you can use the request recordTransaction:

curl "http://localhost:8080/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "mutation {
    recordTransaction(
        transaction_tag: \"transaction2\",
        account_tag: \"100\",
        source: \"sip:10.0.0.1:5060\",
        destination: \"39040123123\",
        timestamp_auth: \"2019-08-15T21:26:15Z\",
        timestamp_begin: \"2019-08-15T21:26:17Z\",
        timestamp_end: \"2019-08-15T21:26:55Z\"
    ) {
        ok
    }
  }"
}
EOF

The response should give us a confirmation like this:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "recordTransaction": { 
      "ok": True 
    }
  }
}

The transaction is now visible with the request:

curl "http://localhost:8000/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "{Transaction(
    transaction_tag: \"transaction2\", 
    account_tag: \"100\"
  ) {
    id
    transaction_tag
    account_tag
    source
    source_ip
    destination
    destination_rate {
      pricelist_tag
      carrier_tag
      prefix
      connect_fee
      rate
      rate_increment
      interval_start
    }
    carrier_ip
    authorized
    timestamp_auth
    timestamp_begin
    timestamp_end
    inbound
    failed
    duration
    fee
  }
}"
}
EOF
HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "Transaction": {
      "id": "0fa4a1b7-cc13-47a7-a4ae-2174e548fb19",
      "transaction_tag": "transaction2",
      "account_tag": "100",
      "source": "sip:10.0.0.1:5060",
      "destination": "39040123123",
      "destination_rate": {
        "pricelist_tag": "pricelist1",
        "carrier_tag": "carrier1",
        "prefix": "39",
        "connect_fee": 0,
        "rate": 20,
        "rate_increment": 60,
        "interval_start": 0
      },
      "carrier_ip": "localhost:5061",
      "authorized": null,
      "timestamp_auth": "2019-08-15T21:26:15Z",
      "timestamp_begin": "2019-08-15T21:26:17Z",
      "timestamp_end": "2020-01-15T14:26:55",
      "inbound": false,
      "failed": false,
      "duration": 38,
      "fee": 20
    }
  },
  "errors": null
}

Rollback Transaction

This method allows the rollback of a particular transaction.

curl "http://localhost:8080/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "mutation {
    rollbackTransaction(
        transaction_tag: \"transaction2\",
        account_tag: \"100\"
    ) {
        ok
    }
  }"
}
EOF

The response should give us a confirmation like this:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "rollbackTransaction": { 
      "ok": True 
    }
  }
}

And if we recheck the transaction via our usual request to the API:

curl "http://localhost:8000/graphql" \
  -X POST \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{"query": "{Transaction(
    transaction_tag: \"transaction2\", 
    account_tag: \"100\"
  ) {
    id
    transaction_tag
    account_tag
    source
    source_ip
    destination
    destination_rate {
      pricelist_tag
      carrier_tag
      prefix
      connect_fee
      rate
      rate_increment
      interval_start
    }
    carrier_ip
    authorized
    timestamp_auth
    timestamp_begin
    timestamp_end
    inbound
    failed
    duration
    fee
  }
}"
}
EOF

We will get this response:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "data": {
    "Transaction": null
  },
  "errors": null
}

The transaction has been deleted via the Agent.