Transformations

CarrierX Core API allows the partners to additionally manipulate the data of the incoming and outgoing calls using transformations.

What Are Transformations and Why Use Them

The users might find transformations quite complicated, but the concept behind the transformations is very simple: you can check the inbound or outbound call data and modify it so that it better matched your purposes.

Why would one even bother with this?

It might happen, that the application you use requires the call data (e.g., the phone number in a certain header field) to have a specific format. Rather than process it on the application side (especially, when you are not the developer of that application, or cannot modify it due to some other reasons), you can apply the transformations within CarrierX and send the data to your application in the format it requires.

Or vice versa, sometimes the application might send the data to CarrierX in a format it cannot accept properly, and this data format cannot be changed on the application side. You can use the transformations to adapt the data into the CarrierX compatible format for the correct work.

The logic of a simple rewrite or set transformation looks like the following:

Rewrite Transformations

More complex transformations include lookup transformations and conditional transformations. The former will lookup for the routing number and transform the call fields depending on the result. The latter will allow the users to check the incoming data against some condition and then apply the matching transformations (simple, lookup, or other conditional) depending on the check results.

You can also combine different types of transformations applying them one-by-one, e.g., first perform lookup, then use some simple transformation, then check for a condition and, it true, use more simple transformations, among which are the STIR/SHAKEN, reject transformations, and others.

Transformations Levels

Depending on the object where the transformations are set, they can be applied to different calls on different levels.

These transformations levels include:

This way, you can use the partner level to set transformations which will be applied to all the calls (inbound or outbound) for which you use your rented phone numbers or specified prefixes. These transformations will be active throughout CarrierX system for you as a partner.

To narrow the rules to a specific DID or prefix and other objects associated with it, and at the same time exclude other phone numbers or prefixes, use transformations on DID/prefix level.

Trunk groups, trunks, and endpoints levels will help apply the transformations to the call data passing through them, and will not affect other trunk groups, trunks or endpoints.

Transformations Format

Any transformation is an object with three fields:

action and direction are the required fields when creating a transformation.

The presence and number of operands depend on the action. While the operands field itself must always be present, the number of operands differ from one transformation to another.

A typical transformation will have the following structure:

{
    "action": "set_header_parameter",
    "direction": "any",
    "operands": ["P-Charging-Vector","orig-ioi","privateSIP"]
}

We will take a closer look at different transformations and their attributes in the section below.

Transformations and Their Examples Explained

In this section we will explain the main types of CarrierX transformations and the operands used with them. We will also see the examples for main transformation types to understand what they do more easily.

Rewrite Transformations

Quite often it is necessary to rewrite a single or multiple call headers or header parameters. This can be done with the help of rewrite transformations:

Rewrite Transformations

The rewrite transformation will analyze the call data, find the source or destination phone number, or the header set by the action and, depending on the action, will replace either the phone number/header or some of the header parameters.

rewrite_from/rewrite_to

The rewrite_from transformation will replace the phone number which is the originator of the call (the source phone number). Its syntax looks like the following:

{
    "action": "rewrite_from",
    "direction": "any",
    "operands": [
        "pattern",
        "replace"
    ]
}

The rewrite_to transformation does the same to the phone number which is the destination of the call. Its syntax looks like the following:

{
    "action": "rewrite_to",
    "direction": "any",
    "operands": [
        "pattern",
        "replace"
    ]
}

rewrite_from_header_param/rewrite_to_header_param

The rewrite_from_header_param transformation will replace the parameters of the From header with the data specified. Its syntax looks like the following:

{
    "action": "rewrite_from_header_param",
    "direction": "any",
    "operands": [
        "parameter",
        "pattern",
        "replace"
    ]
}

The rewrite_to_header_param transformation does the same to the To header. Its syntax looks like the following:

{
    "action": "rewrite_to_header_param",
    "direction": "any",
    "operands": [
        "parameter",
        "pattern",
        "replace"
    ]
}

rewrite_header

The rewrite_header transformation will replace the header (or a part of it) you specify as an operand with the new values, or create it, in the case the call data lacks it. Its syntax looks like the following:

{
    "action": "rewrite_header",
    "direction": "any",
    "operands": [
        "header",
        "pattern",
        "replace",
        "default"
    ]
}

