Forward API
Examples
The functions provided by the Forward API can be combined to construct sophisticated requests.
- Functions
- HTTP basic auth
- Hashed data
- Transformations and overrides
- Conditional transformations
- XML sibling elements sharing a name
- XML attributes
- CVV with vaulted card data
- Forwarding multiple payment methods
- Forwarding multiple payment methods with aliases
Functions
The Forward API provides a number of functions that can be used to construct requests.
Here is part of a config that uses the join
function to concatenate the card number and CVV with a hyphen:
- JSON
{
"name": "join_example",
"transformations": [
{
"path": "/body/card_data",
"value": ["join", "-", ["array", "$number", "$cvv"]]
}
]
}
This might look like join("-", [number, cvv])
in another programming language.
Returns:
- JSON
{"card_data":"4012888888881881-123"}
The function reference lists all of the functions provided.
Nested functions
These functions can be composed just like functions in most programming languages. For example, you could use the join
and base64
functions to encode the above value in base 64.
- JSON
{
"name": "join_example",
"transformations": [
{
"path": "/body/card_data",
"value": ["base64", ["join", "-", ["array", "$number", "$cvv"]]]
}
]
}
That might look like base64(join("-", [number, cvv]))
in another programming language.
Returns:
- JSON
{"card_data": "NDAxMjg4ODg4ODg4MTg4MS0xMjM="}
The results of other functions can be nested, too.
HTTP basic auth
You can use nested functions to accomplish HTTP basic auth.
- JSON
{
"name": "basic_auth_example",
"transformations": [
{ "path": "/body/card/number", "value": "$number" },
{
"path": "/header/Authorization",
"value": [
"join",
" ",
[
"array",
"Basic",
["base64", ["join", ":", ["array", "$user", "$password"]]]
]
]
}
]
}
This request assumes that the global variables $user
and $password
will be provided in each forwarding request under either sensitive_data
or data
.
- bash
curl -i https://forwarding.sandbox.braintreegateway.com/ -H "Content-Type: application/json" -X POST -u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" -d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_nonce": "fake-valid-nonce",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"sensitive_data": {"user": "unicorn", "password": "rainbow"},
"config": {
"name": "basic_auth_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "json"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/header/Authorization", "value": [
"join", " ", [
"array", "Basic", ["base64", ["join", ":", ["array", "$user", "$password"]]]
]
]}
]
}
}'
Returns:
X-Query-String:
Request-UUID: a-unique-identifier-for-the-request
User-Agent: Braintree Forward API/1.0
Authorization: Basic dW5pY29ybjpyYWluYm93
- JSON
{"card":{"number":"4012888888881881"}}
Hashed data
This config demonstrates the following transformations:
- Hash functions
- Template reference
- Variable override
- bash
curl -i https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_nonce": "fake-valid-nonce",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"data": {"cardholder_name": "Pat Smith"},
"config": {
"name": "hashed_data_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "xml"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/body/card/cardholder_name", "value": "$cardholder_name"},
{"path": "/urlparam/card_md5", "value": ["base64", ["md5", "$/body/card"]]}
]
}
}'
Returns:
X-Query-String: card_md5=NN59PISOxm8jEIV1xMbvmw%3D%3D
Request-UUID: a-unique-identifier-for-the-request
User-Agent: Braintree Forward API/1.0
- XML
<card><number>4012888888881881</number><cardholder_name>Pat Smith</cardholder_name></card>
We provide $cardholder_name
as a variable override. The $cardholder_name
is normally provided by the Braintree Vault, we override it here with "Pat Smith"
.
We apply md5
and base64
to the $/body/card
portion of the request, this creates a hash of the serialized content under the path /body/card
. In this request we're specifiying XML as the serialization format for the /body
.
Transformations and overrides
This request demonstrates the interaction of transformations and request overrides.
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_nonce": "fake-valid-nonce",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"override": {
"body": "<card>
<number></number>
<cardholder_name>Overridden</cardholder_name>
<supplemental_data>passed through</supplemental_data>
</card>"
},
"config": {
"name": "transformations_and_overrides",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "xml"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/body/card/cardholder_name", "value": "$cardholder_name"}
]
}
}'
Returns:
- XML
<card><number>4012888888881881</number><cardholder_name>Overridden</cardholder_name><supplemental_data>passed through</supplemental_data></card>
The override functions as a baseline for the request – the entirety of the override will be sent to the destination, modified only by transformations that do not conflict with non-empty values in the override.
A few notes on the values passed in the example request above:
<number></number>
effectively serves as a placeholder – if omitted, the transformation will place<number>4012888888881881</number>
as the final element<cardholder_name>Overridden</cardholder_name>
takes precedence over the transformation because the override value is non-empty- Any additional components of the request that are not affected by transformations – in this case,
<supplemental_data>passed through</supplemental_data>
– are passed through
Conditional transformations
This request demonstrates the if_defined
transformation modifier.
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_nonce": "fake-valid-nonce",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"config": {
"name": "conditional_transformations",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "json"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/body/card/cardholder_name", "value": "$cardholder_name", "if_defined": "$cardholder_name"},
{"path": "/body/card/cvv", "value": "$cvv", "if_defined": "$cvv"}
]
}
}'
Returns:
- JSON
{"card":{"number":"4012888888881881", "cvv": "123"}}
The if_defined
modifier requires the value to be present in order for the transformation to be applied.
Note that the test payment method nonce used in this example, fake-valid-nonce
, doesn't provide a $cardholder_name
but does provide a $cvv
.
XML sibling elements sharing a name
This configuration demonstrates numerically indexed transformation paths.
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_nonce": "fake-valid-nonce",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"data": {"item_1_id": "1234", "item_2_id": "5678"},
"config": {
"name": "xml_sibling_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "xml"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/body/cart/[0]/item/id", "value": "$item_1_id"},
{"path": "/body/cart/[1]/item/id", "value": "$item_2_id"},
]
}
}'
Returns:
- XML
<card><number>4012888888881881</number></card><cart><item><id>1234</id></item><item><id>5678</id></item></cart>
XML attributes
This configuration demonstrates setting XML attributes.
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_nonce": "fake-valid-nonce",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"config": {
"name": "xml_attribute_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "xml"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/body/card/@type", "value": "$card_type"}
]
}
}'
Returns:
- XML
<card type="Visa"><number>4012888888881881</number></card>
CVV with vaulted card data
Braintree does not store CVVs of vaulted payment methods for compliance reasons. If the destination API requires CVV and you are using vaulted card data, you must specify a payment_method_nonce
containing the CVV along with your long-lived payment_method_token
.
You can collect a CVV-only nonce with the client SDKs by tokenizing only the CVV property. Once you have that nonce, you can make a request that includes both the payment_method_token
and CVV-only payment_method_nonce
:
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_token": "'"$TOKEN"'",
"payment_method_nonce": "'"$CVV_ONLY_NONCE"'",
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"config": {
"name": "cvv_with_vaulted_data_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "json"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/card/number", "value": "$number"},
{"path": "/body/card/cvv", "value": "$cvv_2"}
]
}
}'
Returns:
- JSON
{"card":{"number":"4111111111111111","cvv":"123"}}
The $number
variable will come from the payment_method_token
and $cvv_2
will come from the payment_method_nonce
per the Forward API's variable suffixing.
Forwarding multiple payment methods
This configuration demonstrates forwarding multiple payment methods using variable suffixes and using the index value -1
to append.
In the example below, the destination API accepts any number of cards under both set_A
and set_B
. Variables passed in data
are used to control which transformations are performed.
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_tokens": ["'"$TOKEN_1"'", "'"$TOKEN_2"'"],
data: {
"first_card_in_set_A": true,
"second_card_in_set_A": true,
"first_card_in_set_B": false,
"second_card_in_set_B": true
},
"debug_transformations": true,
"url": "https://httpbin.org/post",
"method": "POST",
"config": {
"name": "forwarding_multiple_payment_methods_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "xml"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/data/set_A/card/[0]", "value": "$number_1", "if_defined": "$first_card_in_set_A"},
{"path": "/body/data/set_A/card/[-1]", "value": "$number_2", "if_defined": "$second_card_in_set_A"},
{"path": "/body/data/set_B/card/[0]", "value": "$number_1", "if_defined": "$first_card_in_set_B"},
{"path": "/body/data/set_B/card/[-1]", "value": "$number_2", "if_defined": "$second_card_in_set_B"}
]
}
}'
In the above example, both cards are members of set_A
but only the second is a member of set_B
, producing the following XML:
- XML
<data>
<set_A>
<card>378282246310005</card>
<card>4111111111111111</card>
</set_A>
<set_B>
<card>4111111111111111</card>
</set_B>
</data>
The second transformation for both set_A
and set_B
uses the index value -1
to append because the second card's membership in either set is completely independent of the first card's set membership. It would be possible to express the full set of possible states with absolute indices, but doing so would require additional conditional transformations.
Forwarding multiple payment methods with aliases
This configuration represents an alternative to the additional control variables used in Forwarding multiple payment methods: variable_aliases
. This approach is somewhat more flexible, but may be less concise than a control variable approach dependent on the constraints of the destination API.
In the example below, the destination API accepts any number of cards under both set_A
and set_B
.
- bash
curl https://forwarding.sandbox.braintreegateway.com/ \
-H "Content-Type: application/json" \
-X POST \
-u "${BRAINTREE_PUBLIC_KEY}:${BRAINTREE_PRIVATE_KEY}" \
-d '{
"merchant_id": "'"$BRAINTREE_MERCHANT_ID"'",
"payment_method_tokens": ["'"$TOKEN_1"'", "'"$TOKEN_2"'", "'"$TOKEN_3"'"],
"debug_transformations": true,
"variable_aliases": {"first_A": "number_1", "first_B", "number_2", "second_A": "number_3", "second_B": "number_3"},
"url": "https://httpbin.org/post",
"method": "POST",
"config": {
"name": "forwarding_multiple_payment_methods_example",
"methods": ["POST"],
"url": "^https://httpbin\.org/post$",
"request_format": {"/body": "xml"},
"types": ["CreditCard"],
"transformations": [
{"path": "/body/data/set_A/card/[0]", "value": "$first_A", "if_defined": "$first_A"},
{"path": "/body/data/set_A/card/[-1]", "value": "$second_A", "if_defined": "$second_A"},
{"path": "/body/data/set_B/card/[0]", "value": "$first_B", "if_defined": "$first_B"},
{"path": "/body/data/set_B/card/[-1]", "value": "$number_2", "if_defined": "$second_B"}
]
}
}'
In the above example, TOKEN_1
is a member of set_A
, TOKEN_2
is a member of set_B
, and TOKEN_3
is a member of both set_A
and set_B
, producing the following XML:
- XML
<data>
<set_A>
<card>4111111111111111</card>
<card>5555555555554444</card>
</set_A>
<set_B>
<card>378282246310005</card>
<card>5555555555554444</card>
</set_B>
</data>
See also
Next Page: Cryptography →