Integration Tutorial

The walk-throughs on this page will help you create your first integrations.

Use the information provided to understand how the configurations work. Then, try it with your own integrations.

The content below assumes a basic familiarity with interfaces and focuses more on the specifics of configuring an integration to an external service. Consider going through the Interface Tutorial before proceeding.

The content below also assumes that you have a basic familiarity with using APIs. Note that you will need to register for a free, third-party API to complete this tutorial.

Tutorial Scenario

In this tutorial you'll create two integrations to the Authorize.Net Payment Gateway using their REST API:

  1. You'll create an integration that charges a credit card and use it in an interface. Since the integration is called from an interface the credit card information is never stored in Appian.
  2. You'll create an integration to retrieve unsettled credit card transactions and use it in a grid. The integration supports paging and sorting using the API.

Create the Appian Tutorial Application

The Appian Tutorial application is used to contain the design objects created while working through this tutorial.

The tutorial application only needs to be created once. If you have already created the tutorial application, skip the steps below.

To create the Appian Tutorial application

  1. Log in to Appian Designer (for example, myappiansite.com/suite/design).
  2. Click New Application.
  3. In the Name field, type Appian Tutorial.
  4. Optionally, in the Description field, add a short description.
  5. Click Create.

The application contents view displays. Right now the application is empty. Each design object that you create during the course of this tutorial will appear in this list and be associated with the tutorial application.

Set Up API Access

Register for a Sandbox Account

If you already have access to the Authorize.Net API, you can skip to the next section. Otherwise, register an account. It is free of charge and takes less than a minute. Once you have registered, record your account account login information for reference later.

You will need to wait for a welcome email from Authorize.Net to proceed with the tutorial. This may take 20 minutes or longer. Take note of the Secret Answer included in the email.

Generate API Credentials

Once registered, log in to the Sandbox Merchant Interface and generate API credentials for your account.

  1. Go to Account > Settings > Security Settings > API Credentials & Keys.
  2. Record the value of API Login ID.
  3. Under Create New Key(s), provide the Secret Answer included in the welcome email, select New Transaction Key, and click Submit.
  4. Record the value of Current Transaction Key.

Enable the Transaction Details API

While still in the Sandbox Merchant Interface, enable the Transaction Details API for your account.

  1. Go to Account > Settings > Security Settings > Transaction Details API.
  2. Under Secret Question and Answer, provide the Secret Answer included in the welcome email, and click Enable Transaction Details API.

Create API Constants

Create constants to hold the value of your Authorize.Net API Login ID and Transaction Key:

  1. Create a new constant named AUTHORIZE_DOT_NET_API_LOGIN_ID of type Text and set the value to your Authorize.Net API Login ID.
  2. Create a new constant named AUTHORIZE_DOT_NET_TRANSACTION_KEY of type Text and set the value to your Authorize.Net Transaction Key.

These constants will be used in later steps to identify you when calling the Authorize.Net API.

Create a Connected System

You'll create a connected system to represent Authorize.Net and use it in each of the individual integrations.

  1. Create a new connected system called Authorize.Net and give it a useful Description.
  2. Download this image and upload it as the System Logo to represent Authorize.Net.
  3. Click Use in New Integration to save the new connected system and immediately use it in the first integration.

Charge a Credit Card

You'll use the Payment Transactions API to charge a credit card. The API documentation includes a wide variety of transaction features, but for this tutorial you'll just submit a simple request.

Create the Credit Card Payment Integration

