# Reusing a Saved Card with Payment Tokens

Capture the reusable payment token returned when a card is saved, then charge the stored card again without handling card data.

**Category:** Integration

**Last reviewed:** 31 July 2026

# Reusing a Saved Card with Payment Tokens

When a shopper saves their card during a payment (for example, a Hosted Payment Page or Virtual Terminal sale with save-card enabled), WinkPG vaults the card and returns a reusable **payment token**. You can charge that token later without ever collecting or storing the card number yourself, which keeps the reorder and card-on-file flows out of your PCI scope.

The token you use for this is the **public reference**: a single opaque handle that is both what you receive and what you charge with.

## Where the token appears

The public reference is surfaced in two places whenever a transaction tokenizes a card:

- **The synchronous transaction response** at `responseData.tokenResult.publicReference`.
- **The transaction-completed webhook** at `data.responseData.tokenResult.publicReference` (see the Webhook Integration guide for the envelope and signature scheme).

Both carry the same value. It is present only when the transaction actually saved a card; on a non-tokenizing transaction the `tokenResult` object is omitted.

```json
{
  "responseData": {
    "resultCode": 1,
    "resultMessage": "Approved",
    "tokenResult": {
      "publicReference": "pt_9fKq2ZmB7tLxW3aH5nR8cV1s"
    }
  }
}
```

## What the token is

- **Opaque and self-describing.** It always begins with the `pt_` prefix followed by a URL-safe random string. Treat the whole value as an opaque handle: store it and send it back verbatim. Do not parse, split, or infer anything from its contents.
- **Not a card number and not an internal id.** The public reference is deliberately not shaped like a card number, and it is not the gateway's internal vault identifier. It is the only token identifier WinkPG emits to you; the internal identifier never leaves the gateway.
- **Stable.** The same saved card keeps the same public reference, so you can store it against your customer record and reuse it across orders.

## Charging with the token

To charge a saved card, send the public reference in the payment token field of a sale or authorization request instead of raw card data:

```json
{
  "tokenData": {
    "token": "pt_9fKq2ZmB7tLxW3aH5nR8cV1s"
  },
  "invoiceData": {
    "amounts": { "base": 49.00 }
  }
}
```

WinkPG resolves the token to the stored card, runs the charge, and returns the usual transaction response.

**Send the amount as `base`, not `total`.** `total` is calculated by WinkPG as `base + tip + tax + shipping + convenience`. It is returned on the response; it is not a way to set the amount charged, and a `total` that disagrees with the components you sent does not change what is charged. If you do send `total`, it is treated as an integrity check on those components. Once checksum enforcement is switched on for your environment, a disagreement is rejected with an error naming both values; until then it is recorded for review and the charge proceeds for the component sum. Either way, send a `total` only if you want that check, and always read the `total` on the response as the authoritative amount charged: fees the gateway adds after accepting your request (a surcharge, or a convenience fee it computes) are outside the check and appear only there.

- **Cardholder-initiated (CIT) charges** (the shopper is present and choosing to pay with the saved card) work directly with the token.
- **Merchant-initiated (MIT) charges** (recurring billing, delayed captures, account top-ups where the shopper is not present) additionally require captured stored-credential consent. A merchant-initiated charge without it is declined with `stored_credential_consent_required`. Capture consent at the time the card is first saved so later unattended charges succeed.

### Charging with a companion `cardData`

A token charge does not need a `cardData` object at all: the token is the tender, and WinkPG resolves the card number and expiration from the vault. You may still send one to carry **address-verification fields**, which is the only reason to include it:

```json
{
  "tokenData": {
    "token": "pt_9fKq2ZmB7tLxW3aH5nR8cV1s"
  },
  "cardData": {
    "billingAddress": {
      "address1": "1 Market Street",
      "postalCode": "94105"
    }
  },
  "invoiceData": {
    "amounts": { "base": 49.00 }
  }
}
```

Two things to know about that companion object:

- **Send AVS fields only.** A `cardData` on a token charge should carry the billing address, and optionally the cardholder name, email, or phone. Do not put a card number, track data, or a reader payload in it: the token already identifies the card, and a request that supplies both a token and raw card data is rejected as ambiguous about which one to charge.
- **You do not need to set `isStoredPayment`.** WinkPG stamps that flag itself while resolving the token. It is an output of token resolution, not something the caller declares, so leave it out and let the gateway set it.

Do not declare a card-present `entryMode` (a swipe, chip, or contactless value) on a companion object. Those values assert that a physical card was read on a device, so the request is then held to carrying the reader payload that read produced. Omit `entryMode` on a token charge.

## Treat the token as a credential

Making the public reference chargeable means anyone who holds it can attempt a charge, subject to two protections that always apply: the token is scoped to your merchant account, and merchant-initiated reuse still requires stored-credential consent. The token's shape is not a secret in itself, so:

- Keep the token server-side. Do not embed it in browser code, query strings, or client-visible URLs.
- Store it with the same care you give any reusable credential, and only alongside the customer it belongs to.
- Log it sparingly. It is not card data, but it is a live charging handle.

## What not to rely on

Charge only with the `publicReference` value. Do not attempt to charge using identifiers scraped from a transaction's history or from internal fields: those are not resolvable for charging and are not a supported integration surface. The public reference in the response and webhook is the one supported reusable handle.

## See also

- [All documentation](https://docs.winkpg.io/llms.txt): the machine-readable index of every public page on this site.
