PCI Vault Logo
Proxy Update Data

This guide will help you update payment card data from a third party or web frontend without having the data touch your own servers.

Similar to how you can capture full card data, you can use a capture endpoint to update a specific card with new data (e.g. updating the CVV temporarily for a call to a payment service provider)

By using uniquely generated capture endpoints you can ingest sensitive data without compromising your key or your authorization details. Capturing data this way is the most PCI compliant way of ingesting payment card data. The capture endpoint can be created so that any data sent through to it, updates an existing card already stored in the vault. Note: This guide will use the term "third party" to refer to third parties, your own web frontend or to any other untrusted source.

Overview

There are two ways to use a capture endpoint.

  • One way is to manually POST only the necessary data to the endpoint URL.
  • The other way is to create a configured hosted form which you can load in an iframe or navigate the user to.

Both methods require the creation of a capture endpoint which is locked down to a specific card.

Create a Unique Endpoint

Create an endpoint for capturing data using "Create a Capturing Endpoint".

Provide the existing token you'd like to update and optionally a reference that was stored with it. Each of these endpoints also come with a default TTL (Time To Live) of 24 hours. If you'd like to make the endpoint expire sooner, use the ttl query parameter to set it e.g. PT10M for 10 minutes. It is not recommended to make an endpoint used for card updates have a longer TTL than 24 hours.

For example, this Python code:

import requests
from requests.auth import HTTPBasicAuth

auth = HTTPBasicAuth('user', 'password')

url = "https://api.pcivault.io/v1/capture"
user = "test-user"
passphrase = "ALongAndVerySecretPassphraseThatIsSuperSecure"
token = "44c93045e3cf54d23792c7821c42c2386e3040680caaa1ab512aa45091ad8fd1"
reference = "my-reference"

res = requests.post(f'{url}?user={user}&passphrase={passphrase}&ttl=PT10M&token={token}&reference={reference}', auth=auth)

# do something with the response
print(res)
print(res.text)

should return a JSON object like this:

{
  "url":"/v1/capture/NjUDoEi3z8zFB33WEwSRg",
  "secret":"S2TRYkjufkfwf8oItW2G_j1HcZ1ftMvURZwZJlbzb2BylPEPo8536sqdkO6J9i3x",
  "expires_at":"2022-07-25T15:42:59Z",
  "lockdown_info": {
    "token": "44c93045e3cf54d23792c7821c42c2386e3040680caaa1ab512aa45091ad8fd1",
    "reference": "my-reference"
  }
}

This endpoint can only be used to update the card with token 44c93045e3cf54d23792c7821c42c2386e3040680caaa1ab512aa45091ad8fd1 and reference my-reference. Any data passed in will be merged with the existing data, except the card number itself, as that is immutable.

[Option 1] Manually Posting to a Capture Endpoint

First be sure to create your capture endpoint. Using a caputre endpoint to manually POST data is a 2-step process:

  1. Send the URL and secret to the third party.
  2. The third party sends the data to the vault and receives the same token and reference back

Step 1: Send URL & Secret to Third Party

The way in which you share the URL and Secret to the third party depends on your setup. Typically, you would do this in response to an HTTPS request from the third party.

Here are some dos and don'ts:

  • DO generate a new URL & Secret for every data item. The unique capturing endpoints are meant to be short-lived.
  • DO be careful to whom you share the URL & Secret. Anybody with the URL & Secret can POST data on your behalf until the endpoint is deleted or expired. You will be charged for the POST as if it was a normal API request.
  • DON'T make it too hard for the third party to access the URL & Secret. If you are replying to an HTTPS request, that is enough encryption. Nothing can be done with the URL & Secret except for POSTing data to the vault.
  • DON'T send your basic auth details to the third party, even if the third party is your own web frontend.
  • DON'T send your key or passphrase to the third party, even if the third party is your own web frontend.

If the third party is a web frontend, keep in mind that the user will have access to all data that you send. There is no effective way to protect the URL & Secret once it is on the user's browser. That is why it is a good idea to not disable expiry, and delete the endpoint after it was used.

Step 2: Third Party Stores the Data in the Vault

Using the URL & Secret, the third party can send data to the vault to be tokenized. The secret must be in the X-PCIVault-Capture-Secret HTTP header of the POST request.

