Skip to main content

XML Proxy Requests

Forward XML/SOAP requests to payment processors like Worldpay.

Request Format

For XML requests, pass metadata via headers:
POST /proxy/transaction
Content-Type: text/xml
X-Token: tok_a1b2c3d4e5f6
X-Proxy-URL: https://secure.worldpay.com/jsp/merchant/xml/paymentService.jsp
X-CVC-Session-ID: 550e8400-e29b-41d4-a716-446655440000
<?xml version="1.0" encoding="UTF-8"?>
<paymentService version="1.4" merchantCode="YOUR_MERCHANT">
  <submit>
    <order orderCode="order123">
      <amount value="1000" currencyCode="USD"/>
      <paymentDetails>
        <CARD-SSL>
          <cardNumber>${cardNumber}</cardNumber>
          <expiryDate>
            <date month="${expirationMonth}" year="${expirationYear}"/>
          </expiryDate>
          <cardHolderName>John Doe</cardHolderName>
          <cvc>${cvv}</cvc>
        </CARD-SSL>
      </paymentDetails>
    </order>
  </submit>
</paymentService>

Request Headers

HeaderRequiredDescription
Content-TypeYestext/xml or application/xml
X-TokenYesToken to use
X-Proxy-URLYesTarget endpoint
X-CVC-Session-IDNoCVC session for CVV
AuthorizationVariesIf PSP requires auth

Placeholders

Same placeholders work in XML:
<cardNumber>${cardNumber}</cardNumber>
<expiryMonth>${expirationMonth}</expiryMonth>
<expiryYear>${expirationYear}</expiryYear>
<cvv>${cvv}</cvv>

Examples

Worldpay

curl -X POST https://pci-vault-hrhwdgc4akhse3bs.eastus-01.azurewebsites.net/proxy/transaction \
  -H "Content-Type: text/xml" \
  -H "X-API-Key: YOUR_OZURA_API_KEY" \
  -H "X-Token: tok_a1b2c3d4e5f6" \
  -H "X-Proxy-URL: https://secure.worldpay.com/jsp/merchant/xml/paymentService.jsp" \
  -H "X-CVC-Session-ID: session_xyz" \
  -H "Authorization: Basic YOUR_WORLDPAY_CREDENTIALS" \
  -d '<?xml version="1.0" encoding="UTF-8"?>
<paymentService version="1.4" merchantCode="YOURMERCHANT">
  <submit>
    <order orderCode="ORDER123">
      <description>Test Order</description>
      <amount value="1000" currencyCode="USD" exponent="2"/>
      <paymentDetails>
        <CARD-SSL>
          <cardNumber>${cardNumber}</cardNumber>
          <expiryDate>
            <date month="${expirationMonth}" year="${expirationYear}"/>
          </expiryDate>
          <cardHolderName>John Doe</cardHolderName>
          <cvc>${cvv}</cvc>
        </CARD-SSL>
      </paymentDetails>
    </order>
  </submit>
</paymentService>'

Cybersource (SOAP)

curl -X POST https://pci-vault-hrhwdgc4akhse3bs.eastus-01.azurewebsites.net/proxy/transaction \
  -H "Content-Type: text/xml" \
  -H "X-API-Key: YOUR_OZURA_API_KEY" \
  -H "X-Token: tok_a1b2c3d4e5f6" \
  -H "X-Proxy-URL: https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor" \
  -H "X-CVC-Session-ID: session_xyz" \
  -d '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>YOUR_MERCHANT_ID</wsse:Username>
        <wsse:Password>YOUR_TRANSACTION_KEY</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <requestMessage xmlns="urn:schemas-cybersource-com:transaction-data-1.0">
      <merchantID>YOUR_MERCHANT_ID</merchantID>
      <card>
        <accountNumber>${cardNumber}</accountNumber>
        <expirationMonth>${expirationMonth}</expirationMonth>
        <expirationYear>${expirationYear}</expirationYear>
        <cvNumber>${cvv}</cvNumber>
      </card>
      <ccAuthService run="true"/>
      <purchaseTotals>
        <currency>USD</currency>
        <grandTotalAmount>10.00</grandTotalAmount>
      </purchaseTotals>
    </requestMessage>
  </soapenv:Body>
</soapenv:Envelope>'

Response

XML responses are returned directly:
{
  "success": true,
  "proxy_response": {
    "status_code": 200,
    "headers": {
      "content-type": "text/xml"
    },
    "body": "<?xml version=\"1.0\"?><paymentService>...</paymentService>"
  }
}

Parsing XML Response

const response = await fetch('/proxy/transaction', { ... });
const data = await response.json();

if (data.success && data.proxy_response.status_code === 200) {
  // Parse the XML body
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(data.proxy_response.body, "text/xml");

  // Extract values
  const status = xmlDoc.querySelector('lastEvent').textContent;
}

Error Handling

SOAP Faults

<soapenv:Fault>
  <faultcode>Client</faultcode>
  <faultstring>Invalid card number</faultstring>
</soapenv:Fault>

Connection Errors

{
  "success": false,
  "message": "Failed to proxy request",
  "error": {
    "code": "CONNECTION_FAILED",
    "details": "SSL handshake failed"
  }
}

XML Encoding

Special characters are preserved:
CharacterIn XML
<&lt;
>&gt;
&&amp;
"&quot;
'&apos;
Card numbers don’t contain these characters, but if your XML contains them elsewhere, ensure proper encoding.

Namespaces

Preserve XML namespaces in your request:
<soapenv:Envelope
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:pay="urn:payment-schema">
  ...
</soapenv:Envelope>

Best Practices

1. Validate XML Before Sending

Ensure your XML is well-formed:
function isValidXML(xmlString) {
  const parser = new DOMParser();
  const doc = parser.parseFromString(xmlString, 'text/xml');
  return !doc.querySelector('parsererror');
}

2. Use CDATA for Complex Values

<description><![CDATA[Special & Complex "Value"]]></description>

3. Match PSP’s Expected Format

Different PSPs have different XML schemas. Always refer to their documentation.

Next Steps