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.
In this tutorial you'll create two integrations to the Authorize.Net Payment Gateway using their REST API:
The Appian Tutorial application is used to contain the design objects created while working through this tutorial.
To create the Appian Tutorial application
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.
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.
Once registered, log in to the Sandbox Merchant Interface and generate API credentials for your account.
While still in the Sandbox Merchant Interface, enable the Transaction Details API for your account.
Create constants to hold the value of your Authorize.Net API Login ID and Transaction Key:
These constants will be used in later steps to identify you when calling the Authorize.Net API.
You'll create a connected system to represent Authorize.Net and use it in each of the individual integrations.
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 a new integration called AuthorizeCreditCardPayment and configure it by following these steps:
https://apitest.authorize.net/xml/v1/request.api
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"
}
}
}
}
}
)
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"
.
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 inputs for the credit card information and the transaction amount to allow the integration to be used for any payment.
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)
}
}
}
}
}
)
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
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
)
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
)
! )
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.
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
)
}
)
)
)
The interface will display and you can enter credit card information, but nothing will be submitted when you press the Place Your Order button.
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:
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.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:
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),
! }
! )
)
...
You'll use the Transaction Reporting API to get the list of unsettled transactions.
Create a new integration called GetUnsettledTransactionList and configure it by following these steps:
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
}
}
}
)
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.
You now have a working integration! However, this integration isn't that useful because it can only get the default page of results.
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.
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
! }
}
}
)
a!pagingInfo()
and a!sortInfo()
. For example, a!pagingInfo(1, 2, a!sortInfo("submitTimeUTC", false))
. Only id
and submitTimeUTC
are supported for sorting.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.
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")
)
)
)
}
)
)
)
The grid will display and you can sort and page through the available transactions.
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.
On This Page