Save cards with the iOS SDK

CURRENT

Last updated: Feb 27th, 8:47am

Allow customers to save their credit or debit cards in order to eliminate the need to re-enter payment details on subsequent purchases - leading to a faster checkout experience.

Use cases

Businesses save payment methods if they want customers to:

  • Check out without re-entering a payment method
  • Pay after use, for example, ride-sharing and food delivery

Availability

  • In the US only.
  • For both desktop and mobile web.

How it works

PayPal encrypts payment method information and stores it in a digital vault for that customer.

  1. The payer saves their payment method.
  2. For a first-time payer, PayPal creates a customer ID. Store this within your system for future use.
  3. The customer ID can be used to save another payment method for an existing customer or to display saved payment methods for a customer in your application.

The checkout process is now shorter because it uses saved payment information.

Know before you code

  • This integration requires a PayPal Developer account.
  • You'll need to have an existing advanced credit and debit card payments integration. PayPal must approve your account to process advanced credit and debit card payments.
  • Complete the steps in Get started to get the following sandbox account information from the Developer Dashboard:
    • The sandbox client ID and secret of your REST app.
    • An access token to use the PayPal REST API server.
  • This client-side and server-side integration uses the following:

1. Set up sandbox to save payment methods

Set up your sandbox and live business accounts to save payment methods:

  1. Log in to the Developer Dashboard.
  2. Under REST API apps, select your app name.
  3. Under Sandbox App Settings > App Feature Options, check Accept payments.
  4. Expand Advanced options. Confirm that Vault is selected.


2. Add toggle for payers to save card

