Vaulting and Customers

The card reader can collect a physically presented payment method and store it for future transactions.

Getting Started

If you're building a checkout experience that might require additional charges in the future when the customer is no longer present, you may choose to create a flow that vaults the payment method presented to the card reader.

These use cases might include keeping a card on file for members, signing a customer up for a subscription, or performing a checkout in which some items are shipped or fulfilled today and others, later.

These vaulted payment methods can be linked to a customer profile (customer ID) in Braintree which can include additional customer data such as name, email, phone #, etc... or they can be used as standalone payment method tokens (payment method ID) for future payments against a customer profile stored in your own CRM or POS application.

Future charges against a Multi Use Payment Method will be processed as card-not-present and receive card not present pricing.

Create a Customer ID (Optional)

The customer object is an important optional component of the Braintree gateway. Use customer ID's to store and organize payment methods. A single customer ID can have multiple payment methods.

mutation createCustomer($input: CreateCustomerInput!) {
  createCustomer(input: $input) {
    customer {
      id
      legacyId
      firstName
      lastName
      email
      phoneNumber
      createdAt
    }
  }
}

Vaulting a Card without a Transaction

This process can be used to request the vaulting of a PaymentMethod without a related transaction.

Step 1 - Request Vault from In-Store Reader

This will initialize the card reader for vaulting flow. You will receive a inStoreContextPayload.id in the response to poll and check the status of the customer's interaction with the reader.

mutation RequestVaultFromInStoreReader(
  $input: RequestVaultFromInStoreReaderInput!
) {
  requestVaultFromInStoreReader(input: $input) {
    id
    status
    reader {
        id
        name
        status
    }
  }
}

Step 2 - Check the Status of the Context

When the context comes back with a status of COMPLETE, you will receive a paymentMethod.id in the response to use in future requests to make charges.

query ID($contextId: ID!) {
  node(id: $contextId) {
    ... on RequestVaultInStoreContext {
      id
      status
      reader {
        id
        name
        status
      }
      paymentMethod {
        id
        legacyId
        usage
        details {
          ... on CreditCardDetails {
            brandCode
            bin
            last4
            cardholderName
            expirationMonth
            expirationYear
            uniqueNumberIdentifier
            binData {
              prepaid
              debit
              countryOfIssuance
            }
          }
        }
        customer {
          id
          email
          firstName
          lastName
        }
      }
      verification {
        id
      }
    }
  }
}

Vaulting a Card with a Transaction

This process can be used when you wish to place an immediate charge on a card for a known amount, but also save the card for future usage. This might be common where a customer leaves with 3 items today, but 1 item will ship in the future from a warehouse.

Step 1 - Request Charge from In-Store Reader

Simply include the vaultPaymentMethodAfterTransacting attribute in the requestChargeFromInStoreReader mutation. This will initialize the card reader for the normal charge flow. You will receive a inStoreContextPayload.id in the response to poll and check the status of the customer's interaction with the reader.

mutation RequestChargeFromInStoreReader(
  $input: RequestChargeFromInStoreReaderInput!
) {
  requestChargeFromInStoreReader(input: $input) {
        clientMutationId
        id
        status
        reader {
            id
            name
            status
        }
  }
}

Step 2 - Check the Status of the Context

When the context comes back with a status of COMPLETE, you will receive a RequestChargeInStoreContext.transaction.customer object in the response to use in future requests to make charges.

{
 node(id: "{{last_braintree_instore_context}}") {
  ... on RequestChargeInStoreContext {
   id
   status
   statusReason
   reader {
    id
    name
    status
   }
   transaction {
    id
    orderId
    status
    statusHistory {
     ... on PaymentStatusEvent {
      status
      timestamp
      terminal
      ... on AuthorizedEvent {
       processorResponse {
        authorizationId
        emvData
        message
        legacyCode
        retrievalReferenceNumber
       }
      }
      ... on GatewayRejectedEvent {
       gatewayRejectionReason
      }
      ... on FailedEvent {
       processorResponse {
        retrievalReferenceNumber
        emvData
        message
        legacyCode
       }
       networkResponse {
        message
        code
       }
      }
      ... on ProcessorDeclinedEvent {
       processorResponse {
        legacyCode
        message
        authorizationId
        additionalInformation
        retrievalReferenceNumber
        emvData
       }
       declineType
       networkResponse {
        code
        message
       }
      }
     }
    }
    merchantAddress {
     company
     streetAddress
     addressLine1
     extendedAddress
     addressLine2
     locality
     adminArea2
     region
     adminArea1
     postalCode
     countryCode
     phoneNumber
    }
    amount {
     value
     currencyIsoCode
    }
    merchantAccountId
    merchantName
    createdAt
    channel
    customFields {
     name
     value
    }
    paymentMethodSnapshot {
     ... on CreditCardDetails {
      origin {
       details {
        ... on EmvCardOriginDetails {
         applicationPreferredName
         applicationIdentifier
         terminalId
         inputMode
         pinVerified
        }
       }
      }
      brandCode
      last4
      bin
      expirationMonth
      expirationYear
      cardholderName
      binData {
       issuingBank
       countryOfIssuance
       prepaid
       healthcare
       debit
       commercial
      }
     }
    }
   }
  }
 }
}

Making Future Charges

Use the standard Braintree eCommerce GraphQL mutations to make future charges on the paymentMethod.id generated using the above vaulting flows.

Vaulted Digital Wallet payment methods

When digital wallets (such as Apple Pay, Google Pay, and Samsung Pay) are used on the card reader, and a vaulted payment method is requested, that vaulted payment method is stored in the Braintree vault. When that paymentMethod.id token is then used for a subsequent transaction, an MIT (merchant-initiated transaction) flag will be automatically applied to the transaction. This will result in these transactions having an auth expiry window of 24 hours. This means that you should factor in this auth expiry window into your capture flow and re-auth logic.

We suggest parsing the authorizationExpiresAt object from the API response, which will indicate when the authorization will expire. In the case of authorizations initiated from a paymentMethodId token originating from a card present digital wallet, these auth expiry windows will be 24 hours. You may wish to use this to support your re-auth logic.

Tips when using Vaulting

  • The paymentMethodId token is great for performing future charges but is unique per vaulting request, so it is not recommended to be used for customer data analytics.

  • The uniqueNumberIdentifier is a unique token per card number that can be used for customer analytics; however, it cannot be used for performing future charges.

  • The uniqueNumberIdentifer is only available for cards and not available for QRC payment methods (PayPal and Venmo).

  • There are a couple of options when it comes to requesting to vault a payment method. You may request a paymentMethodId token upon a successful auth attempt or "ALWAYS" for every auth attempt, even if unsuccessful.

Last updated