Reusing a stored payment method with payment tokens
Capture the reusable payment token returned when a card is saved, then charge the stored card again without handling card data, declaring whether the customer is present for each charge.
When a customer 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's 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's present only when the transaction actually saved a card; on a non-tokenizing transaction the tokenResult object is omitted.
{
"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 random string safe for use in a web address. Treat the whole value as an opaque handle: store it and send it back verbatim. Don't parse, split, or infer anything from its contents. - Not a card number and not an internal id. By design, the public reference isn't shaped like a card number, and it's not the gateway's internal vault identifier. It's the only token identifier WinkPG emits to you; the internal identifier never leaves the gateway.
- Stable. The same stored payment method keeps the same public reference, so you can store it against your customer record and reuse it across orders.
Charge with the token
To charge a stored payment method, send the public reference in the payment token field of a sale or authorization request instead of raw card data:
{
"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's returned on the response; it's not a way to set the amount charged, and a total that disagrees with the components you sent doesn't change what's charged. If you do send total, it's 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's recorded for review and the charge proceeds for the component sum. Either way, send a total only if you want that check. Always read the total on the response as the authoritative amount charged: fees the gateway adds after accepting your request, such as a surcharge or a convenience fee it computes, are outside the check and appear only there.
Say who initiated the charge
Card network rules require every charge against a stored payment method to say who initiated it, and WinkPG reports that to the processor from one field on the request: initiationType. The rule is about the customer's presence at the moment of the charge. It isn't about which system sends the request (your platform sends every request), and it isn't about what's being sold.
- The customer is present and agreeing to this charge right now, at a counter, on a kiosk, on a checkout page in front of them, or on a phone call: a cardholder-initiated (CIT) charge.
- The customer isn't present and you're charging on their behalf, for a subscription, an unpaid balance, a no-show fee, or an order you fulfill later: a merchant-initiated (MIT) charge.
The same stored payment method can be charged both ways. Decide per charge, not per integration.
When the customer is present (CIT)
Send initiationType as CardholderInitiated, or leave it out; an omitted value is treated as cardholder-initiated. Don't send a mitReason.
{
"initiationType": "CardholderInitiated",
"tokenData": {
"token": "pt_9fKq2ZmB7tLxW3aH5nR8cV1s"
},
"invoiceData": {
"customerId": "3f2a6c1e-8d4b-4f0a-9b7e-2c5d1a8e6f30",
"amounts": { "base": 49.00 }
}
}
WinkPG recognizes a cardholder-initiated charge that pays with a stored token as a later use of a stored payment method and reports it to the processor as one, referencing the network transaction that stored the card. No consent is consulted, so this works for any active stored payment method, including one saved without consent. invoiceData.customerId isn't enforced on a cardholder-initiated charge, but send it so the token resolves scoped to the customer who owns it.
When the customer isn't present (MIT)
Send initiationType as MerchantInitiated, a mitReason, and the owning customer in invoiceData.customerId. All three are required. A merchant-initiated token charge without customerId is rejected before any consent is checked.
{
"initiationType": "MerchantInitiated",
"mitReason": "UnscheduledCOF",
"tokenData": {
"token": "pt_9fKq2ZmB7tLxW3aH5nR8cV1s"
},
"invoiceData": {
"customerId": "3f2a6c1e-8d4b-4f0a-9b7e-2c5d1a8e6f30",
"amounts": { "base": 49.00 }
}
}
A merchant-initiated charge also needs a captured stored-credential consent that permits the reason: Recurring for a fixed schedule, Installment for a known total split into payments, and UnscheduledCOF for anything with no fixed schedule (it also covers DelayedCharge, NoShow, and IncrementalAuth). WinkPG resolves the active consent from the token and customer for you, so don't look up or send a consent id. A merchant-initiated charge with no consent that permits its reason is declined with stored_credential_consent_required.
Consent is captured when the card is saved, on a hosted payment page with save-card enabled or in the Virtual Terminal; the direct API can't record it. Ask for every usage you expect to need at that moment, because a later merchant-initiated charge can't add one. Setting up a hosted payment page covers the save-card purposes and the session-level consent settings.
Sending MerchantInitiated for a purchase the customer is making in front of you isn't rejected, but it misreports the charge to the networks, which price and dispute the two kinds differently. Sending a cardholder-initiated charge for one the customer never saw is the same mistake in the other direction.
Charge with a companion cardData
A token charge doesn't 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:
{
"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
cardDataon a token charge should carry the billing address, and optionally the cardholder name, email, or phone. Don't 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 don't need to set
isStoredPayment. WinkPG stamps that flag itself while resolving the token. It's an output of token resolution, not something the caller declares, so leave it out and let the gateway set it.
Don't declare a card-present entryMode (a magnetic-stripe, 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 isn't a secret in itself, so:
- Keep the token server-side. Don't 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's not card data, but it's a live charging handle.
What not to rely on
Charge only with the publicReference value. Don't attempt to charge using identifiers scraped from a transaction's history or from internal fields: those aren't resolvable for charging and aren't a supported integration surface. The public reference in the response and webhook is the one supported reusable handle.