Use a selection UI element to select the vault option.

    1VStack {
    2 Toggle("Save your card", isOn: $shouldSaveCard)
    3}

    3. Send the user's preference to your endpoint

    When the user selects the submit button, pass the user's vault preference to your endpoint that calls the Orders API. You will use the user's preference to populate the request to the Orders API in the next step.

    4. Create order

    Server side

    Set up your server to call the Orders API. If the user consents to save their payment method, include a payment_source object in the request to the Orders API. See the following code snippet.

    First-time payer

    Save payment method for first-time payers

    This request is for payers who:

    • Don't have a payment source saved into the vault.
      1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
      2 -H "Content-Type: application/json" \
      3 -H "Authorization: Bearer 'ACCESS-TOKEN'" \
      4 -d '{
      5 "intent": "CAPTURE",
      6 "purchase_units": [{
      7 "amount": {
      8 "currency_code": "USD",
      9 "value": "100.00"
      10 }
      11 }],
      12 "payment_source": {
      13 "card": {
      14 "attributes": {
      15 "vault": {
      16 "store_in_vault": "ON_SUCCESS"
      17 }
      18 }
      19 }
      20 }
      21 }

      Returning payer

      Save payment method for returning payers

      This request is for payers who:

      • Already have a payment method saved in the vault.
      • Want to save another payment method to the vault.

      Pass the PayPal-generated customer.id as part of this request. Link additional payment_sources to this customer through their customer.id. The customer.id is returned in the response from an authorize or capture request.

        1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
        2 -H "Content-Type: application/json" \
        3 -H "Authorization: Bearer 'ACCESS-TOKEN'" \
        4 -d '{
        5 "intent": "CAPTURE",
        6 "purchase_units": [{
        7 "amount": {
        8 "currency_code": "USD",
        9 "value": "100.00"
        10 }
        11 }],
        12 "payment_source": {
        13 "card": {
        14 "attributes": {
        15 "vault": {
        16 "store_in_vault": "ON_SUCCESS"
        17 },
        18 "customer": {
        19 "id": "'PayPal-generated customer id'"
        20 }
        21 }
        22 }
        23 }
        24 }

        Pass the order ID and card details to the iOS SDK. Calling CardClient.approveOrder() updates the order with the new card details. PayPal handles any PCI compliance issues. When approveOrder() succeeds, you can then authorize or capture the order using the orderID.

        5. Approve order using iOS SDK

        In the iOS SDK you will need to create a CardRequest to pass into the approve function.

        A CardRequest object:

        • Attaches a card to an ORDER_ID.
        • Launches 3D Secure when a payment requires additional authentication.

        1. Collect card payment details

        Build a card object with the buyer's card details.

          1let card = Card(
          2 number: "4005519200000004",
          3 expirationMonth: "01",
          4 expirationYear: "2025",
          5 securityCode: "123",
          6 cardholderName: "Jane Smith",
          7 billingAddress: Address(
          8 addressLine1: "123 Main St.",
          9 addressLine2: "Apt. 1A",
          10 locality: "City",
          11 region: "IL",
          12 postalCode: "12345",
          13 countryCode: "US"
          14 )
          15)

          Collecting a billing address can reduce the probability of an authentication challenge.

          2. Build CardRequest

          Build a CardRequest with the card object and your ORDER_ID:

            1let cardRequest = CardRequest(
            2 orderID: "ORDER_ID",
            3 card: card,
            4 sca: .scaAlways // default value is .scaWhenRequired
            5)

            3D Secure is supported for all card payments to comply with the Second Payment Services Directive (PSD2). PSD2 is a European Union regulation that introduces Strong Customer Authentication (SCA) and other security requirements.

            Select your SCA launch option type using the sca parameter in the CardRequest initializer:

            • SCA.scaWhenRequired launches an SCA challenge when applicable. This is enabled by default.
            • SCA.scaAlways requires an SCA challenge for all card transactions.

            3. Approve order

            After your CardRequest has the card details, call cardClient.approveOrder() to process the payment. Set up your CardDelegate to handle successful payments, errors, cancellations, and 3D Secure transaction flows.

              1let coreConfig = CoreConfig(clientID: "CLIENT_ID", environment: .sandbox)
              2let cardClient = CardClient(config: coreConfig)
              3cardClient.delegate = self
              4cardClient.approveOrder(request: cardRequest)

              4. Handle payment result scenarios

                1extension MyViewController: CardDelegate {
                2 // MARK: - CardDelegate
                3 func card(_ cardClient: CardClient, didFinishWithResult result: CardResult) {
                4 // Order was approved and is ready to be captured/authorized (refer to the next step)
                5 }
                6 func card(_ cardClient: CardClient, didFinishWithError error: CoreSDKError) {
                7 // Handle the error by accessing `error.localizedDescription`
                8 }
                9 func cardDidCancel(_ cardClient: CardClient) {
                10 // 3D Secure auth was canceled by the user
                11 }
                12 func cardThreeDSecureWillLaunch(_ cardClient: CardClient) {
                13 // 3D Secure auth will launch
                14 }
                15 func cardThreeDSecureDidFinish(_ cardClient: CardClient) {
                16 // 3D Secure auth finished
                17 }
                18}

                6. Authorize or capture order and save card

                Server side

                Set up your server to call the v2 Orders API:

                Request

                Authorize or capture order request

                1. Authorize
                2. Capture
                1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/authorize \
                2 -H "Content-Type: application/json" \
                3 -H "Authorization: Bearer 'ACCESS-TOKEN'" \
                4 -d '{}'

                Response

                  1{
                  2 "id": "5O190127TN364715T",
                  3 "status": "COMPLETED",
                  4 "payment_source": {
                  5 "card": {
                  6 "brand": "VISA",
                  7 "last_digits": "4949"
                  8 "attributes": {
                  9 "vault": {
                  10 "id": "nkq2y9g",
                  11 "customer": {
                  12 "id": "695922590"
                  13 },
                  14 "status": "VAULTED",
                  15 "links": [{
                  16 "href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/nkq2y9g",
                  17 "rel": "self",
                  18 "method": "GET"
                  19 },
                  20 {
                  21 "href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/nkq2y9g",
                  22 "rel": "delete",
                  23 "method": "DELETE"
                  24 },
                  25 {
                  26 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
                  27 "rel": "up",
                  28 "method": "GET"
                  29 }
                  30 ]
                  31 }
                  32 }
                  33 }
                  34 },
                  35 "purchase_units": [{
                  36 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
                  37 "payments": {
                  38 "captures": [{
                  39 "id": "3C679366HH908993F",
                  40 "status": "COMPLETED",
                  41 "amount": {
                  42 "currency_code": "USD",
                  43 "value": "100.00"
                  44 },
                  45 "seller_protection": {
                  46 "status": "NOT_ELIGIBLE"
                  47 },
                  48 "final_capture": true,
                  49 "seller_receivable_breakdown": {
                  50 "gross_amount": {
                  51 "currency_code": "USD",
                  52 "value": "100.00"
                  53 },
                  54 "paypal_fee": {
                  55 "currency_code": "USD",
                  56 "value": "3.00"
                  57 },
                  58 "net_amount": {
                  59 "currency_code": "USD",
                  60 "value": "97.00"
                  61 }
                  62 },
                  63 "create_time": "2022-01-01T21:20:49Z",
                  64 "update_time": "2022-01-01T21:20:49Z",
                  65 "processor_response": {
                  66 "avs_code": "Y",
                  67 "cvv_code": "M",
                  68 "response_code": "0000"
                  69 },
                  70 "links": [{
                  71 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/3C679366HH908993F",
                  72 "rel": "self",
                  73 "method": "GET"
                  74 },
                  75 {
                  76 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/3C679366HH908993F/refund",
                  77 "rel": "refund",
                  78 "method": "POST"
                  79 }
                  80 ]
                  81 }]
                  82 }
                  83 }],
                  84 "links": [{
                  85 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
                  86 "rel": "self",
                  87 "method": "GET"
                  88 }]
                  89}

                  In the response from the Authorize or Capture request, the Orders v2 API interacts with the Payment Method Tokens v3 API to save the card.

                  The payment_source.card.attributes.vault stores the card information as the vault.id, which can be used for future payments when the vault.status is VAULTED.

                  Save approved payment source

                  If the payment has been authorized or captured, the payer does not need to be present to save a payment_source. To keep checkout times as short as possible, the Orders API responds as soon as payment is captured.

                  If the attributes.vault.status returned after payment is APPROVED, you won't have a vault.id yet. An example of the attributes object from this scenario is in the following sample:

                    1"attributes": {
                    2 "vault": {
                    3 "status": "APPROVED",
                    4 "links": [
                    5 {
                    6 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
                    7 "rel": "up",
                    8 "method": "GET"
                    9 }
                    10 ]
                    11 }
                    12 }

                    In order to retrieve a vault_id when an APPROVED status is returned, you'll need to subscribe to the VAULT.PAYMENT-TOKEN.CREATED webhook event.

                    The Payment Method Tokens API sends a webhook event after the payment source is saved. An example of the VAULT.PAYMENT-TOKEN.CREATED webhook payload is shown in the following sample:

                      1{
                      2 "id":"WH-1KN88282901968003-82E75604WM969463F",
                      3 "event_version":"1.0",
                      4 "create_time":"2022-08-15T14:13:48.978Z",
                      5 "resource_type":"payment_token",
                      6 "resource_version":"3.0",
                      7 "event_type":"VAULT.PAYMENT-TOKEN.CREATED",
                      8 "summary":"A payment token has been created.",
                      9 "resource":{
                      10 "time_created":"2022-08-15T07:13:48.964PDT",
                      11 "links":[
                      12 {
                      13 "href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m",
                      14 "rel":"self",
                      15 "method":"GET",
                      16 "encType":"application/json"
                      17 },
                      18 {
                      19 "href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m",
                      20 "rel":"delete",
                      21 "method":"DELETE",
                      22 "encType":"application/json"
                      23 }
                      24 ],
                      25 "id":"nkq2y9g",
                      26 "payment_source":{
                      27 "card":{
                      28 "last_digits":"1111",
                      29 "brand":"VISA",
                      30 "expiry":"2027-02",
                      31 "billing_address":{
                      32 "address_line_1":"123 Main St.",
                      33 "address_line_2":"Unit B",
                      34 "admin_area_2":"Anytown",
                      35 "admin_area_1":"CA",
                      36 "postal_code":"12345",
                      37 "country_code":"US"
                      38 }
                      39 }
                      40 },
                      41 "customer":{
                      42 "id":"695922590"
                      43 }
                      44 },
                      45 "links":[
                      46 {
                      47 "href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F",
                      48 "rel":"self",
                      49 "method":"GET"
                      50 },
                      51 {
                      52 "href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F/resend",
                      53 "rel":"resend",
                      54 "method":"POST"
                      55 }
                      56 ]
                      57 }

                      In this example, the resource.id field is the vault ID, and resource.customer.id is the PayPal-generated customer ID.

                      You can now style your card fields and test a purchase.

                      Payment processor codes

                      Payment processors return the following codes when they receive a transaction request. For advanced card payments, the code displays in the authorization object under the response_code field.

                      The following sample shows the processor response codes returned in an authorization (avs_code) and capture call (cvv_code) response:

                        1"processor_response": {
                        2 "avs_code": "Y",
                        3 "cvv_code": "S",
                        4 "response_code": "0000"
                        5 }

                        See the Orders API response_code object to get the processor response code for the non-PayPal payment processor errors.

                        7. Pay with saved payment methods

                        When a payer returns to your site, you can show the payer's saved payment methods with the Payment Method Tokens API.

                        List all saved payment methods

                        Make the server-side list all payment tokens API call to retrieve payment methods saved to a payer's PayPal-generated customer ID. Based on this list, you can show all saved payment methods to a payer to select during checkout.

                        Show saved card to payer

                        Display the saved card to the payer and use the Orders API to make another transaction. Use the vault ID the payer selects as an input to the Orders API.


                        8. Test your integration

                        Test your vault integration in the PayPal sandbox.

                        1. Copy the sample request code.
                        2. Change 'ACCESS_TOKEN' to your access token.

                        Save payment method

                        1. On the checkout page, enter the card information and select the option to save the card. You can use test card numbers from this page for testing.
                        2. Capture the transaction.
                        3. Log in to sandbox with your merchant account and verify the transaction.

                        Pay with a saved payment method

                        1. Use the list all payment tokens API to retrieve all the payment methods saved for the payer.
                        2. Capture the payment by passing the payer-selected vault ID to the Orders API.
                        3. Log in to the sandbox with your merchant account and verify the transaction.


                        Next steps

                        If you accept cookies, we’ll use them to improve and customize your experience and enable our partners to show you personalized PayPal ads when you visit other sites. Manage cookies and learn more