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

# Store Paycard (Card Migration)

> Store card details in PCI Booking when migrating from local storage. The card data is sent in XML format.

<Card title="Card Migration Guide" icon="book" href="/capture-cards/store-card-migration">
  Migrate existing card data into PCI Booking tokens
</Card>

Use this endpoint to migrate card data you currently store on your own systems into PCI Booking tokens. Send the full card details in XML format, and PCI Booking returns a token URI you can use for all future operations. This is typically a one-time bulk migration step when onboarding with PCI Booking.

<Warning>
  This endpoint accepts card details in **XML format only**. Set `Content-Type: text/xml`.
</Warning>

## Error Responses

| Code  | HTTP Status | Condition                                                                                 |
| ----- | ----------- | ----------------------------------------------------------------------------------------- |
| -123  | 400         | Request body is not valid XML or is null                                                  |
| -123  | 400         | XML fails schema validation                                                               |
| -160  | 404         | Submitted data is PaymentInfo instead of BankCard                                         |
| -179  | 400         | Card validation failed (Luhn check, expiration, or CVV). Returns `errorList` with details |
| -125  | 400         | Card storage failed due to invalid data                                                   |
| -150  | 500         | Card storage failed due to a system error                                                 |
| -1003 | 401         | Missing `CanTokenize` permission                                                          |

## Parameter Constraints

| Parameter                | Type    | Required | Constraints                                                                     |
| ------------------------ | ------- | -------- | ------------------------------------------------------------------------------- |
| validateLuhn             | boolean | No       | Defaults to `true`. Validates card number with Luhn algorithm                   |
| validateExpiration       | boolean | No       | Defaults to `false`. When `true`, rejects expired cards                         |
| saveCVV                  | boolean | No       | Defaults to `false`. Requires CVV retention policy to be set after storage      |
| eliminateCardDuplication | boolean | No       | Defaults to `false`. When `true`, returns existing token if card already stored |
| Content-Type             | string  | Yes      | Must be `text/xml`                                                              |
| Auth                     | string  | Yes      | ApiKey, AccessToken, or SessionToken                                            |

The request body must contain a `BankCardDetails` XML document. See [Card Data XML Structure](/reference/card-data-xml-structure) for the full field reference.

```xml theme={null}
<BankCardDetails xmlns="http://www.pcibooking.net/reservation" schemaVersion="1.0">
  <BankCard>
    <Type>Visa</Type>
    <Number>4918914107195005</Number>
    <NameOnCard>Juan Dela Cruz</NameOnCard>
    <ExpirationDate>
      <Month>07</Month>
      <Year>2020</Year>
    </ExpirationDate>
    <IssueNumber>2</IssueNumber>
    <OwnerID>123456789</OwnerID>
    <CVV>123</CVV>
  </BankCard>
</BankCardDetails>
```

On success, a card token is created and the token URI is returned in the `Location` response header. The response body contains the submitted card details with sensitive data masked.

## Parameters

### Headers

<ParamField header="Authorization" type="string" required>
  Your API key prefixed with `APIKEY`. Example: `APIKEY your-api-key`. For server-to-server calls.
</ParamField>