rewrite_header_parameter

The rewrite_header transformation will replace the parameter of the header you specify as an operand with the new value, or create it, in the case the call data lacks it. Its syntax looks like the following:

{
    "action": "rewrite_header_parameter",
    "direction": "any",
    "operands": [
        "header",
        "parameter",
        "pattern",
        "replace",
        "default"
    ]
}

Set Transformations

In the case the required parameters are missing from the call data, they can be added to it with the help of set transformations.

Set Transformations

set_header

The set_header transformation will add a new header you specify as an operand to the call data. Its syntax looks like the following:

{
    "action": "set_header",
    "direction": "any",
    "operands": [
        "header",
        "value"
    ]
}

set_header_parameter

The set_header_parameter transformation will add a new parameter to the header you specify as an operand. Its syntax looks like the following:

{
    "action": "set_header_parameter",
    "direction": "any",
    "operands": [
        "header",
        "parameter",
        "value"
    ]
}

Lookup Transformations

It is also possible to perform more complex transformations, e.g., lookup the routing number and transform the call fields depending on the result.

Lookup Transformations

lookup_rn

The lookup_rn information will lookup the routing number and return it so that it could be used instead of the source or destination number. Its syntax looks like the following:

{
    "action": "lookup_rn",
    "direction": "inbound",
    "operands": [
        "force",
        "always",
        "phonenumber",
        "destination",
        "on_failure",
        "input_format",
        "output_format_domestic",
        "output_format_international",
        "output_format_guess_not_found"
    ]
}

STIR/SHAKEN Transformations

The STIR/SHAKEN transformations are used to check the calling party, validate it, and add the appropriate mark to the call data depending on the attestation result. Refer to the STIR/SHAKEN section for more information about this.

stir_validate

The stir_validate transformation will validate the call and return data that can be used with other transformations.

STIR Validate Transformation

Its syntax looks like the following:

{
    "action": "stir_validate",
    "direction": "any",
    "operands": []
}

Conditional Transformations

The conditional transformations are normally used when there is a more complex logic behind them. They allow the users to check the incoming data against some condition and then apply the matching transformations (rewrite, lookup, other conditional, etc) depending on the check results.

Conditional Transformations

Multiple conditional transformations can be applied to one and the same call, each of them will trigger some other transformation depending on the rule matched.

if_match

The if_match transformation will add conditions based on which other transformations are applied. Its syntax looks like the following:

{
    "action": "if_match",
    "direction": "inbound",
    "operands": [
        "value",
        "match",
        "action",
        "arg1",
        "argX"
    ]
}

Other Transformations

reject

The reject transformation will drop the calls with one of the supported reasons.

Reject Transformation

Its syntax looks like the following:

{
    "action": "reject",
    "direction": "inbound",
    "operands": [
        "reason"
    ]
}

Chaining Transformations

Sometimes, it might be necessary to use multiple transformations rather than a single one. In this case, the actions can be chained, and the next transformations will either be using the results of the previous ones, or cover cases which the previous transformations missed.

Let’s see what the following succession of transformations does:

"transformations": [
    {
        "action": "stir_validate",
        "direction": "inbound",
        "operands": []
    },
    {
        "action": "set_header",
        "direction": "inbound",
        "operands": ["X-StirResult", "{{stir_verstat}}-{{stir_attest}}"]
    },
    {
        "action": "if_match",
        "direction": "inbound",
        "operands": ["{{stir_verstat}}:{{stir_attest}}", "TN-Validation-Passed:[AB]", "rewrite_from_header_param", "cnam", "(.{1,14})", "\\1*"]
    },
    {
        "action": "if_match",
        "direction": "inbound",
        "operands": ["{{stir_verstat}}", "No-TN-Validation", "rewrite_from_header_param", "cnam", ".*", "POSSIBLE FRAUD"]
    },
    {
        "action": "if_match",
        "direction": "inbound",
        "operands": ["{{stir_verstat}}", "TN-Validation-Failed", "reject", "forbidden"]
    }
]

The above transformations logic looks like the following:

Chaining Transformations

Further Reading

Read the following articles to get a better understanding of how things work in CarrierX: