Show / Hide Table of Contents

Async Payment

sequenceDiagram
    Browser->>+Website: Request to initiate payment
    Website->>+Api: Create Async Payment
    Api->>+Website: Response with url
    Website->>+Browser: Iframe or redirect to url
    Browser->>+PayLolly: Redirect to paylolly
    PayLolly->>+PayLolly: Process transaction
    PayLolly->>+Browser: Redirect to Website
    Browser->>+Website: Back from payment
    Api->>+Website: Webhook (optional)

Use Cases

Async Payment - Single one-shot payment

Use Payment/CreateAsyncPayment call

  • Populate merchantId
  • Optionally populate accountid if you want to force a particular account
  • Populate Currency ex EUR
  • Populate amount ex 1.00
  • Create a merchantRef - must be unique - suggest Guid
  • Enter cardholder details
  • Enter card details in cardData
  • Populate AuthorisationType depending on your use case
    • Preauth - Auth
    • Preauth and Capture - AuthCapture
  • Recurrence - OneTime
  • WebHooks - suggest population of completed and approved webhooks to receive server-to-server call when payment completed
  • Initiation - set to CIT (the only value accepted on async payments: MIT and MOTO are rejected with VAL13)
  • ReturnUrl - enter a valid url to redirect cardholder at the end of the payment
  • ThreeDSConfig - see ThreeDSConfig - default values apply if omitted
  • validUntil - enter a valid until date/time - suggest 20 minutes

The above will create a single one-shot payment request

request:

{
  "returnUrl": "https://portal.dev.paylolly.app/VirtualTerminal/Async/Return",
  "validUntil": "2022-11-04T11:15:54.8200623Z",
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "currency": "EUR",
  "amount": 100.0,
  "merchantRef": "2425363c-5541-4c37-a698-77447650610d",
  "cardHolder": {
    "email": "test@test.com",
    "name": "test user"
  },
  "cardData": {
    "cardNo": "4000000000000002",
    "expiryYear": "22",
    "expiryMonth": "12",
    "cvc": "123",
    "expiryYYMM": "2212"
  },
  "authorisationType": "AuthCapture"
}

response:

{
  "redirectUrl": "https://api.dev.paylolly.app/payment/async/ed9d773b-f27b-4286-8525-cbb9293d7604/Index",
  "paymentId": "ed9d773b-f27b-4286-8525-cbb9293d7604",
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "accountId": "81de44cb-4b70-4207-9f5e-54355491a5cc",
  "currency": "EUR",
  "amount": 100,
  "cardData": {
    "maskedPAN": "400000*0002",
    "expiryYYMM": "2212",
    "token": "830DAE88123E8DD3DEF9658E846F97C2"
  },
  "threeDSData": null,
  "result": {
    "status": "Async",
    "processorId": "35cdb967-a12a-4bae-9dfd-9617a8f8abae",
    "message": "redirect to async",
    "authCode": null,
    "traceId": null,
    "standardHostCode": null,
    "mastercardMacCode": null
  },
  "merchantRef": "2425363c-5541-4c37-a698-77447650610e"
}

Async Payment - one-shot payment with previous details (fixed) - repeated payment CIT

Use Payment/CreateAsyncPayment call

  • Populate merchantId

  • Optionally populate accountid if you want to force a particular account

  • Populate Currency ex EUR

  • Populate amount ex 1.00

  • Create a merchantRef - must be unique - suggest Guid

  • Enter cardholder details if known

  • populate tokenData with previous payment Token

  • Populate AuthorisationType depending on your use case

    • Preauth - Auth
    • Preauth and Capture - AuthCapture
  • Recurrence - OneTime

  • WebHooks - suggest population of completed and approved webhooks to receive server-to-server call when payment completed

  • Initiation - set to CIT (the only value accepted on async payments: MIT and MOTO are rejected with VAL13)

  • ReturnUrl - enter a valid url to redirect cardholder at the end of the payment

  • ThreeDSConfig - see ThreeDSConfig - default values apply if omitted

  • validUntil - enter a valid until date/time - suggest 20 minutes

  • The above will create a single one-shot payment request

request:

{
  "returnUrl": "https://portal.dev.paylolly.app/VirtualTerminal/Async/Return",
  "validUntil": "2022-11-04T11:15:54.8200623Z",
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "currency": "EUR",
  "amount": 100.0,
  "merchantRef": "2425363c-5541-4c37-a698-77447650610b",
  "cardHolder": {
    "email": "test@test.com",
    "name": "test user"
  },
  "tokenData": {
    "token": "830DAE88123E8DD3DEF9658E846F97C2"
  },
  "cardData":{
    "cvc":"123"
  },
  "authorisationType": "AuthCapture"
}