The rest of the request works exactly the same as POSTing to the vault directly from your own server, except that the basic auth details, key, and passphrase have been replaced by the URL & Secret.

For example, you can send the data using JavaScript's fetch API:

const requestInfo = {
    method: 'POST',
    headers: {
      'X-PCIVault-Capture-Secret': 'S2TRYkjufkfwf8oItW2G_j1HcZ1ftMvURZwZJlbzb2BylPEPo8536sqdkO6J9i3x',
    },
    body: JSON.stringify({
      "card_expiry": "06-2025",
      "cvv": "145"
    }),
};

fetch("https://api.pcivault.io/v1/capture/NjUDoEi3z8zFB33WEwSRg", requestInfo)
    .then((response) => {
        return response.json();
    })
    .then((response) => {
        console.debug(response);
        // do something with the response
    })

The vault will reply to the third party with the token and reference like this:

{
  "user": "test-user",
  "token": "44c93045e3cf54d23792c7821c42c2386e3040680caaa1ab512aa45091ad8fd1",
  "reference": "my-reference"
}

[Option 2] Using a Configured Hosted Form with a Capture Endpoint

First be sure to create your capture endpoint. Using the endpoint with a configured hosted form is a 3-step process:

  1. Create a configured hosted form to only display the fields you require to update.
  2. Construct a URL to send to the third party or use as a redirect.
  3. The third party submits the form.

Step 1: Create a Configured Hosted Form

To create a configured hosted form, we use the Create a Hosted Form endpoint.

For example, this Python code:

import requests
import json
import base64

from requests.auth import HTTPBasicAuth

auth = HTTPBasicAuth('user', 'password')

# javascript to execute on successful submission
callback_code = """function(responseData, requestData) { 
  const reference = responseData.reference;
  window.location.replace(`https://mywebsite.com/update/success?reference=${reference}`);
}"""

url = "https://api.pcivault.io/v1/capture/iframe"
body = {
  "success_callback": base64.b64encode(callback_code.encode("utf-8")).decode("utf-8"),
  "field_options": {
    "reference": {
      "visible": False
    },
    "card_holder": {
      "visible": False
    },
    "expiry": {
      "visible": False
    },
    "card_number": {
      "visible": False
    }
  }
}
res = requests.post(f'{url}?form_type=pcd', auth=auth, data=json.dumps(body))

# do something with the response
print(res)
print(res.text)

should return a JSON object like this:

{
  "type": "pcd",
  "id": "MmRMVP4UjYD8g5kVUcmx4Z",
  "link": "api.pcivault.io/v1/capture/iframe/MmRMVP4UjYD8g5kVUcmx4Z"
}

Make note of the link field, we'll use it to construct a URL to load the iframe, which makes use of the capture endpoint we created earlier.

Step 2: Construct a URL to Send to the Third Party

Putting it all together, we use the capture endpoint id and secret with our configured form url as follows:

https://{{form_link}}?unique_id={{capture_endpoint_id}}&secret={{capture_endpoint_secret}}

For example, https://api.pcivault.io/v1/capture/iframe/MmRMVP4UjYD8g5kVUcmx4Z?unique_id=NjUDoEi3z8zFB33WEwSRg&secret=S2TRYkjufkfwf8oItW2G_j1HcZ1ftMvURZwZJlbzb2BylPEPo8536sqdkO6J9i3x

The first part of the URL is the link to the configured form, and as query string parameters we pass the capture endpoint id as well as the capture endpoint secret. This URL will load the configured hosted form which hides all fields except the CVV, coupled to the capture endpoint which we locked down to a specific card token and reference. Data submitted through this form will be merged with the existing data stored in the vault, thereby updating the CVV field only. (If you would like to update the expiry date too, simply create your configured hosted form with "expiry": {"visible": True} in the field_options)

This URL can be loaded as the src of an iframe or the user can be redirected to it.

Step 3: The Third Party Submits the Form

When the HTML form is submitted, the data captured hits the capture endpoint. On a successful HTTP request, the callback function will be executed. In this example we created the configured form with a callback function which redirects the user to https://mywebsite.com/update/success?reference=${reference}, but any of the returned fields (token, reference or user) can be leveraged to determine what the next page rendered looks like.