Create a new integration called AuthorizeCreditCardPayment and configure it by following these steps:

  1. If the Authorize.Net connected system created earlier isn't already pre-populated, select the Use an existing connected system option and then use the Connected System picker to select it from the list.
  2. In the URL field, enter the value of the Authorize.Net Sandbox API endpoint: https://apitest.authorize.net/xml/v1/request.api
  3. For Method, select POST.
    • Selecting POST automatically switches Usage to Modifies data. Since this integration will submit credit card payments, this is the correct selection.
  4. For Content-Type, select JSON (application/json).
    • The Authorize.Net API also supports XML (text/xml), but JSON is easier to work with in this scenario.
  5. In the Body field, copy and paste the following expression to create the request body:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    a!toJson(
      {
        "createTransactionRequest": {
          "merchantAuthentication": {
            "name": cons!AUTHORIZE_DOT_NET_API_LOGIN_ID,
            "transactionKey": cons!AUTHORIZE_DOT_NET_TRANSACTION_KEY
          },
          "transactionRequest": {
            "transactionType": "authCaptureTransaction",
            "amount": "100.00",
            "payment": {
              "creditCard": {
                "cardNumber": "5424000000000015",
                "expirationDate": "1220",
                "cardCode": "999"
              }
            }
          }
        }
      }
    )
    
  6. In the Automatic Output Parsing section, choose Convert the JSON Response to an Appian Value
  7. Click Test Request. You should receive a result with a status code of 200 and a body containing a transactionResponse with a message indicating that "This transaction has been approved".

  8. If you receive an unexpected result or an error, check the integration configuration, confirm your API Login Key and Transaction Key, and use the HTTP Request and HTTP Response tabs to diagnose the problem.
    • Note that if you test multiple times with the same credit card number and amount, you may get results indicating that a duplicate transaction has been submitted. Change the amount to test additional transactions.

You now have a working integration! However, this integration isn't that useful because it can only charge a specific amount to a specific card.

Add Payment Inputs

Add inputs for the credit card information and the transaction amount to allow the integration to be used for any payment.

  1. Expand the inputs pane on the right side of the integration designer. Since this integration is configured to modify data you'll notice that the onSuccess and onError inputs appear automatically.
  2. Create the following additional inputs:
    • cardNumber (Text)
    • expirationDate (Number (Integer))
    • ccv (Number (Integer))
    • amount (Number (Decimal))
  3. Update the Body expression to use the new inputs:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    a!toJson(
      {
        "createTransactionRequest": {
          "merchantAuthentication": {
            "name": cons!AUTHORIZE_DOT_NET_API_LOGIN_ID,
            "transactionKey": cons!AUTHORIZE_DOT_NET_TRANSACTION_KEY
          },
          "transactionRequest": {
            "transactionType": "authCaptureTransaction",
    !        "amount": tostring(ri!amount),
            "payment": {
              "creditCard": {
    !            "cardNumber": ri!cardNumber,
    !            "expirationDate": tostring(ri!expirationDate),
    !            "cardCode": tostring(ri!ccv)
              }
            }
          }
        }
      }
    )
    
  4. Test the new configuration by providing test values for the four inputs. You can use the same values as in the original configuration (varying the amount), or you can experiment with other test values as described in the Authorize.Net Testing Guide.
  5. Be sure to save your integration.

Add Error Handling

By default, an integration will be considered successful if the system returns a status code of 200. However, because we want to treat transaction issues as requests

  1. In the Error Handling section select Override and define all error conditions
  2. Update the Success Criteria expression with:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     if(
       fv!success,
    !  if(
    !    or(fv!result.body.transactionResponse.messages.resultCode = "Error", not(isnull(fv!result.body.transactionResponse.errors))),
    !    false,
    !    true
    !  ),
       false
     )
    
  3. Update the Error Message expression with:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    ! if(
    !  fv!result.statusCode = 200,
    !  a!integrationError(
    !    title: "Transaction Could not be Completed",
    !    message: fv!result.body.transactionResponse.errors[1].errorText
    !  ),
       a!integrationError(
         title: fv!error.title,
         message: fv!error.message,
         detail: fv!error.detail
       )
    ! )    
    

Create the Payment Form

