PCI Vault Logo
Adyen

Sending card data to Adyen

PCI Vault has the ability to forward card data to third parties.

In this proxy recipe, we'll detail how to cater to a common use-case, where card data is forwarded to Adyen to create a payment transaction without it ever passing through your own server.

Unlike some other payment gateways, Adyen does not require any complicated hashed signatures or data encryption to be applied on the data. This removes the need to create a custom rule to do all the computation. The process is relatively straighforward.

Overview

In this proxy recipe, we'll show you how to:

  1. Initiate a proxy request
  2. Handle the response from Adyen

Step 1: Initiate a proxy request

We'll use the Proxy Post endpoint to initiate a proxy request. The following query string parameters are required:

  • token: the token identifying the card we'd like to send to Adyen
  • user: the key used to encrypt the data
  • passphrase: the passphrase for the key used to encrypt the data

The request URL will look like https://api.pcivault.io/v1/proxy/post?token=uniquetoken&user=ABCD&passphrase=secretpassphrase

The request body will look something like:

{
  "request": {
    "method": "POST",
    "url": "https://yoursubdomain.adyen.com/v71/payments", //remember to set your account-specific subdomain here
    "headers": [
      {
        "Content-Type": "application/json"
      },
      {
        "X-API-Key": "{{api_key}}"
      },
      {
        "Idempotency-Key": "{{idempotency_key}}"
      }
    ],
    "body": "{\"amount\": {\"currency\": \"{{currency}}\",\"value\": {{amount}}},\"reference\": \"{{reference}}\",\"paymentMethod\": {\"type\": \"scheme\",\"number\": \"{{card_number}}\",\"expiryMonth\": \"{{expiry_month}}\",\"expiryYear\": \"{{expiry_year}}\",\"holderName\": \"{{card_holder}}\",\"cvc\": \"{{cvv}}\"},\"returnUrl\": \"{{return_url}}\",\"merchantAccount\": \"{{merchant_account}}\"}",
    "extra_data": {
      "api_key": "your-adyen-api-key",
      "idempotency_key": "uuid-generated-for-request",
      "currency": "USD",
      "amount": 1000,
      "reference": "youruniqueref",
      "return_url": "https://your-company.example.com/...",
      "merchant_account": "yourmerchantaccount",
    }
  },
  "synchronous": true
}

(Note: this request uses field names as they would be captured by our Hosted Form, if your data is in a different format, these field names have to be adjusted accordingly)

We define the proxy request as being a "POST" method, having content-type header of application/json and we also set our Adyen API key and unique idempotency key as headers. For the body we'll set a mustache template, where PCI Vault will populate the values from the vault before sending the request to Adyen. Note that one can construct the body template string with fields already populated or like in this case, set an extra_data object whose fields will be merged with the stored data before being populated in the mustache template. Using extra_data is often simpler and cleaner than string concatenation.

The parsed JSON for the body field looks like:

{
  "amount": {
    "currency": "{{currency}}",
    "value": {{amount}}
  },
  "reference": "{{reference}}",
  "paymentMethod": {
    "type": "scheme",
    "number": "{{card_number}}",
    "expiryMonth": "{{expiry_month}}",
    "expiryYear": "{{expiry_year}}",
    "holderName": "{{card_holder}}",
    "cvc": "{{cvv}}"
  },
  "returnUrl": "{{return_url}}",
  "merchantAccount": "{{merchant_account}}"
}

One optional parameter that is set in this example is "synchronous": true. This will tell PCI Vault to wait for the Adyen response to be returned and will send the result back to us when the request completes.

Step 2: Handle the response from Adyen

The response from Adyen will be wrapped in a JSON object like this:

{
  "id": "SLHpcudvjdUCokB2UCkR4n",
  "status": "success",
  "type": "post",
  "use_static_ip": false,
  "synchronous": true,
  "request": {
    "method": "POST",
    "url": "https://yoursubdomain.adyen.com/v71/payments",
    "headers": [
      {
        "content-type": "application/json"
      },
      {
        "X-API-Key": "{{api_key}}"
      },
      {
        "Idempotency-Key": "{{idempotency_key}}"
      }
    ],
    "body": "...",
    "extra_data": {
      "api_key": "your-adyen-api-key",
      "idempotency_key": "uuid-generated-for-request",
      "currency": "USD",
      "amount": 1000,
      "reference": "youruniqueref",
      "return_url": "https://your-company.example.com/...",
      "merchant_account": "yourmerchantaccount",
    }
  },
  "webhook": {
    "status": "pending"
  },
  "max_attempts": 1,
  "attempts": 0,
  "debug_mode": false,
  "received": "2025-11-12T14:06:06.621177+00:00",
  "result": {
    "headers": [
      {
        "Content-Type": "application/json"
      },
      ...
    ],
    "body": "{\"additionalData\": {\"cvcResult\": \"1 Matches\",\"authCode\": \"044925\",\"avsResult\": \"4 AVS not supported for this card type\",\"avsResultRaw\": \"4\",\"cvcResultRaw\": \"M\",\"refusalReasonRaw\": \"AUTHORISED\",\"acquirerCode\": \"TestPmmAcquirer\",\"acquirerReference\": \"8PQMP9VEP3H\"},\"pspReference\": \"993617895204576J\",\"resultCode\": \"Authorised\",\"merchantReference\": \"string\"}",
    "status_code": 200
  }
}

The response from Adyen is in the result field. The body is returned as a JSON string, which can be parsed and handled as needed.