Venmo

Client-Side Implementationanchor

Set up your iOS clientanchor

Get the SDKanchor

CocoaPodsanchor

Include Braintree/Venmo in your Podfile:

  1. Ruby
# Podfile
pod 'Braintree/Venmo'

Swift Package Manageranchor

Include the BraintreeVenmo framework.

Carthageanchor

Include the BraintreeCore and BraintreeVenmo frameworks.

Allowlist Venmo URL schemeanchor

You must add the following to the queries schemes allowlist in your app's info.plist:

  1. XML
<key>LSApplicationQueriesSchemes</key>
<array>
  <string>com.venmo.touch.v2</string>
</array>

Include the app display nameanchor

You must have a display name in your app's info.plist to help Venmo identify your application:

  1. XML
<key>CFBundleDisplayName</key>
<string>Your App Name</string>

Setup for app context switchinganchor

To handle workflows that involve switching to another app or SFSafariViewController for authentication, you must register a URL type and configure your app to handle return URLs.

Register a URL typeanchor

  1. In Xcode, click on your project in the Project Navigator and navigate to App Target > Info > URL Types
  2. Click [+] to add a new URL type
  3. Under URL Schemes, enter your app switch return URL scheme. This scheme must start with your app's Bundle ID and be dedicated to Braintree app switch returns. For example, if the app bundle ID is com.your-company.your-app, then your URL scheme could be com.your-company.your-app.payments.
important

If you have multiple app targets, be sure to add the return URL type for all of the targets.

Testing the URL typeanchor

You can test out your new URL scheme by opening up a URL that starts with it (e.g. com.your-company.your-app.payments://test) in Mobile Safari on your iOS Device or Simulator.

In addition, always test your app switching on a real device.

Set your return URLanchor

In your AppDelegate's application:didFinishLaunchingWithOptions: implementation, use setReturnURLScheme: with the value you set above.

For example:

  1. Swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    BTAppContextSwitcher.setReturnURLScheme("com.your-company.your-app.payments")
    return true
}
importantThe SSL certificates for all Braintree SDKs are set to expire by June 31, 2025. This will impact existing versions of the SDK in published versions of your app. To reduce the impact, upgrade the iOS SDK to version 6.17.0+ for the new SSL certifications. If you do not decommission your app versions that include the older SDK versions or force upgrade your app with the updated certificates by the expiration date, 100% of your customer traffic will fail.

Handle app context switchinganchor

Then pass the payment authorization URL to Braintree for finalization.

If you’re using SwiftUI, you must add the onOpenURL(perform:) modifier to your ContentView, and then call BTAppContextSwitcher's handleOpen(url:) method.

  1. Swift
.onOpenURL { url in
    BTAppContextSwitcher.sharedInstance.handleOpen(url)
}

If you're using UISceneDelegate (introduced in iOS 13), call BTAppContextSwitcher's handleOpenURL(context:)'s method from within the scene:openURLContexts scene delegate method.

  1. Swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
	URLContexts.forEach { context in
		if context.url.scheme?.localizedCaseInsensitiveCompare("com.your-company.your-app.payments") == .orderedSame {
			BTAppContextSwitcher.sharedInstance.handleOpenURL(context: context)
		}
	}
}

Otherwise, if you aren't using UISceneDelegate, call BTAppContextSwitcher's handleOpen(_:)'s method from within the application:openURL:options app delegate method.

  1. Swift
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
	if url.scheme?.localizedCaseInsensitiveCompare("com.your-company.your-app.payments") == .orderedSame {
		BTAppContextSwitcher.sharedInstance.handleOpen(url)
	}
	return false
}
important

The SSL certificates for all Braintree SDKs are set to expire by June 31, 2025. This will impact existing versions of the SDK in published versions of your app. To reduce the impact, upgrade the iOS SDK to version 6.17.0+ for the new SSL certifications.

If you do not decommission your app versions that include the older SDK versions or force upgrade your app with the updated certificates by the expiration date, 100% of your customer traffic will fail.

Choose an integration methodanchor

You can set up your client-side either with our Drop-in UI or with a custom integration.

Drop-in integrationanchor

Our Drop-in UI is the fastest way to set up your client-side integration.

For full details, see Drop-in Setup and Integration.

Handling the responseanchor

