> ## Documentation Index
> Fetch the complete documentation index at: https://developers.pcibooking.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Content Filters

> Define XML, JSON, form-encoded, and query string content filters that tell PCI Booking where card data fields are in your messages

A content filter is an XML configuration within a [target profile](/account-setup/target-profiles) that tells PCI Booking exactly where card data fields are located in a message. Content filters are used for both **tokenization** (extracting card data) and **token replacement** (injecting card data). The field selectors are declared inside a `<content>` element for tokenization filters, and inside a `<replace>` element for token replacement filters.

## Writing Filters in the Portal

You do not have to write content filters by hand. The [PCI Booking portal](https://users.pcibooking.net) includes a dedicated filter editor: go to **PCI Shield Settings** > **PCI Shield Profile Settings** and click the edit (pencil) icon on a profile's **Tokenization** or **Retrieve cards** column.

The editor gives you:

* **Sample templates** - a dropdown loads a ready-made base filter for each combination of message format (XML or JSON) and direction (tokenization or token replacement). Pick the closest template and adjust the selectors to your message structure.
* **Intellisense** - as you type `<`, a space, or `=` (or press <kbd>Ctrl</kbd>+<kbd>Space</kbd>), the editor suggests the valid elements, attributes, and attribute values at that position: the `<transform>` root, `<content>`/`<replace>` children, every card field element, `format` values, and the full card type name list for type mapping.
* **Validation** - clicking **Apply XML** validates the filter on the server before saving. Any structural errors are listed in the editor so you can fix them immediately.

The sections below explain the filter syntax the editor produces.

<Tip>
  **You are not on your own.** At any point, contact [support@pcibooking.net](mailto:support@pcibooking.net) to:

  * **Validate your filter** - send your content filter together with a sample message and our team will confirm it is accurate before you go live.
  * **Have a filter built for you** - send a sample of the message you exchange with the third party and our team will create the content filter for you.
</Tip>

## Supported Message Formats

Content filters support four message formats. Set the `type` attribute on the `<transform>` element to match your message format.

| Format | Type Value | Selector Syntax | Description |
| - | - | - | - |
| **XML body** | `body` | XPath | XML or SOAP message bodies |
| **JSON body** | `body` | JSONPath | JSON message bodies |
| **Form-encoded body** | `body` | Field name | `application/x-www-form-urlencoded` data |
| **URL query string** | `querystring` | Parameter name | Card data in URL query parameters |

PCI Booking detects whether body content is XML, JSON, or form-encoded based on the content type header.

## Content Filter Structure

A content filter is an XML document whose root element is `<transform>` in the `http://www.pcibooking.net/pciShieldProfiles` namespace:

```xml theme={null}
<transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="body">
  <content selector="XPath or JSONPath to card block">
    <number selector="path/to/card/number" />
    <expYear selector="path/to/exp/year" />
    <expMonth selector="path/to/exp/month" />
    <securityCode selector="path/to/cvv" />
    <nameOnCard selector="path/to/name" />
    <type selector="path/to/card/type" />
  </content>
</transform>
```

<Warning>
  The root element must be `<transform>` with the `xmlns="http://www.pcibooking.net/pciShieldProfiles"` namespace declaration exactly as shown. Filters with a different root element or a missing namespace are rejected.
</Warning>

The `<content>` element's `selector` attribute points to the parent element containing card fields. Each child element then uses a relative selector to locate its specific field within that parent. For token replacement filters, use a `<replace>` element instead of `<content>` - the structure inside is the same.

## Format Examples

<Tabs>
  <Tab title="XML Body">
    For XML messages, use XPath expressions. Use `local-name()` to match elements regardless of XML namespace prefix.

    **Tokenization filter** (extracting card data):

    ```xml theme={null}
    <transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="body">
      <content selector="//*[local-name()='PaymentCard']">
        <number selector="*[local-name()='CardNumber']" />
        <expYear selector="*[local-name()='ExpireDate']/@Year" format="YYYY" />
        <expMonth selector="*[local-name()='ExpireDate']/@Month" format="MM" />
        <nameOnCard selector="*[local-name()='CardHolderName']" />
        <securityCode selector="*[local-name()='SeriesCode']/@SeriesCode" />
        <type selector="@CardCode" />
      </content>
    </transform>
    ```

    **Token replacement filter** (injecting card data) - note the `<replace>` element:

    ```xml theme={null}
    <transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="body">
      <replace selector="//*[local-name()='PaymentCard']">
        <number selector="*[local-name()='CardNumber']" />
        <expYear selector="*[local-name()='ExpireDate']/@Year" format="YYYY" />
        <expMonth selector="*[local-name()='ExpireDate']/@Month" format="MM" />
        <nameOnCard selector="*[local-name()='CardHolderName']" />
        <securityCode selector="*[local-name()='SeriesCode']/@SeriesCode" />
        <type selector="@CardCode">
          <Visa>VI</Visa>
          <MasterCard>MC</MasterCard>
          <AMEX>AX</AMEX>
          <DinersClub>DC</DinersClub>
          <JCB>JC</JCB>
        </type>
      </replace>
    </transform>
    ```
  </Tab>

  <Tab title="JSON Body">
    For JSON messages, use JSONPath expressions.

    ```xml theme={null}
    <transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="body">
      <content selector="$..BankCard">
        <number selector="CardNo" />
        <expYear selector="ExpirationYear" format="YYYY" />
        <expMonth selector="ExpirationMonth" format="MM" />
        <nameOnCard selector="CardHolder" />
        <securityCode selector="CVV" />
        <type selector="CardType" />
      </content>
    </transform>
    ```

    **Token replacement filter** (injecting card data into a JSON message) - note the `<replace>` element:

    ```xml theme={null}
    <transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="body">
      <replace selector="$..cardDetails">
        <number selector="number" />
        <expYear selector="expirationYear" format="YYYY" />
        <expMonth selector="expirationMonth" format="MM" />
        <nameOnCard selector="nameOnCard" />
        <securityCode selector="cvv" />
      </replace>
    </transform>
    ```

    The `selector` on `<replace>` locates the object that holds the card; each child selector is relative to it. Omit any child the target does not need.

    <Info>
      When working with JSON, you can use the `tryJsonNumber` attribute on numeric fields (`number`, `expYear`, `expMonth`, `issueNumber`, `type`) to output values as JSON numbers instead of strings.
    </Info>
  </Tab>

  <Tab title="Form-Encoded">
    For `application/x-www-form-urlencoded` data, selectors are the field names directly.

    ```xml theme={null}
    <transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="body">
      <content>
        <number selector="ccNumber" />
        <expYear selector="ccExpYear" format="YY" />
        <expMonth selector="ccExpMonth" format="M" />
        <nameOnCard selector="ccName" />
        <securityCode selector="ccCVV" />
      </content>
    </transform>
    ```
  </Tab>

  <Tab title="Query String">
    For card data passed as URL query parameters, set `type="querystring"`.

    ```xml theme={null}
    <transform xmlns="http://www.pcibooking.net/pciShieldProfiles" type="querystring">
      <content>
        <number selector="cc" />
        <expYear selector="exp_year" format="YYYY" />
        <expMonth selector="exp_month" format="MM" />
        <securityCode selector="cvv" />
      </content>
    </transform>
    ```
  </Tab>
</Tabs>

## Card Data Fields

Each `<content>` element can map the following card fields:

| Element | Description | Attributes |
| - | - | - |
| `<number>` | Full card number (PAN) | `selector`, `substring`, `dataSubstring`, `rename` |
| `<expYear>` | Expiration year | `selector`, `format` (`YYYY` or `YY`), `substring`, `rename` |
| `<expMonth>` | Expiration month | `selector`, `format` (`MM` or `M`), `substring`, `rename` |
| `<securityCode>` | CVV / CVC / CID | `selector`, `rename` |
| `<nameOnCard>` | Cardholder name | `selector`, `rename` |
| `<type>` | Card brand (Visa, MasterCard, etc.) | `selector`, `rename`, child mapping elements (see [Card Type Mapping](#card-type-mapping)) |
| `<issueNumber>` | Card issue number | `selector`, `rename` |

### Format Attributes

The `format` attribute controls how date fields are read and written:

* **`expYear`**: `YYYY` (default, four digits) or `YY` (two digits)
* **`expMonth`**: `MM` (two digits with leading zero) or `M` (default, no leading zero)

### Substring Extraction

When a third party combines multiple values into a single field, use substring extraction to isolate the part you need.

* **`substring`** - extracts a portion of the value when **reading** from the message (tokenization). Format: `"startPosition"` or `"startPosition,length"` (zero-based).
* **`dataSubstring`** - extracts a portion of the replacement data when **writing** to the message (token replacement). Same format as `substring`.

Example: expiration date sent as `0125` (MMYY) in a single field:

```xml theme={null}
<expMonth selector="expDate" substring="0,2" format="MM" />
<expYear selector="expDate" substring="2,2" format="YY" />
```

### Renaming a Field

Whenever PCI Booking writes a value into the message, the field keeps its original name by default. If the system receiving the message expects that value under a different name, add the `rename` attribute to that field:

```xml theme={null}
<number selector="@CardNumber" rename="Mask" />
```

A card sent as `<PaymentCard CardCode="MC" CardNumber="5454545454545454" ExpireDate="1228" />` is returned as `<PaymentCard CardCode="MC" ExpireDate="1228" Mask="545454******5454" />`.

Renaming changes only the message PCI Booking produces. Your original message is unchanged, and the way the field is found is unchanged, so `selector` still refers to the field name as it arrives.

`rename` works in both directions and in every supported message format, but the fields it can affect differ, because a field is only renamed where a value is written:

| Filter | Fields that can be renamed |
| - | - |
| Tokenization filter (`<content>`) | The fields PCI Booking masks: the card number, the security code and the cardholder name. Expiry and card type are passed through untouched, so a `rename` on them has no effect. |
| Retrieve cards filter (`<replace>`) | Every field PCI Booking injects except the expiry fields and the 3DS fields: card number, card type, security code, cardholder name and issue number. |

The renamed field keeps its value, but not necessarily its position: a renamed XML attribute moves to the end of the attribute list, and a renamed JSON property moves to the end of its object. Test this if the receiving system is sensitive to field order.

A renamed XML element keeps its position, but it is written without a namespace. In a message that uses a default namespace, it gets an `xmlns=""` declaration. Renaming an attribute avoids this.

A rename is skipped, and the field keeps its original name, when:

* a field with the new name already exists alongside it, or
* the new name is not valid for the message format. XML names must begin with a letter or an underscore, may contain only letters, digits, hyphens, underscores and periods, and may not begin with "xml". JSON property names and query string parameter names must not be empty.

During tokenization a skipped rename is reported as a warning, not an error, and the operation still succeeds.

<Tip>
  Avoid the characters `.`, `[`, `]` and `$` in a JSON field name. They are accepted, but they can interfere with the selectors used elsewhere in the same filter.
</Tip>

### Card Type Mapping

When a third party uses different card type codes than PCI Booking, add mapping entries as child elements of the `<type>` field. Each entry's **element name** is PCI Booking's card type name, and its **content** is the third party's code.

```xml theme={null}
<type selector="@CardCode">
  <Visa>VI</Visa>
  <MasterCard>MC</MasterCard>
  <AMEX>AX</AMEX>
  <DinersClub>DC</DinersClub>
  <Dankort>DN</Dankort>
  <JCB>JC</JCB>
  <UnionPay>UP</UnionPay>
</type>
```

See [Supported Card Types](/reference/card-types) for the full list of PCI Booking card type names.

## 3D Secure Fields

Content filters can also map 3DS authentication data alongside card fields. Add these inside a `<threeDs>` wrapper element, which sits as a sibling of the card field elements inside `<content>`:

| Element | Description |
| - | - |
| `<auth>` | Authentication value (CAVV or AAV) |
| `<eci>` | Electronic Commerce Indicator |
| `<xid>` | 3DS v1 transaction identifier |
| `<acs>` | ACS Transaction ID (3DS v2) |
| `<version>` | 3DS protocol version |
| `<merchantName>` | Merchant name used in the 3DS challenge |
| `<sli>` | Security Level Indicator (MasterCard-specific) |

Example with 3DS fields:

```xml theme={null}
<content selector="//*[local-name()='PaymentCard']">
  <number selector="*[local-name()='CardNumber']" />
  <expYear selector="*[local-name()='ExpireDate']/@Year" />
  <expMonth selector="*[local-name()='ExpireDate']/@Month" />
  <threeDs>
    <auth selector="*[local-name()='ThreeDSecure']/*[local-name()='AuthValue']" />
    <eci selector="*[local-name()='ThreeDSecure']/*[local-name()='ECI']" />
    <xid selector="*[local-name()='ThreeDSecure']/*[local-name()='XID']" />
  </threeDs>
</content>
```

<Warning>
  The 3DS selector elements are only read from inside the `<threeDs>` wrapper. Placed directly inside `<content>`, they are ignored.
</Warning>

## Multiple Cards in One Message

If a message contains multiple cards (e.g., a batch of reservations), add a `reservationSelector` attribute to the `<content>` element. This XPath expression identifies each repeating card block, and PCI Booking processes each one independently.

```xml theme={null}
<content selector="//*[local-name()='PaymentCard']"
         reservationSelector="//*[local-name()='Reservation']">
  <number selector="*[local-name()='CardNumber']" />
  <!-- other fields -->
</content>
```

PCI Booking iterates over every element matching `reservationSelector` and applies the card field selectors within each.

When `reservationSelector` is present, the card `selector` is evaluated relative to each matching element rather than against the whole message. A selector that works without `reservationSelector` may find nothing once it is added, so write it relative to the reservation.

### customValue

The `customValue` attribute selects an additional value from each reservation, such as the property or hotel identifier, and is also evaluated relative to the reservation:

```xml theme={null}
<content selector=".//*[local-name()='PaymentCard']"
         reservationSelector="//*[local-name()='HotelReservation']"
         customValue=".//*[local-name()='BasicPropertyInfo']/@HotelCode">
  <number selector="@CardNumber" />
  <!-- other fields -->
</content>
```

<Note>
  Both `reservationSelector` and `customValue` are optional for standard tokenization, but they are mandatory where custom tokenization is in use, including for a message that carries a single reservation.
</Note>

## Next Steps

<CardGroup cols={2}>
  <Card title="Target Profiles" icon="book" href="/account-setup/target-profiles">
    Create and manage profiles that use content filters
  </Card>

  <Card title="Supported Card Types" icon="code" href="/reference/card-types">
    Full list of card type values for card type mapping
  </Card>

  <Card title="Tokenization on Response" icon="book" href="/capture-cards/tokenization-on-response">
    Tokenize card data from third-party responses
  </Card>

  <Card title="Token Replacement in Request" icon="book" href="/use-tokens/token-replacement-in-request">
    Replace tokens with real card data in outbound requests
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.