> ## 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.

# Tokenize on Response Using Preset Profiles

> Send a request through a pre-configured PCI Booking profile to a third party. PCI Booking intercepts the response, tokenizes card data, and returns the sanitized response.

<Card title="Universal Tokenization Guide" icon="book" href="/capture-cards/universal-tokenization">
  Tokenize cards from any source using preset profiles
</Card>

PCI Booking forwards your request to the third party defined in the profile, tokenizes any card data found in the response, and returns the sanitized response with the following custom headers:

| Header                               | Description                                                                                                         |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `X-pciBooking-cardUri`               | Semicolon-separated list of token URIs for each card tokenized. The header name can be customized per profile.      |
| `X-pciBooking-Tokenization-Errors`   | Errors encountered during tokenization (e.g. invalid card number, missing fields). Present only if errors occurred. |
| `X-pciBooking-Tokenization-Warnings` | Warnings encountered during tokenization (e.g. expired card accepted). Present only if warnings occurred.           |

## Error Responses

| Code    | HTTP Status | Condition                                                                           |
| ------- | ----------- | ----------------------------------------------------------------------------------- |
| `-1003` | `401`       | Authorization token is missing or invalid (requires Access Token or Session Token). |
| `-1003` | `401`       | User does not have `CanTokenize` permission.                                        |
| `-125`  | `400`       | The specified profile name was not found.                                           |
| `-150`  | `500`       | Failed to retrieve the profile configuration (internal error).                      |

## Parameter Constraints

* **ProfileName**: Must match an existing profile name (see [Get Tokenization Profiles](/api-reference/tokenize-cards/get-tokenization-profiles)).
* **pathSegments**: Required if the profile's target URL has dynamic path segments. Provide key-value pairs in query string format.
* **eliminateCardDuplication**: When `true`, a `200` status indicates the card already existed; `201` means a new token was created.

## Parameters

### Authentication

<Warning>
  This is a browser-facing endpoint. Use one of the authentication methods below instead of the API key shown above.
</Warning>

<ParamField query="accessToken" type="string">
  Recommended. A long-lived token for browser-side calls. [How to generate](/getting-started/authentication#access-token).
</ParamField>

<ParamField query="sessionToken" type="string">
  Alternative. Valid for 5 minutes. [How to generate](/api-reference/general/start-temporary-session).
</ParamField>

If both are provided, the session token takes precedence.

### Path Parameters

<ParamField path="ProfileName" type="string" required>
  The name of the profile as returned from the [Get Tokenization Profiles](/api-reference/tokenize-cards/get-tokenization-profiles) method.
</ParamField>

### Query String

<ParamField query="pathSegments" type="string">
  Dynamic path segments to append to the profile's target URL. Some third-party endpoints include dynamic values in the URL path (e.g. `https://ws.mydomain.com/{customerName}`). The [Get Tokenization Profiles](/api-reference/tokenize-cards/get-tokenization-profiles) response lists the required path segments for each profile.
</ParamField>

<ParamField query="fwd" type="string">
  Query string parameters to append to the profile's target URL. Some third-party endpoints require additional parameters (e.g. `?param1=value1&param2=value2`). Provide the full query string as needed.
</ParamField>

<ParamField query="saveCVV" type="boolean" default="false">
  Whether to save the CVV in the database. `true`: save the CVV. `false`: discard the CVV.
</ParamField>

<ParamField query="ref" type="string">
  A reference value which can be used to query for this card token.
</ParamField>

<ParamField query="MerchantId" type="string">
  The user ID of the property to associate the token with. Found under "Property settings" in the user's site.
</ParamField>

<ParamField query="eliminateCardDuplication" type="boolean" default="false">
  Controls whether PCI Booking checks if the card already exists as a token in your account.

  * **`true`**: PCI Booking looks up the card in your stored tokens. If a match is found, the existing token URI is returned instead of creating a new one. The response status will be `200` instead of `201`.
  * **`false`** (default): A new token is always created, even if the same card was previously stored.
</ParamField>

### Request Body

<Note>
  The request body and headers are passed through to the third party as-is. Include any body content and headers that the third party requires.
</Note>

<RequestExample>
  ```javascript Node.js theme={null}
  const profileName = 'SiteMinder';
  const params = new URLSearchParams({
    pathSegments: 'SiteMinderCustID=CUST001',
    saveCVV: 'true',
    ref: 'booking-12345'
  });

  const response = await fetch(
    `https://service.pcibooking.net/api/booker/${profileName}/reservation?${params}`,
    {
      method: 'POST',
      headers: {
        'Authorization': 'APIKEY your-api-key',
        'Content-Type': 'application/xml'
      },
      body: '<ReservationRequest><HotelCode>HOTEL01</HotelCode></ReservationRequest>'
    }
  );

  const tokenUri = response.headers.get('X-pciBooking-cardUri');
  console.log('Token URI:', tokenUri);

  const data = await response.text();
  console.log('Sanitized response:', data);
  ```

  ```python Python theme={null}
  import requests

  profile_name = 'SiteMinder'

  response = requests.post(
      f'https://service.pcibooking.net/api/booker/{profile_name}/reservation',
      params={
          'pathSegments': 'SiteMinderCustID=CUST001',
          'saveCVV': 'true',
          'ref': 'booking-12345'
      },
      headers={
          'Authorization': 'APIKEY your-api-key',
          'Content-Type': 'application/xml'
      },
      data='<ReservationRequest><HotelCode>HOTEL01</HotelCode></ReservationRequest>'
  )

  token_uri = response.headers.get('X-pciBooking-cardUri')
  print('Token URI:', token_uri)
  print('Sanitized response:', response.text)
  ```
</RequestExample>

## Response

**200** - The card already exists in your account (when `eliminateCardDuplication` is `true`). The response body contains the third-party response with card details masked. The existing token URI is returned in the `X-pciBooking-cardUri` header.

**201** - A new card was tokenized. The response body contains the third-party response with card details masked. The new token URI is returned in the `X-pciBooking-cardUri` header.

<Info>
  Remember to set the [CVV Retention Policy](/capture-cards/cvv-retention-policy) on the token.
</Info>

<ResponseExample>
  ```text 201 theme={null}
  The third-party response body is returned with card details replaced by token placeholders.
  The X-pciBooking-cardUri header contains the new token URI.
  ```

  ```json Invalid profile 400 theme={null}
  {
      "code": -125,
      "message": "Bad input data",
      "moreInfo": "Couldn't fetch a valid pciShield profile:: wsc",
      "errorList": null
  }
  ```

  ```json Invalid target URI 400 theme={null}
  {
      "code": -125,
      "message": "Bad input data",
      "moreInfo": "Invalid target Uri::",
      "errorList": null
  }
  ```

  ```json 401 theme={null}
  {
      "code": -1003,
      "message": "Not authorized to access this resource",
      "moreInfo": "Bad or missing authorization data, expected Temp Session or One-Time Accesss Token",
      "errorList": null
  }
  ```
</ResponseExample>