To handle the successful Venmo payment, cast the BTPaymentMethodNonce to a BTVenmoAccountNonce to access the username property that you receive from the BTDropInResult.

Custom integrationanchor

Alternatively, you can add Venmo to your current custom integration. Keep in mind, for compliance purposes, we require you to present the customer with an order summary before and after purchase.

The pre-purchase summary should include:

  • The items ordered
  • The total order price
  • An indication of Venmo as the payment method

The post-purchase summary can either be shown in the UI or sent via email. It should include:

  • The items purchased
  • The total purchase price
  • The customer's name
  • The customer's Venmo username

Failing to comply with these guidelines can lead to an interruption of your Venmo service.

note

Click here to download Venmo's brand guidelines, and be sure to follow them when configuring the Venmo button or making any other references to Venmo in your app.

  1. Swift
class ViewController: UIViewController {

    var venmoClient : BTVenmoClient?
    var venmoButton : UIButton?
    var apiClient : BTAPIClient!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.apiClient = BTAPIClient(authorization: "<#CLIENT_AUTHORIZATION#>")
        self.venmoClient = BTVenmoClient(apiClient: self.apiClient)
        // setup venmoButton ....
        self.venmoButton?.isHidden = !self.venmoClient?.isVenmoAppInstalled() ?? true
    }

    func tappedButton() {
        let request = BTVenmoRequest(paymentMethodUsage: .multiUse)
        request.vault = true // Set this and use a client token with a customer ID to vault
        self.venmoClient?.tokenize(request) { (venmoAccount, error) in

            guard let venmoAccount = venmoAccount else {
                print("Error: (error)")
                return
            }

            // You got a Venmo nonce!
            print(venmoAccount.nonce)
        }
    }
}
note

It's best practice to display the customer's Venmo username alongside their Venmo payment method in your checkout UI – like you would the last 4 digits of a credit card number.

Payment method usageanchor

You must initialize a BTVenmoRequest with a paymentMethodUsage:

  • .multiUse: Request authorization for future payments (vaulting allowed)
  • .singleUse: Request authorization for a one-time payment (vaulting not allowed)

If neither of these options has been specified, vaulting will be supported, but customers will see a legacy UI flow in the Venmo app. We recommend using .multiUse or .singleUse for the best customer experience.

The payment method usage will affect the customer flow by:

  • Displaying different phrases to the customer on the transaction consent page (e.g. "Authorize Business Name to pay with Venmo" vs. "Authorize Business Name to pay with Venmo for future purchases" where Business Name is the business name submitted in the Venmo application form).
  • Not displaying a merchant connection on the Connected Businesses page in the Venmo app when the paymentMethodUsage property is .singleUse.
  • Allowing customers to update their funding instrument on the Connected Businesses page in the Venmo app when the paymentMethodUsage property is .mulitiUse.
note

If paymentMethodUsage is set to .singleUse:

  • A validation error will be returned if attempting to vault via PaymentMethod.create or Customer.create.
  • The transaction will be processed normally but the nonce will not be vaulted if store-in-vault or store-in-vault-on-success is passed during transaction.sale.
  1. Swift
let request = BTVenmoRequest(paymentMethodUsage: .multiUse)
        self.venmoClient.tokenize(with: request) { (nonce, error) in
            // ...
        }

For improved security we strongly recommend merchants to use the Universal Links flow when integrating with Venmo. Customers who do not have the Venmo app installed, or if the Venmo app cannot be presented, will fallback to a web based Venmo flow. In the web based Venmo fallback customers will be presented the flow in their default browser and returned to the merchant app securely.

important

This feature is only available in iOS v6.13.0+ and Android v4.42.0+

  1. Swift
let request = BTVenmoRequest(paymentMethodUsage: .multiUse) // or .singleUse
        request.fallbackToWeb = true

Multiple profilesanchor

If you have a custom integration and have onboarded multiple apps for Venmo processing with a single Braintree gateway, you'll need to pass the profile_id to specify which Venmo profile to present during the payment flow.

You'll also need to pass the profile_id when creating the transaction on the server side.

  1. Swift
let request = BTVenmoRequest(paymentMethodUsage: .multiUse)
request.profileID = "YOUR_VENMO_PROFILE_ID"
self.venmoClient.tokenize(request) { (nonce, error) in
    // ...
}
note