You will use the AuthorizeCreditCardPayment integration in an interface to allow users to pay for goods or services. The form data used in the tutorial is hardcoded. You will need to update the form to work with a real application.

  1. Create a new interface called ProcessCreditCardPaymentUsingExternalSystem.
  2. Open the interface, switch to EXPRESSION MODE, then copy and paste the following expression into the INTERFACE DEFINITION to create the interface:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    
    =load(
      local!cardNumber,
      local!expirationDate,
      local!ccv,
      local!amount: 412.97,
      local!paymentComplete: false,
      local!paymentErrorMessage,
      local!paymentConfirmationMessage,
      a!formLayout(
        label: "Submit Credit Card Payment",
        contents: a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: {
                a!sectionLayout(
                  label: "Order Summary",
                  contents: {
                    a!richTextDisplayField(
                      label: "Total",
                      value: a!richTextItem(text: dollar(local!amount), style: "LARGE")
                    ),
                    a!gridField(
                      label: "Items",
                      totalCount: 5,
                      columns: {
                        a!gridTextColumn(label: "Description", data: {"Mobile device for demos", "Video software upgrade", "Device accessories"}),
                        a!gridTextColumn(label: "Category", data: {"Hardware", "Software", "Miscellaneous"}),
                        a!gridTextColumn(label: "Qty", data: {2, 1, 2}, alignment: "RIGHT"),
                        a!gridTextColumn(label: "Unit Price", data: {dollar({150, 50.99, 30.99}), "Total"}, alignment: "RIGHT"),
                        a!gridTextColumn(label: "Amount", data: dollar({300, 50.99, 61.98, local!amount}), alignment: "RIGHT")
                      },
                      value: a!pagingInfo(startIndex: 1, batchSize: 5),
                      rowHeader: 1
                    )
                  }
                )
              }
            ),
            a!columnLayout(
              contents: {
                a!sectionLayout(
                  label: "Payment Information",
                  validations: if(isnull(local!paymentErrorMessage),
                    {},
                    local!paymentErrorMessage
                  ),
                  contents: {
                    a!textField(
                      label: "Card Number",
                      labelPosition: "ABOVE",
                      placeholder: "0000111122223333",
                      refreshAfter: "KEYPRESS",
                      value: local!cardNumber,
                      saveInto: {
                        local!cardNumber,
                        a!save(local!paymentErrorMessage, null)
                      },
                      required: true,
                      disabled: local!paymentComplete
                    ),
                    a!integerField(
                      label: "Expiration Date",
                      labelPosition: "ABOVE",
                      placeholder: "MMYY",
                      refreshAfter: "KEYPRESS",
                      value: local!expirationDate,
                      saveInto: {
                        local!expirationDate,
                        a!save(local!paymentErrorMessage, null)
                      },
                      required: true,
                      disabled: local!paymentComplete
                    ),
                    a!integerField(
                      label: "CCV",
                      labelPosition: "ABOVE",
                      placeholder: "999",
                      refreshAfter: "KEYPRESS",
                      value: local!ccv,
                      saveInto: {
                        local!ccv,
                        a!save(local!paymentErrorMessage, null)
                      },
                      required: true,
                      disabled: local!paymentComplete
                    ),
                    if(local!paymentComplete,
                      {
                        a!richTextDisplayField(
                          value: {
                            a!richTextImage(image: a!documentImage(document: a!iconIndicator(icon: "STATUS_OK"))),
                            a!richTextItem(text: "Payment Complete! ", style: "MEDIUM"),
                            a!richTextItem(text: "Transaction ID " & local!paymentConfirmationMessage, style: "UNDERLINE")
                          }
                        )
                      },
                      a!buttonLayout(
                        primaryButtons: {
                          a!buttonWidget(
                            label: "Place Your Order",
                            style: "PRIMARY",
                            validate: true,
                            disabled: not(isnull(local!paymentErrorMessage)),
                            saveInto: {}
                          )
                        }
                      )
                    ),
                    a!richTextDisplayField(
                      value: a!richTextItem(text: "Credit card transactions are handled by our secure payment processor. We do not store your credit card information.", style: "EMPHASIS")
                    ),
                    a!richTextDisplayField(
                      value: a!richTextItem(text: "When you click the 'Place Your Order' button, we'll send you an email message acknowledging receipt of your order. Your contract to purchase an item will not be complete until we send you an email notifying you that the item has been shipped.", style: "EMPHASIS")
                    ),
                  }
                )
              }
            )
          }
        ),
        buttons: a!buttonLayout(
          primaryButtons: {
            a!buttonWidget(
              label: "Continue",
              style: "PRIMARY",
              disabled: not(local!paymentComplete),
              submit: true
            )
          }
        )
      )
    )
    
  3. The interface will display and you can enter credit card information, but nothing will be submitted when you press the Place Your Order button.

