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.
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:
- the payment method verification failed (for payment methods that require it)
- the single-use payment method has already been consumed
- the single-use payment method has expired
- the single-use payment method represents invalid payment information
- the single-use payment method represents payment information that isn't vaultable
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:
- JSON
{
"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:
- Graphql
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"
}
}
Search
Use the search
query to search for a payment method using information on a Customer
:
- Graphql
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.