Proxy payment instruments
If you have read our Vault Proxy page, you already know that Payrails offers two ways to use proxy, by pre-configured connections to work with any third party and for any data, and by an API call without any prior configuration to work with payment providers during payment authorizations.
If you haven't read, we recommend reading it first to see which proxy is better for your use case and goals. This page describes the second alternative in detail, which is to proxy payment instruments to payment providers. If you are looking for how to proxy to any third party, you can switch to this guide to read about configurable proxies.
Payrails Vault is a core module of our Payment Orchestration system and works with our Payments and Ledger services to help you accept and optimize your payments smoothly.
However, every service at Payrails can be used standalone to adapt to our merchant's use cases. This guide explains how to use the instruments and tokens stored in our Vault with your Payment service so that your infrastructure is never exposed to sensitive data.
We call this feature Vault Proxy because our Payrails Vault stands between your backend and the PSP that will receive the sensitive data. When receiving your request, we replace specific placeholders in the request body with the sensitive information stored in our vault before sending it to the provider. When they respond, we remove the sensitive information and send the response back to you.
This feature is usually used to execute payment authorization requests. Still, depending on the external provider, the card may need to be received in a separate endpoint. For example, Mangopay requires you to store the card and execute the payment with their card identifier, so you can use our Proxy only on the first call.
The following is a high-level sequence diagram of the interaction between the services.
Obtaining provider identifier
Before being able to use the /proxy
endpoint, you have to inform Payrails about the provider with whom you want to exchange information.
We must start by checking their PCI certification to receive full PANs securely. Payrails must check the provider before sending card data to ensure everyone's security and compliance. After the security checks, we're ready to configure the provider on our system. For example, we need to know which endpoint in the provider itself we need to call on your behalf (providerUrl
) and the credentials we need to use for authentication (providerConfig
).
After Payrails is done checking their compliance, we will provide you with a providerId
that identifies the Provider in our system, and a providerConfigId
, which contains your specific credentials for calling them. You will need both to execute proxy requests.
Executing proxy requests
After the provider is created and configured, you can use the Vault Proxy endpoint to send your instruments to the provider.
The following are some examples of some well-known providers and how you should map the card data using our instruments.
{
"paymentInstrumentId": "eeaac45c-f032-49bc-a8c5-ec99d79b74e2",
"providerConfigId": "d9699acd-9361-4e11-8d06-b30f41fc6210",
"url" : "https://checkout-test.adyen.com/v69/payments",
"headers": {
"x-API-key": "YOUR_API_KEY"
},
"body": {
"amount": {
"currency": "USD",
"value": 1000
},
"reference": "your-order-number",
"paymentMethod": {
"type": "scheme",
"number": "{{cardNumber}}",
"expiryMonth": "{{cardExpiryMonth}}",
"expiryYear": "{{cardExpiryYear}}",
"cvc": "{{cardSecurityCode}}",
"holderName": "{{cardHolderName}}"
},
"returnUrl": "https://your-company.com/...",
"merchantAccount": "YOUR_MERCHANT_ACCOUNT"
}
}
{
"paymentInstrumentId": "eeaac45c-f032-49bc-a8c5-ec99d79b74e2",
"providerConfigId": "d9699acd-9361-4e11-8d06-b30f41fc6210",
"url" : "https://api.sandbox.checkout.com/payments",
"headers": {
"x-API-key": "YOUR_API_KEY"
},
"body": {
"amount": 1000,
"currency": "USD",
"reference": "some_reference",
"source": {
"type": "card",
"number": "{{cardNumber}}",
"expiry_month": "{{cardExpiryMonth}}",
"expiry_year": "{{cardExpiryYear}}",
"cvv": "{{cardSecurityCode}}",
"name": "{{cardHolderName}}"
},
"payment_type": "Regular",
"authorization_type": "Final",
"capture": true,
"processing_channel_id": "pc_xxxxxxxxxxx",
"risk": {
"enabled": false
},
"merchant_initiated": true
}
}
{
"paymentInstrumentId": "eeaac45c-f032-49bc-a8c5-ec99d79b74e2",
"providerConfigId": "d9699acd-9361-4e11-8d06-b30f41fc6210",
"url" : "https://pci.mangopay.com/pci/v2.01/YOUR_CLIENT_ID/payins/card/direct/raw",
"headers": {},
"body": {
"Tag": "Custom meta",
"AuthorId": "205062273",
"DebitedFunds": {
"Currency": "EUR",
"Amount": 5000
},
"SecureModeReturnURL": "https://mangopay.com/docs/please-ignore",
"Culture": "EN",
"BrowserInfo": {
"AcceptHeader": "text/html, application/xhtml+xml, application/xml;q=0.9, /;q=0.8",
"JavaEnabled": true,
"Language": "en-EN",
"ColorDepth": 4,
"ScreenHeight": 1800,
"ScreenWidth": 400,
"TimeZoneOffset": 60,
"UserAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
"JavascriptEnabled": true
},
"IpAddress": "b02a:7967:ecc2:d827:cdd0:67d3:6d2f:4fef",
"Billing": {
"FirstName": "Alex",
"LastName": "Smith",
"Address": {
"AddressLine1": "100 rue Rivoli",
"AddressLine2": null,
"City": "Paris",
"Region": "Ile-de-France",
"PostalCode": "75001",
"Country": "FR"
}
},
"Shipping": {
"FirstName": "Alex",
"LastName": "Smith",
"Address": {
"AddressLine1": "100 rue Rivoli",
"AddressLine2": null,
"City": "Paris",
"Region": "Ile-de-France",
"PostalCode": "75001",
"Country": "FR"
}
},
"Card":{
"Number":"{{cardNumber}}",
"ExpirationDate":"{{cardExpiryMonth}}{{cardExpiryYear2Digits}}",
"CVX":"{{cardSecurityCode}}"
},
"CardType":"CB_VISA_MASTERCARD"
}
}
We currently support both JSON and XML. If you need additional content types, you can contact our team to enable more. If the destination provider requires a JSON body for the API endpoint to which you wish to proxy data, use a request header of 'Content-Type': text/json. Similarly, if you need to send XML to the destination provider, use the request header as 'Content-Type': text/xml.
curl --location 'http://127.0.0.1/payment/providers/97d028f0-24bd-4705-924f-6c956b9a7a1c/proxy' \
--header 'x-idempotency-key: 75b4db76-bd2d-429c-b757-ebff73f72d56' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer ....' \
--header 'Content-Type: text/xml' \
--header 'Accept: application/json' \
--data '{
"paymentInstrumentId": "0fb576ef-9f5e-4480-9254-94b6d03b2c9c",
"providerConfigId": "d9699acd-9361-4e11-8d06-b30f41fc6210",
"url": "https://checkout-test.adyen.com/v69/payments",
"headers": {
"Accept": "application/xml",
"Content-Type": "application/xml"
},
"body": {
"paymentMethod": {
"number": "{{cardNumber}}",
"expiryMonth": "{{cardExpiryMonth}}",
"expiryYear": "{{cardExpiryYear}}",
"cvc": "{{cardSecurityCode}}",
"holderName": "{{cardHolderName}}"}'
},
curl --location 'http://127.0.0.1/payment/providers/97d028f0-24bd-4705-924f-6c956b9a7a1c/proxy' \
--header 'x-idempotency-key: 75b4db76-bd2d-429c-b757-ebff73f72d56' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer ....' \
--header 'Content-Type: text/xml' \
--header 'Accept: application/json' \
--data '{
"paymentInstrumentId": "0fb576ef-9f5e-4480-9254-94b6d03b2c9c",
"providerConfigId": "d9699acd-9361-4e11-8d06-b30f41fc6210",
"url": "https://checkout-test.adyen.com/v69/payments",
"headers": {
"Accept": "application/xml",
"Content-Type": "application/xml"
},
"body": "<request><card_number><{{cardNumber}}</card_number><exp_month>{{cardExpiryMonth}}</pg_exp_month><exp_year>{{cardExpiryYear}}</exp_year></request>..."
The keys in the
headers
object must be case insensitive unique.
Dynamic variable substitution during proxying
In this type of proxy, you don't need to pre-configure a connection to map the sensitive fields up front, but you just need to put {{key}}
in the place of the sensitive fields inside the proxy body, while sending the proxy request to Payrails. The fields with the format {{key}}
will be replaced by actual card data by Payrails Vault, the fields that do not have a key will be sent "as is" to the destination payment provider.
You can use the below {{key}}
s for cards and network tokens, when sending payment authorization requests to payment providers.
Cards
- For card number, use
{{cardNumber}}
- For cardholder name, use
{{cardHolderName}}
- For card security code (or CVV, CVC, etc), use
{{cardSecurityCode}}
- For card expiry month, use
{{cardExpiryMonth}}
or{{MM}}
- For card expiry year, if:
- 4-digit card expiry year, use
{{cardExpiryYear}}
or{{YYYY}}
- 2-digit card expiry year, use
{{cardExpiryYear2Digits}}
or{{YY}}
.
- 4-digit card expiry year, use
Network tokens
- For network token number, use
{{networkTokenNumber}}
- For cryptogram, use
{{networkTokenCryptogram}}
- Expiry month of the network token, use
{{networkTokenExpiryMonth}}
- For expiry year of the network token, if:
- 4-digit expiry year of the network token, use
{{networkTokenExpiryYear}}
- 2-digit expiry year of the network token, use
{{networkTokenExpiryYear2Digits}}
.
- 4-digit expiry year of the network token, use
If you would like to send any other field that does not exist in the above list, please contact our team to support you to enable custom records for your environment.
With great power comes great responsibility
This feature gives you absolute control on what is sent to the Provider. Make sure you sanitize and validate your requests to avoid risk of exposing sensitive information in a field that is not protected.
For example, if you put the variable
{{cardNumber}}
in a field that the Provider shows in their Portal (like an order description, cart item name, etc.), then you would be exposing the customer's card number to your support team.
Override card security code
According to PCI DSS rules, we can only retain the card security code during a payment authorization. This means that when including the {{cardSecurityCode}}
in your request body, you must ensure that the value is still available in our Vault.
If the card was initially stored with the correct authorization flags, you should not need the security code to authorize a payment. However, we provide this option in case you have one of the following use cases:
- you want to ask for the security code to prevent fraud due to account takeover attacks
- a Provider requires you to include this field even if the card is already stored
Our Vault Proxy endpoint has an optional parameter called encryptedSecurityCode
that allows you to override the stored value (if any) of the {{cardSecurityCode}}
variable in the body
you intend to send to your Provider.
To obtain the value of the encryptedSecurityCode
, you can use our client-side SDK function called encryptCardData
. Check the documentation for it here.
Updated 7 days ago