Call the Integration from the Payment Form

You'll now update the form to call the AuthorizeCreditCardPayment integration so that credit card transactions are sent to Authorize.Net.

When processing the results of the integration the interface in this tutorial handles several different scenarios:

  • If an HTTP error (e.g.: 404 status code) or a network error (e.g.: request timeout) occurs, the onError input will be executed. When this happens the interface will show the error message in fv!error.message to the user.
  • If the call to the integration succeeds the onSuccess input will be executed. The interface parses the response body in fv!result.body and updates the form depending on the result:
    • If the body contains an error message (e.g.: duplicate transaction, invalid credit card number) the interface will show that error message to the user.

    • If the body contains a successful transaction ID the interface will show that ID as a confirmation to the user.

When creating your own integrations use the integration designer to test different scenarios to see how the external system responds. The designer shows the result and error that will be returned when the integration is called from an interface (or other object) so that you can decide how to handle each response.

Add the integration to the interface using the following steps:

  1. In the saveInto field of the Place Your Order button, call the integration by updating the interface expression as shown below:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    ...
        a!buttonWidget(
          label: "Place Your Order",
          style: "PRIMARY",
          validate: true,
          disabled: not(isnull(local!paymentErrorMessage)),
    !      saveInto: rule!AuthorizeCreditCardPayment(
    !        cardNumber: local!cardNumber,
    !        expirationDate: local!expirationDate,
    !        ccv: local!ccv,
    !        amount: local!amount,
    !        onSuccess:{
    !          /* Handle successful payment and show comfirmation */
    !          a!save(local!paymentErrorMessage, null),
    !          a!save(local!paymentComplete, true),
    !          a!save(local!paymentConfirmationMessage, fv!result.body.transactionResponse.transId),
    !        },
    !        onError: {
    !          /* Handle HTTP error */
    !          a!save(local!paymentErrorMessage, fv!error.message),
    !        }
    !      )
        )
    ...
    
  2. Test the completed form with a variety of inputs to see what happens. The Authorize.Net Testing Guide provides different credit card numbers and associated details to try different scenarios.
  3. Be sure to save your interface.

View Unsettled Transactions

You'll use the Transaction Reporting API to get the list of unsettled transactions.

Create the Unsettled Transactions Integration

Create a new integration called GetUnsettledTransactionList and configure it by following these steps:

  1. Select the Use an existing connected system option and then use the Connected System picker to select Authorize.Net from the list.
  2. In the URL field, enter the value of the Authorize.Net Sandbox API endpoint: https://apitest.authorize.net/xml/v1/request.api
  3. For Method, select POST.
  4. For Usage, select Queries data.
    • Selecting POST automatically switches Usage to Modifies data. However, since this integration retrieves a list of transactions and does NOT modify data, the default value must be changed.
  5. For Content-Type, select JSON (application/json).
    • The Authorize.Net API also supports XML (text/xml), but JSON is easier to work with in this scenario.
  6. In the Body field, copy and paste the following expression to create the request body:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    a!toJson(
      {
        "getUnsettledTransactionListRequest": {
          "merchantAuthentication": {
            "name": cons!AUTHORIZE_DOT_NET_API_LOGIN_ID,
            "transactionKey": cons!AUTHORIZE_DOT_NET_TRANSACTION_KEY
          }
        }
      }
    )
    
  7. Click Test Request. You should receive a result with a status code of 200 and a body containing a list of transactions.

    • Make sure you have recently submitted transactions using the credit card payment integration. If you haven't submitted any successful payment transactions the results will be empty. Authorize.Net settles transactions daily, so you may need to submit new transactions to make sure that the result is populated.

  8. If you receive an unexpected result or an error, check the integration configuration, confirm your API Login Key and Transaction Key, and use the HTTP Request and HTTP Response tabs to diagnose the problem.

You now have a working integration! However, this integration isn't that useful because it can only get the default page of results.