response:

{
  "redirectUrl": "https://api.dev.paylolly.app/payment/async/469a8e0f-8633-4f67-bb2b-cc08722edc83/Index",
  "paymentId": "469a8e0f-8633-4f67-bb2b-cc08722edc83",
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "accountId": "81de44cb-4b70-4207-9f5e-54355491a5cc",
  "currency": "EUR",
  "amount": 100,
  "cardData": {
    "maskedPAN": "400000*0002",
    "expiryYYMM": "2212",
    "token": "830DAE88123E8DD3DEF9658E846F97C2"
  },
  "threeDSData": null,
  "result": {
    "status": "Async",
    "processorId": "bec048de-d9f9-48f0-82b2-94833f9698e4",
    "message": "redirect to async",
    "authCode": null,
    "traceId": null,
    "standardHostCode": null,
    "mastercardMacCode": null
  },
  "merchantRef": "2425363c-5541-4c37-a698-77447650610b"
}
Tip

See Payment Actions for further actions possible on completed async payment

Async Payment - register a card with an agreement

Tip

For a subscription or instalments (fixed amount and interval) use recurrence Scheduled and agreement.schedule instead of OneClick, see Agreements.

Use this to save the card for later payments (merchant initiated payments, one-click) and record what the cardholder agreed to, when you show the consent on your own page. (On the hosted page PayLolly shows and records the consent for you, see Hosted Payment.) The concepts and all channels are in Agreements.

Use Payment/CreateAsyncPayment as for a one-shot payment, but:

  • recurrence: OneClick (the registering payment)
  • initiation: CIT
  • cardHolder.reference: your id for the customer (mandatory, 1 to 64 characters)
  • agreement: what was agreed
    • description: what the card may be used for (optional on async)
    • agreementRef, maxAmount, expiresAt: optional
    • consent: mandatory - textVersion (the version of the consent text you showed), timestamp (when the cardholder agreed, UTC, not in the future), optionally ip (default: the browser address PayLolly sees during 3D Secure) and evidenceRef (your own record of the consent, for disputes)
  • the merchant must be enabled for agreements (AGR09)

The consent is your assertion: PayLolly records it as attested by you. Show the cardholder the exact text you version, and keep your own record.

request:

{
  "returnUrl": "https://portal.dev.paylolly.app/VirtualTerminal/Async/Return",
  "validUntil": "2026-11-04T11:15:54.8200623Z",
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "currency": "EUR",
  "amount": 25.0,
  "merchantRef": "2425363c-5541-4c37-a698-77447650610c",
  "cardHolder": {
    "reference": "CUST-1",
    "email": "test@test.com",
    "name": "test user"
  },
  "cardData": {
    "cardNo": "4000000000000002",
    "expiryYYMM": "3012",
    "cvc": "123"
  },
  "authorisationType": "AuthCapture",
  "recurrence": "OneClick",
  "initiation": "CIT",
  "agreement": {
    "agreementRef": "TOPUP-1",
    "description": "Wallet top-ups",
    "maxAmount": 100,
    "consent": {
      "textVersion": "v3",
      "timestamp": "2026-10-16T09:00:00Z",
      "evidenceRef": "consent-2026-10-16-4711"
    }
  }
}

response (the payment is pending until the cardholder has been through 3D Secure, so there is no agreement yet):

{
  "redirectUrl": "https://api.dev.paylolly.app/payment/async/469a8e0f-8633-4f67-bb2b-cc08722edc84/Index",
  "paymentId": "469a8e0f-8633-4f67-bb2b-cc08722edc84",
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "currency": "EUR",
  "amount": 25,
  "merchantRef": "2425363c-5541-4c37-a698-77447650610c"
}

Send the cardholder to redirectUrl. PayLolly runs 3D Secure, which always asks the cardholder to authenticate (a mandated challenge, indicator 04) on a registering payment. After approval the agreement is registered and the outcome is in Payment/GetPaymentStatus and in your completed and approved webhooks:

{
  "paymentId": "469a8e0f-8633-4f67-bb2b-cc08722edc84",
  "result": { "status": "Approved" },
  "cardData": { "maskedPAN": "400000*0002", "token": "08524FF1F8BE79B7EA0CE19204E81BF2" },
  "agreement": {
    "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10",
    "status": "Created",
    "agreementRef": "TOPUP-1",
    "consentStatus": "Recorded"
  }
}

Store the token and the agreementId for the customer. Later payments quote them, see Payment Actions. Declined payments register nothing (NotCreated / PaymentNotApproved). The same customer, card and agreementRef again updates the same agreement. See Webhooks for the outcomes.

In this article
Back to top Generated by DocFX