availability

Use of the production Forward API is subject to eligibility.

Contact your Account Manager for more information or submit an inquiry to our Business Development team.

The functions provided by the Forward API can be combined to construct sophisticated requests.

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 →