Add Paging/Sorting Inputs

Add inputs to allow the integration to control how the transaction list is retrieved. You'll use a PagingInfo data type and transform it into the paging and sorting inputs expected by the Authorize.Net API.

  1. Expand the inputs pane on the right side of the integration designer.
  2. Create an input named pagingInfo of type PagingInfo.
  3. Update the Body expression to use the new input:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    a!toJson(
      {
        "getUnsettledTransactionListRequest": {
          "merchantAuthentication": {
            "name": cons!AUTHORIZE_DOT_NET_API_LOGIN_ID,
            "transactionKey": cons!AUTHORIZE_DOT_NET_TRANSACTION_KEY
          }`,`
    !      "sorting": {
    !        "orderBy": ri!pagingInfo.sort[1].field,
    !        "orderDescending": not(ri!pagingInfo.sort[1].ascending)
    !      },
    !      "paging": {
    !        "limit": ri!pagingInfo.batchSize,
    !        "offset": tointeger((ri!pagingInfo.startIndex - 1) / ri!pagingInfo.batchSize) + 1
    !      }
        }
      }
    )
    
  4. Test the new configuration by providing test values using a!pagingInfo() and a!sortInfo(). For example, a!pagingInfo(1, 2, a!sortInfo("submitTimeUTC", false)). Only id and submitTimeUTC are supported for sorting.
  5. Be sure to save your integration.

Create the Transactions Grid

In this section you will use the GetUnsettledTransactionList integration in a paging grid with the ability to page and sort the list of transactions. The Transaction Reporting API does not provide the total number of transactions available for the result, so you'll be hardcoding the grid's totalCount parameter to 1000.

  1. Create a new interface called ViewUnsettledCreditCardTransactionsUsingExternalSystem.
  2. Open the interface, switch to EXPRESSION MODE, then copy and paste the following expression into the INTERFACE DEFINITION to create the interface:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    
    =load(
      /* Setup the initial paging and sorting values */
      local!pagingInfo: a!pagingInfo(1, 5, a!sortInfo("submitTimeUTC", false)),
      with(
        /* Call the external system to return a subset of the transaction list */
        local!transactionListPage: rule!GetUnsettledTransactionList(local!pagingInfo).result.body,
        /* Check whether the current page has results */
        local!hasResults: tointeger(local!transactionListPage.totalNumInResultSet) > 0,
        a!gridField(
          /* The total count from the external system is unknown, so default to 1000 and handle empty results */
          totalCount: 1000,
          value: local!pagingInfo,
          saveInto: local!pagingInfo,
          rowHeader: 1,
          columns: {
            a!gridTextColumn(
              label: "Transaction ID",
              field: "id",
              data: local!transactionListPage.transactions.transId
            ),
            a!gridTextColumn(
              label: "Type",
              data: local!transactionListPage.transactions.accountType
            ),
            a!gridTextColumn(
              label: "Account",
              data: local!transactionListPage.transactions.accountNumber
            ),
            a!gridTextColumn(
              label: "Amount",
              data: a!forEach(
                items: local!transactionListPage.transactions.settleAmount,
                expression: dollar(fv!item)
              )
            ),
            a!gridTextColumn(
              label: "Submitted Time (UTC)",
              field: "submitTimeUTC",
              data: a!forEach(
                /* Format the date/time string */
                items: if(local!hasResults, local!transactionListPage.transactions.submitTimeUTC, {}),
                expression: with(
                  local!time: mid(fv!item, 12, 8),
                  local!year: mid(fv!item, 1, 4),
                  local!month: mid(fv!item, 6, 2),
                  local!day: mid(fv!item, 9, 2),
                  text(todate(local!month & "/" & local!day & "/" & local!year) + totime(local!time), "MMM dd, yyyy h:mm aa")
                )
              )
            )
          }
        )
      )
    )
    
  3. The grid will display and you can sort and page through the available transactions.

  4. Be sure to save your interface.

Troubleshooting

If you encounter problems when configuring the integrations, refer to the Authorize.Net API documentation and use the integration designer to test different configurations and input values and to view the HTTP request and response.

FEEDBACK