<Accordion title="Alternative: Browser-Side Authentication">
  This endpoint also accepts token-based authentication via query parameters:

  | Method                         | Details                                                                                                             |
  | ------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
  | **Access Token** (recommended) | `accessToken` query param. [How to generate](/getting-started/authentication#access-token).                         |
  | **Session Token**              | `sessionToken` query param. [How to generate](/api-reference/general/start-temporary-session). Valid for 5 minutes. |

  If multiple methods are provided, precedence: Session Token > Access Token > API Key.
</Accordion>

<ParamField header="Content-Type" type="string" required default="text/xml">
  Must be `text/xml`. This endpoint accepts card details in XML format only.
</ParamField>

### Query String

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

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

<ParamField query="allowedUserId" type="string">
  User ID of the PCI Booking customer (booker ID) to associate the token with. The customer must share their PCI Booking user ID with you.
</ParamField>

<ParamField query="saveCVV" type="boolean" default="false">
  Whether to save the CVV in the database. **true** - save the CVV. **false** - do not save the CVV.
</ParamField>

<ParamField query="ValidateExpiration" type="boolean" default="false">
  Whether to check if the expiration date is valid. `True` validates the expiration date and tokenization will fail if expired. `False` accepts the date as is, even if in the past.
</ParamField>

<ParamField query="validateLuhn" type="boolean" default="true">
  Whether to check if the card number passes the Luhn algorithm. `True` validates using Luhn and tokenization will fail if the number does not pass. `False` accepts the number as is.
</ParamField>

### Request Body

<ParamField body="BankCardDetails" type="object">
  The BankCardDetails object. See the XML structure and example above.
</ParamField>

## Request Example

Store a Visa card and associate it with a reference and property:

<Tabs>
  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://service.pcibooking.net/api/payments/paycard?ref=booking-12345&merchant=hotel-sunrise&saveCVV=true" \
      -H "Authorization: APIKEY your-api-key" \
      -H "Content-Type: text/xml" \
      -d '<?xml version="1.0" encoding="utf-8"?>
    <BankCardDetails xmlns="http://www.pcibooking.net/reservation" schemaVersion="1.0">
      <BankCard>
        <Type>Visa</Type>
        <Number>4111111111111111</Number>
        <NameOnCard>Jane Smith</NameOnCard>
        <ExpirationDate>
          <Month>12</Month>
          <Year>2028</Year>
        </ExpirationDate>
        <CVV>123</CVV>
      </BankCard>
    </BankCardDetails>'
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    const xmlBody = `<?xml version="1.0" encoding="utf-8"?>
    <BankCardDetails xmlns="http://www.pcibooking.net/reservation" schemaVersion="1.0">
      <BankCard>
        <Type>Visa</Type>
        <Number>4111111111111111</Number>
        <NameOnCard>Jane Smith</NameOnCard>
        <ExpirationDate>
          <Month>12</Month>
          <Year>2028</Year>
        </ExpirationDate>
        <CVV>123</CVV>
      </BankCard>
    </BankCardDetails>`;

    const params = new URLSearchParams({
      ref: "booking-12345",
      merchant: "hotel-sunrise",
      saveCVV: "true"
    });

    const response = await fetch(
      `https://service.pcibooking.net/api/payments/paycard?${params}`,
      {
        method: "POST",
        headers: {
          "Authorization": "APIKEY your-api-key",
          "Content-Type": "text/xml"
        },
        body: xmlBody
      }
    );

    const tokenUri = response.headers.get("Location");
    console.log("Token URI:", tokenUri);

    const data = await response.json();
    console.log(data);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    xml_body = """<?xml version="1.0" encoding="utf-8"?>
    <BankCardDetails xmlns="http://www.pcibooking.net/reservation" schemaVersion="1.0">
      <BankCard>
        <Type>Visa</Type>
        <Number>4111111111111111</Number>
        <NameOnCard>Jane Smith</NameOnCard>
        <ExpirationDate>
          <Month>12</Month>
          <Year>2028</Year>
        </ExpirationDate>
        <CVV>123</CVV>
      </BankCard>
    </BankCardDetails>"""

    response = requests.post(
        "https://service.pcibooking.net/api/payments/paycard",
        params={
            "ref": "booking-12345",
            "merchant": "hotel-sunrise",
            "saveCVV": "true"
        },
        headers={
            "Authorization": "APIKEY your-api-key",
            "Content-Type": "text/xml"
        },
        data=xml_body
    )

    token_uri = response.headers.get("Location")
    print("Token URI:", token_uri)
    print(response.json())
    ```
  </Tab>
</Tabs>

On success, the token URI is returned in the `Location` response header (e.g. `Location: https://service.pcibooking.net/api/payments/paycard/tok_abc123`).

## Response

**201** - Card stored. A `Location` header is returned with the token URI. The response body contains the card details with sensitive data masked.

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

<ResponseExample>
  ```json 201 theme={null}
  {
      "Type": "Visa",
      "Number": "491891******5005",
      "NameOnCard": "Juan Dela Cruz",
      "ExpirationDate": {
          "Month": "07",
          "Year": "2020"
      },
      "IssueNumber": "2"
  }
  ```

  ```json Unauthorized (bad credentials) 401 theme={null}
  {
      "code": -1003,
      "message": "Not authorized to access this resource",
      "moreInfo": "Bad or missing authorization data, expected APIKEY or Temp Session or One-Time Accesss Token",
      "errorList": null
  }
  ```

  ```json Unauthorized (no access) 401 theme={null}
  {
      "code": -1003,
      "message": "Not authorized to access this resource",
      "moreInfo": "Merchant or Owner are not associated with bank card [{{Token}] userID: SoBookIt",
      "errorList": null
  }
  ```
</ResponseExample>
