How to Vault A Payment Method

This guide provides instructions for vaulting a single-use payment method, storing it for future use. Once vaulted, a payment method can be reused as many times as possible without your customer needing to re-enter or authenticate their payment information.

Obtain a Single-Use Payment Method (Nonce)

Follow this guide to obtain a payment method nonce from your client.

In this context, you can think of the payment method nonce string as a unique ID for a credit card, PayPal account, or any other payment method type that you've already sent to Braintree from your client-side integration. In the GraphQL API, this is represented by the PaymentMethod type, with its usage field containing a value of SINGLE_USE. The ID for this tokenized, single-use payment method information is the only thing you need to vault it.

For the remainder of this guide, we will refer to the payment method represented by the nonce as a "single-use payment method", and the nonce itself as its ID.

Vault the Payment Method

Once you have a single-use payment method ID from your client, you can vault the underlying payment method. To do so, use the vaultPaymentMethod mutation.

This mutation will automatically run a verification against payment methods that support them before storing them in the vault. The verification result is represented both at the top level as vaultPaymentMethod.verification, and on the payment method itself in vaultPaymentMethod.paymentMethod.verifications. These fields have slightly different purposes and semantics, which will be explained later in the guide.

Note that the single-use payment method will be consumed if it is successfully vaulted. You will not be able to use it again. Instead, the mutation will return a new, multi-use payment method representing the same payment information. Use the ID returned by the vaultPaymentMethod mutation to charge it.

Mutation

mutation ExampleVaultWithTypeFragment($input: VaultPaymentMethodInput!) {
  vaultPaymentMethod(input: $input) {
    paymentMethod {
      id
      usage
      details {
        __typename
        ... on CreditCardDetails {
          cardholderName
        }
        ... on PaypalAccountDetails {
          payer {
            email
          }
        }
        ... on VenmoAccountDetails {
          username
        }
        ... on UsBankAccountDetails {
          accountHolderName
        }
      }
    }
    verification {
      status
    }
  }
}

Variables

{
  "input": {
    "paymentMethodId": "<single-use-payment-method-id>"
  }
}

Full Request

curl \
 -H 'Content-Type: application/json' \
 -H 'Authorization: Basic PUBLICKEY:PRIVATEKEY_BASE64ENCODED' \
 -H 'Braintree-Version: 2019-01-01' \
 -X POST https://payments.sandbox.braintree-api.com/graphql \
 -d '{
  "query": "mutation ExampleVaultSimple($input: VaultPaymentMethodInput!) {
    vaultPaymentMethod(input: $input) {
      paymentMethod {
        id
        usage
        details {
          __typename
        }
      }
      verification {
        status
      }
    }
  }",
  "variables": {
    "input": {
      "paymentMethodId": "<single-use-payment-method-id>"
    }
  }
}'

Response

For a request that included the type details, the output could look like:

{
  "data": {
    "vaultPaymentMethod": {
      "paymentMethod": {
        "id": "<multi-use-payment-method-id>",
        "usage": "MULTI_USE",
        "details": {
          "__typename": "CreditCardDetails",
          "cardholderName": "Jane Q. Cardholder"
        }
      },
      "verification": {
        "status": "VERIFIED"
      }
    }
  }
}

or, if the payment method does not require a verification:

{
  "data": {
    "vaultPaymentMethod": {
      "paymentMethod": {
        "id": "<multi-use-payment-method-id>",
        "usage": "MULTI_USE",
        "details": {
          "__typename": "PaypalAccountDetails",
          "payer": {
            "email": "emailfor@paypal.account"
          }
        }
      },
      "verification": nil
    }
  }
}

See the API Explorer for more possible payment method types and fields.

Customers

If you want to group payment methods together in the Braintree API by indivdual customer, you can pass a customerId in the vault request. Once vaulted, a payment method cannot be transferred to a different customer, but the customer can be updated with new personal information. All payment methods belonging to a customer will be available on the paymentMethods connection field on the customer.

The default behavior when vaulting a payment method, without a customerId, is to create an empty customer associated with the newly-vaulted payment method. This can be ignored if unused, or updated later to hold relevent information.

Error Handling

The only required parameter on input is paymentMethodId. Failing to supply this will result in an error.

If the vaulting mutation fails otherwise, it is most likely because:

  • the payment method verification step failed on a payment method type that requires it
  • the single-use payment method has already been consumed (for example, you've already charged it to create a transaction)
  • the single-use payment method has expired
  • the single-use payment method is "not valid", and represents invalid payment information
  • the underlying payment information is not vaultable (for example, when authorizing their PayPal account, the customer only grants permission to charge it once)

Depending on which error you receive, you will need to prompt your customer to re-enter or enter another payment method.

A note about verifications

In order to mitigate fraudulent payment method usage, the vaultPaymentMethod mutation will automatically run verifications against payment methods that support them (e.g. credit cards). You can control which merchant account to run the verification against using the verificationMerchantAccountId input field.

If the verification fails or is declined, the payment method will not be stored in the vault. In this case, you will need to check the vaultPaymentMethod.verification response field to understand why the verification failed.

Here is an example response from a failed verification:

{
  "data": {
    "vaultPaymentMethod": {
      "paymentMethod": null,
      "verification": {
        "status": "PROCESSOR_DECLINED"
      }
    }
  },
  "errors": [
    {
      "message": "Payment method failed verification.",
      "path": ["vaultPaymentMethod", "paymentMethod"],
      "extensions": {
        "errorClass": "VALIDATION",
        "inputPath": ["input", "paymentMethodId"]
      }
    }
  ]
}

This response represents a GraphQL "partial failure", in which a failure to fetch one part of the response (verifyCreditCard.paymentMethod) doesn't affect the ability to fetch another (verifyCreditCard.verification). In this case, the errors entry is used to describe what happened to cause the verifyCreditCard.paymentMethod field to be null, while the data entry still contains useful information about the verification result in vaultPaymentMethod.verification.

There are certain cases where a single vaultPaymentMethod request could result in multiple verifications (for example $1 verification retries). To fetch these results, refer to the vaultPaymentMethod.paymentMethod.verifications field, which returns all historical verifications run on the payment method. This field is represented as a paginated VerificationConnection, rather than a simple list. Read more about this type in our Connections and Pagination guide.