If you have multiple business profiles, the profile_id for each profile can be found by logging into the Control Panel, clicking the gear icon in the top right corner, selecting Processing from the drop-down menu, scrolling to Venmo, and clicking the Options link.

Collect device dataanchor

You must collect information about the customer's device before creating each transaction.

Get the SDKanchor

CocoaPodsanchor

Include Braintree/DataCollector in your Podfile:

  1. Ruby
# Podfile
  pod 'Braintree/DataCollector'

Swift Package Manageranchor

Include the DataCollector framework.

Carthageanchor

Include the DataCollector and PPRiskMagnes frameworks.

Collect device dataanchor

  1. Swift
let apiClient = BTAPIClient("<TOKENIZATION_KEY_OR_CLIENT_TOKEN>")
  let dataCollector = BTDataCollector(apiClient: apiClient)

  dataCollector.collectDeviceData { deviceData, error in
      // handle response
  }

You'll need to pass this deviceData when creating the Venmo transaction from your server.

important

Be sure to pass device data as close to the transaction creation as possible. Doing so will help reduce decline rates.

Shipping and Billing Address collectionanchor

Starting in Braintree iOS v6.4.0, you can specify if you wish to receive a customer's Venmo shipping and billing address by setting the collectCustomerBillingAddress and collectCustomerShippingAddress properties on BTVenmoRequest. When these flags are enabled, Venmo will collect the required addresses from the consumer and send them back in the response object.

  1. Swift
let request = BTVenmoRequest()
  request.paymentMethodUsage = .multiUse
  request.collectCustomerBillingAddress = true
  request.collectCustomerShippingAddress = true
  self.venmoDriver?.tokenizeVenmoAccount(with: request) { (nonce, error) in
    // ...
  }
note

You will only be able to collect customer addresses if you have Enriched Customer Data (ECD) enabled in the Control Panel. Details about how to enable ECD can be found in this support article. A validation error will be returned if attempting to collect customer addresses without enabling ECD.

Once the tokenization call is successful, you will receive the shipping and billing address in the response object.

  1. Swift
self.venmoDriver?.tokenizeVenmoAccount(with: request) { (nonce, error) in
    // Display the billing address
    let billingAddress = venmoAccount.billingAddress
    print(billingAddress.streetAddress)
    print(billingAddress.extendedAddress)
    print(billingAddress.locality)
    print(billingAddress.region)
    print(billingAddress.postalCode)

    // Display the shipping address
    let shippingAddress = venmoAccount.shippingAddress
    print(shippingAddress.streetAddress)
    print(shippingAddress.extendedAddress)
    print(shippingAddress.locality)
    print(shippingAddress.region)
    print(shippingAddress.postalCode)
  }

Amounts and Line Itemsanchor

Starting in Braintree iOS v6.4.0, if the create call is made in the context of a purchase, you will need to pass the total amount of the transaction which will be displayed to the user on the Venmo paysheet. Additionally, you can also pass other transaction details that you would like to render to the user such as subtotal, discount, taxes, shipping amount and line items.

  1. Swift
let request = BTVenmoRequest(paymentMethodUsage: .multiUse)
  request.profileId = "your-profile-id"
  request.totalAmount = "10.00"

  // Set optional amounts & line items
  request.subTotalAmount = "8.00"
  request.taxAmount = "1.00"
  request.discountAmount = "1.00"
  request.shippingAmount = "2.00"
  request.lineItems = [
    BTVenmoLineItem(quantity: 1, unitAmount: "4.00", name: "item-1", kind: .debit),
    BTVenmoLineItem(quantity: 1, unitAmount: "4.00", name: "item-2", kind: .debit)
  ]

  self.venmoDriver?.tokenizeVenmoAccount(with: request) { (nonce, error) in
    // ...
  }
note

All amount and line-item fields are optional except for totalAmount, which is required in the context of purchase. If the tokenize call is for vaulting only, totalAmount can be omitted.

important

The following validations will be performed on the provided transaction details:

  • All amounts are expected to be in USD
  • All amounts must be non-negative
  • All amounts must be of string type and must contain either a whole number or a number with two decimal places
  • Line-item should have four properties: item name, quantity, unit amount and type
  • Line-item type must be either CREDIT or DEBIT
  • The amounts for all individual line items present must add up to the total amount, or sub-total when present
  • All individual amounts (discount, shipping, tax, sub-total) must add up to the total amount

Next Page: Server-side