Skip to main content

Payment Methods

A PaymentMethod represents transactable payment information such as credit card details or a customer's authorization to charge a PayPal or Venmo account. Payment methods belong to a customer, are securely stored in the Braintree Vault, and have an id attribute that you can store on your servers (with reduced PCI compliance burden) and later use to create create transactions.

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.

Vaulting 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.

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": "id_of_single_use_payment_method"
}
}

curl

curl -H 'Content-Type: application/json' -H 'Authorization: Basic BASE64_ENCODED(PUBLIC_KEY:PRIVATE_KEY)' -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": "id_of_single_use_payment_method"
}
}
}'

response

{
"data": {
"vaultPaymentMethod": {
"paymentMethod": {
"id": "id_of_multi_use_payment_method",
"usage": "MULTI_USE",
"details": {
"__typename": "CreditCardDetails",
"cardholderName": "Jane Q. Cardholder"
}
},
"verification": {
"status": "VERIFIED"
}
}
}
}

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

response

{
"data": {
"vaultPaymentMethod": {
"paymentMethod": {
"id": "id_of_multi_use_payment_method",
"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.

NOTE

Braintree strongly recommends verifying all cards before they are stored in your Vault by enabling card verification for your entire account in the Control Panel.

Customers

If you want to group payment methods together in the Braintree API by individual 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 relevant 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:

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

Payment Method Verification Failed

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 verification.merchantAccountId 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:

errors

{
"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.

Single-Use Payment Method is Consumed

The vaulting mutation could also fail if the paymentMethodId you provide has already been consumed. These IDs are single-use, so if you've already used it to create a transaction, for instance, you cannot vault it. Actions that consume a single-use payment method include charging, authorizing, capturing, and vaulting.

Single-Use Payment Method has Expired

Single-use payment methods expire after 3 hours. If it has been more than 3 hours since you collected payment information to create a single-use payment method, you can no longer consume it.

Single-Use Payment Method Represents Invalid Data

When the payment information a single-use payment method represents is "not valid," the vaulting mutation will return a validation error.

Single-Use Payment Method Isn't Vaultable

In some cases, the single-use payment method represents payment information that is not vaultable. For example, when authorizing a PayPal account, the customer only grants permission to charge it once. In that case, you are not permitted to retain the information in your vault. Any calls to the vaulting mutation with such a single-use payment method will result in an error.

Verify

Running a Verification checks whether a payment method has passed your fraud rules and the issuer has ensured it is associated with a valid account. When vaulting a credit card, by default, vaultPaymentMethod will also verify that card before vaulting. If you need to verify a multi-use payment method, provide the verifyPaymentMethod mutation with a payment method ID at the minimum.

mutation

mutation VerifyPaymentMethod($input: VerifyPaymentMethodInput!) {
verifyPaymentMethod(input: $input) {
verification {
id
status
merchantAccountId
gatewayRejectionReason
paymentMethod {
id
}
processorResponse {
legacyCode
message
}
}
}
}

variables

{
"input": {
"paymentMethodId": "id_of_payment_method"
}
}

response

{
"data": {
"verifyPaymentMethod": {
"verification": {
"id": "id_of_verification",
"status": "VERIFIED",
"merchantAccountId": "id_of_merchant_account",
"gatewayRejectionReason": null,
"paymentMethod": {
"id": "id_of_payment_method"
},
"processorResponse": {
"legacyCode": "legacy_code",
"message": "Approved"
}
}
}
},
"extensions": {
"requestId": "a-uuid-for-the-request"
}
}

Update

The only update the GraphQL API currently supports on payment methods is on a credit card's billing address. This can be accomplished with the updateCreditCardBillingAddress mutation, which will set the new billing address for a multi-use credit card, and before updating, it will verify the card and new address.

mutation

mutation UpdateCreditCardBillingAddress($input: UpdateCreditCardBillingAddressInput!){
updateCreditCardBillingAddress(input: $input){
billingAddress{
addressLine1
adminArea2
adminArea1
}
verification{
id
legacyId
status
createdAt
}
}
}

variables

{
"input": {
"paymentMethodId": "id_of_payment_method",
"billingAddress": {
"addressLine1": "123 Cantina",
"adminArea2": "Mos Eisley",
"adminArea1": "Tatooine"
}
}
}

response

{
"data": {
"updateCreditCardBillingAddress": {
"billingAddress": {
"addressLine1": "123 Cantina",
"adminArea2": "Mos Eisley",
"adminArea1": "Tatooine"
},
"verification": {
"id": "id_of_verification",
"legacyId": "legacy_id_of_verification",
"status": "VERIFIED",
"createdAt": "created_at_date"
}
}
},
"extensions": {
"requestId": "a-uuid-for-the-request"
}
}

Find

Use a node query to fetch a payment method like as in a GET request:

query

query PaymentMethod {
node(id: "id_of_payment_method"){
id
... on PaymentMethod {
id
legacyId
usage
createdAt
}
}
}

response

{
"data": {
"node": {
"id": "id_of_payment_method",
"legacyId": "legacy_id_of_payment_method",
"usage": "usage_of_payment_method",
"createdAt": "created_at_date"
}
},
"extensions": {
"requestId": "a-uuid-for-the-request"
}
}

Use the search query to search for a payment method using information on a Customer:

query

query CustomerSearch($input: CustomerSearchInput!) {
search {
customers(input: $input) {
edges {
node {
id
paymentMethods {
edges {
node {
id
createdAt
details {
... on CreditCardDetails {
brandCode
last4
expirationMonth
expirationYear
cardholderName
uniqueNumberIdentifier
}
}
}
}
}
}
}
}
}
}

variables

{
"input": {
"id": {
"is":"id_of_customer"
}
}
}

response

{
"data": {
"search": {
"customers": {
"edges": [
{
"node": {
"id": "id_of_customer",
"paymentMethods": {
"edges": [
{
"node": {
"id": "id_of_payment_method",
"createdAt": "created_at_date",
"details": {
"brandCode": "brand_code_of_credit_card",
"last4": "last_4_digits_of_an_account_number",
"expirationMonth": "MM",
"expirationYear": "YYYY",
"cardholderName": "name_of_cardholder",
"uniqueNumberIdentifier": null
}
}
}
]
}
}
}
]
}
}
},
"extensions": {
"requestId": "a-uuid-for-the-request"
}
}

If the the customer can't be found, it will return an empty list of customers like so:

response

{
"data": {
"search": {
"customers": {
"edges": []
}
}
},
"extensions": {
"requestId": "a-uuid-for-the-request"
}
}

The return value of this search query will be a CustomerConnection.

Delete

If your customer no longer wishes their payment method to be stored for future use, or you otherwise want to remove the multi-use payment method, use the deletePaymentMethodFromVault mutation. This is non-reversible; to store the same payment method again, you would need to obtain a new single-use payment method from the customer for it, and re-vault it, which would create a new multi-use payment method (with a new ID) representing the same underlying payment method.

mutation

mutation DeletePaymentMethodFromVault($input: DeletePaymentMethodFromVaultInput!) {
deletePaymentMethodFromVault(input: $input) {
clientMutationId
}
}

variables

{
"input": {
"paymentMethodId": "id_of_payment_method"
}
}

response

{
"data": {
"deletePaymentMethodFromVault": {
"clientMutationId": null
}
},
"extensions": {
"requestId": "a-uuid-for-the-request"
}
}

If the payment method can't be found, it will return an error stating "An object with this ID was not found."

Deleting A Vaulted Venmo Account

If you use the deletePaymentMethodFromVault mutation to remove a multi-use Venmo payment method, it will also delete the Venmo customer's merchant connection within their Venmo app in "Connected Businesses". However, if your vault has duplicate Venmo payment methods for the same underlying customer Venmo account, the merchant connection will not be deleted until the last payment method is deleted.

Keep in mind that a Venmo customer can also delete a merchant connection from within their Venmo app at any time. This will automatically remove the Venmo payment method from your vault. You can be notified when this happens via the PaymentMethodRevokedByCustomer webhook; see the Webhooks Guide for information on setting up webhooks outside of the GraphQL API.