Token service
Token service is a service which takes card data and returns a token
This token can be used in various API calls instead of presenting card data
sequenceDiagram
Browser->>+Website: Load page / start request to initiate payment
Website->>+Api: GetMerchantSessionKey
Api->>+Website: Response with MerchantSessionKey
Website->>+Browser: Render payment page (local)
Browser->>+Api: Tokenize Card
Api->>+Browser: Card Token
Browser->>Website: Card Token
How long a card is kept
A stored card is kept while it is used. A card that has not been used for two years is deleted, and the token stops working (TOK07). Every approved payment made with the token, and tokenising the same card again, counts as a use and starts the two years again.
The agreements of a card (see Hosted Payment) are deleted together with the card: PayLolly does not keep an agreement, or the consent evidence in it, for a card it no longer holds. If you need the evidence for longer, keep your own record of it (the agreement block of the payment, and your own consent record referenced by evidenceRef).
Use Cases
Call token service to tokenise existing card data
Call TokenizeCard with the details Store returned Token
request:
curl -X 'POST' \
'https://api.dev.paylolly.app/api/rest/v1.0/Token/TokenizeCard' \
-H 'accept: application/json' \
-H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a' \
-H 'Content-Type: application/json' \
-d '{
"cardNo": "4000000000000002",
"expiryYear": "30",
"expiryMonth": "12",
"expiryYYMM": "3012",
"email": "test@email.com",
"name": "NAME SURNAME",
"traceId": "1234567890A0B0C0D0E0F"
}'
response:
"9C2C6412351A5BED6529ED5698DE395E"
Note
A token created with TokenizeCard (for example with a traceId you imported) is just a card: it has no agreement and no recorded consent. Record the consent with Agreement/RecordConsent (below) to give it one, and to make the card appear in the hosted lookup of returning customers.
Detokenise card
For security reasons, only masked card details are returned
request:
curl -X 'GET' \
'https://api.dev.paylolly.app/api/rest/v1.0/Token/DeTokenizeCard?token=9C2C6412351A5BED6529ED5698DE395E' \
-H 'accept: application/json' \
-H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a'
response:
{
"token": "9C2C6412351A5BED6529ED5698DE395E",
"maskedPAN": "400000*0002",
"expiryYear": "30",
"expiryMonth": "12",
"expiryYYMM": "3012",
"email": "test@email.com",
"name": "NAME SURNAME",
"traceId": "1234567890A0B0C0D0E0F"
}
Call token service directly from javascript
Before serving website, from your backend call GetMerchantSessionKey
Ticks should be a good estiamte for maximum session time until tokenisation is completed - typically suggest "00:20:00" ie 20 minutes
Return is a MerchantSessionKey
This MerchantSessionKey is to be embedded / sent to the javscript domain so that a CORS request is possible to TokenizeCard directly from the browser
Insert header MerchantSessionKey in the request header
Note
CORS is enabled for TokenizeCard only
Of course card token is now returned to javascript domain, and should be uploaded to your backend for further processing
request:
curl -X 'GET' \
'https://api.dev.paylolly.app/api/rest/v1.0/Token/GetMerchantSessionKey?timeSpan=00%3A20%3A00' \
-H 'accept: application/json' \
-H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a'
response:
"CfDJ8LX3uRJAScJAif7HfPfxL1DJh6t97s7VHMqDR7AG4RG64Y4_tiZkz6_ttvqA-RWlFZp9TZiw4AjlN7l3UZ-sSUvAI8HnNdfoVtvGdgWvJN3aOrhAr-zoX_-j-GcI8LChjIrdUwjF9trG_8oiAjhqdjfhNFZbdL0Z5R4zCgw45UMe"
Request from Browser:
curl -X 'POST' \
'https://api.dev.paylolly.app/api/rest/v1.0/TokenJS/TokenizeCard' \
-H 'accept: application/json' \
-H 'MerchantSessionKey: CfDJ8LX3uRJAScJAif7HfPfxL1DJh6t97s7VHMqDR7AG4RG64Y4_tiZkz6_ttvqA-RWlFZp9TZiw4AjlN7l3UZ-sSUvAI8HnNdfoVtvGdgWvJN3aOrhAr-zoX_-j-GcI8LChjIrdUwjF9trG_8oiAjhqdjfhNFZbdL0Z5R4zCgw45UMe' \
-H 'Content-Type: application/json' \
-d '{
"cardNo": "4000000000000002",
"expiryYear": "30",
"expiryMonth": "12",
"expiryYYMM": "3012",
"email": "test@email.com",
"name": "NAME SURNAME"
}'
response:
"9C2C6412351A5BED6529ED5698DE395E"
Perform AsyncPayment with Token
Follow "Call token service directly from javascript above"
Follow "Async Payments" but instead of entering card details, you can pass token
Note
Please note that CORS is only enabled for TokenizeCard, so all other requests must be made from the backend **
request:
curl -X 'POST' \
'https://api.dev.paylolly.app/api/rest/v1.0/Payment/CreateAsyncPayment' \
-H 'accept: application/json' \
-H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a' \
-H 'Content-Type: application/json' \
-d '{
"merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
"currency": "EUR",
"amount": 1,
"merchantRef": "9e31818e-407b-48d8-8bbf-eb19fa565723",
"cardHolder": {
"email": "test@email.com",
"name": "NAME SURNAME"
},
"cardData":{
"cvc":"123"
},
"tokenData": {
"token": "9C2C6412351A5BED6529ED5698DE395E",
"traceId": "0102030405060708090A0B0C0D0E0F"
},
"authorisationType": "Auth",
"recurrence": "OneTime",
"initiation": "CIT",
"returnUrl": "https://mywebsite.com/payment/return/abc123",
"validUntil": "2026-12-31T13:55:10.603Z"
}'
response:
{
"redirectUrl": "https://api.dev.paylolly.app/payment/async/21f8d828-c855-4ef3-ab47-867fee51bdcb/Index",
"paymentId": "21f8d828-c855-4ef3-ab47-867fee51bdcb",
"merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
"accountId": "81de44cb-4b70-4207-9f5e-54355491a5cc",
"currency": "EUR",
"amount": 1,
"cardData": {
"maskedPAN": "400000*0002",
"expiryYYMM": "3012",
"token": "9C2C6412351A5BED6529ED5698DE395E"
},
"result": {
"status": "Async",
"processorId": "dd1ccb51-29e0-4967-a8de-8cc0a39c1d85",
"message": "redirect to async"
},
"merchantRef": "9e31818e-407b-48d8-8bbf-eb19fa565723"
}
The payment is a customer present payment, so initiation is CIT (MIT and MOTO are rejected with VAL13 on async payments) and cardData.cvc is required. A traceId is only needed for merchant initiated payments (see Payment Actions). To record what the cardholder agreed to, add the optional agreement object, or send an agreementId of an existing agreement: see Agreements.
Perform 3Dsecure with Token
Follow "Call token service directly from javascript above"
Follow "3DS API" but instead of entering card details, you can pass token
- Use ThreeDSVersionTokenized call instead of ThreeDSVersion
- Use ThreeDSAuthenticateTokenized call instead of ThreeDSAuthenticate
The challenge indicator 04 (challenge mandated) is forced only for the registering payment (CIT with recurrence OneClick); for other payments the value configured in 3DS Config is used.
Record consent for an existing token
Attach an agreement and your consent evidence to a token that already exists, without a payment. Full description and all fields: Agreements.
curl -X 'POST' \
'https://api.dev.paylolly.app/api/rest/v1.0/Agreement/RecordConsent' \
-H 'accept: application/json' \
-H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a' \
-H 'Content-Type: application/json' \
-d '{
"token": "08524FF1F8BE79B7EA0CE19204E81BF2",
"cardHolder": { "reference": "CUST-1" },
"agreement": {
"agreementRef": "TOPUP-1",
"description": "Wallet top-ups",
"consent": { "textVersion": "v3", "timestamp": "2026-09-01T09:00:00Z" }
}
}'
response:
{
"agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10",
"status": "Created",
"agreementRef": "TOPUP-1",
"consentStatus": "Recorded"
}
The same token, customer and agreementRef again returns Updated with the same agreementId. The token must belong to your merchant (TOK07 otherwise).
Cancel an agreement
Flag an agreement as cancelled. It is no longer offered to the cardholder on the hosted page; payments that quote it are counted and still processed.
curl -X 'POST' \
'https://api.dev.paylolly.app/api/rest/v1.0/Agreement/Cancel?agreementId=0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10' \
-H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a'
response:
{ "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10", "status": "Cancelled" }
An unknown id, or one that belongs to another merchant, gives AGR08. See Agreements.