Show / Hide Table of Contents

Agreements

An agreement records what a cardholder allowed you to do with a stored card: who the customer is, what the card may be used for, the limits, the evidence of consent, and the references PayLolly needs to make later merchant initiated payments correctly. Agreements work alongside tokens: a token still identifies the card, an agreement says what was agreed for it.

You do not have to use agreements. Payments with a token and traceId keep working exactly as before. Agreements are for merchants who want recorded consent, several independent arrangements on one card, or consent shown on the hosted page.

On this page

  • Vocabulary
  • Ways to create an agreement
  • Fields by channel
  • What an agreement does to a payment
  • Lifecycle
  • Use Cases
  • Rejected requests

Vocabulary

Term Meaning
agreement The recorded arrangement for a customer and a card
agreement The object you send on a payment to register one
cardHolder.reference Your id for the customer. It is the customer of the agreement (mandatory when you send agreement, 1 to 64 characters, not case sensitive)
agreementRef Your reference for the agreement, up to 36 characters (letters, digits, -, _, .). It tells parallel agreements of the same customer and card apart
agreementId PayLolly's id of the agreement, returned to you. Quote it on later payments
consent The cardholder's agreement to the arrangement, with its evidence

An agreement is identified by customer + card + agreementRef + type (the type follows from the request: a request with a schedule is a scheduled agreement, any other an unscheduled one). The agreementRef is not case sensitive and the first spelling is kept. Registering the same combination again updates the same agreement (the agreementId never changes); a different combination creates another agreement. So one card can carry several agreements, for example a wallet top-up and a subscription.

Ways to create an agreement

Way Consent Notes
Hosted payment Given on the PayLolly page and recorded by PayLolly Mandatory or optional (AskTokenize). Also for saved cards that have no consent yet
Async payment You collect it and attest it in the request consent object mandatory
Agreement/RecordConsent You collect it and attest it For tokens created before agreements, or imported. No payment involved
Sync payment not supported yet A sync payment with recurrence OneClick still returns a token as before; add the agreement afterwards with RecordConsent

All of them are for the registering payment: a customer present payment with recurrence OneClick (or Scheduled for a scheduled agreement) and initiation CIT. 3D Secure always asks the cardholder to authenticate (a mandated challenge, 04) on that payment.

Fields by channel

M = mandatory, O = optional, - = not sent by you (PayLolly records or derives it).

Field Hosted Async RecordConsent
cardHolder.reference (customer) M M M
agreementRef O O O
description (up to 200) M (shown in the consent sentence) O O
maxAmount (greater than 0) O (shown) O O
expiresAt (future, UTC) O (shown) O O
consent.textVersion (up to 32) not allowed M M
consent.timestamp (UTC, not in the future) not allowed M M
consent.ip (up to 45) - (observed) O (default: the browser IP seen during 3D Secure) O
consent.evidenceRef (up to 64) not allowed O O
token - - M (your token)

On hosted payments consent is recorded by PayLolly (AGR05 if you send it). On the other channels it is your assertion, so keep your own record of it and quote it in evidenceRef.

The merchant must be enabled for agreements (AGR09).

What an agreement does to a payment

  • Later payments: on a payment with a token you may send agreementId. PayLolly then uses the trace id and processor references of that agreement instead of the token's. With only the token (and traceId) nothing changes. The card itself is not changed by such a payment: its own trace id and processor references stay as they were, so payments that quote nothing are not affected. agreementId needs the stored card (tokenData, otherwise AGR16) and is not accepted on hosted payments (AGR17): the hosted page finds the agreement of the card from the agreement object.
  • Hosted lookup: the cards PayLolly offers a returning customer (LookupTokensByReference) are only those with an active agreement with recorded consent. See Saved cards.
  • Consent again: on the hosted page a saved card shows the consent checkbox when its agreement has no recorded consent, or when what you now send differs from what the agreement holds (description, maximum amount, end date or schedule). A card whose agreement says exactly the same is not asked again.
  • Scheduled agreements: a payment that quotes a scheduled agreement is compared with its schedule (amount, interval, instalments). Deviations are counted, never refused.
  • Never blocking: a payment is never rejected because an agreement is missing, cancelled or expired. A payment under a cancelled or expired agreement is counted and, where you quote it, still processed. This keeps your existing merchant initiated payments working. An agreementId that is not yours, or does not belong to the card of the payment, is the exception: it is rejected with AGR08, because it is a mistake in the request.

Lifecycle

State How Effect
Created A registering payment is approved (or RecordConsent) agreementId returned
Updated The same customer, card, type and agreementRef again Same agreementId. New consent replaces the terms (description, maximum amount, end date, schedule: what you leave out is cleared), and the previous consent with the terms it covered stays in the agreement's record (the last 10). A cancelled agreement becomes active again only with new consent. A scheduled agreement starts a new series: the payment count restarts and the dates are counted from the registering payment
Cancelled Agreement/Cancel Only a flag: it is no longer offered to the cardholder on the hosted page, and later payments quoting it are counted. Nothing else is blocked
Read Agreement/Get Returns the agreement, its consent evidence and the masked card. Changes nothing
Deleted With its card A card unused for two years is deleted together with its agreements and their consent evidence. See Token service

Use Cases

1. Hosted: register a card, consent mandatory

recurrence OneClick, mode New, cardHolder.reference and an agreement with a description. The cardholder must tick the consent box. Full request, pictures and response: Hosted Payment.

2. Hosted: register a card only if the cardholder agrees

recurrence OneTime and mode New,AskTokenize. Ticked: the card is registered. Unticked: a normal one-time payment, response NotCreated / ConsentDeclined. See Hosted Payment.

3. Hosted: returning customer with a saved card

mode PresetToken, PresetTokens or New,PresetToken with the same agreement. The consent box appears only while the agreement has no recorded consent for that card. See Hosted Payment.

4. Async: register a card with your own consent

You collect the consent on your page and tell PayLolly what the cardholder agreed to. PayLolly runs 3D Secure and registers the agreement after approval. Details and the 3D Secure flow: Async Payment.

"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"
  }
}

The result is in GetPaymentStatus and the webhooks:

"agreement": { "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10", "status": "Created", "agreementRef": "TOPUP-1", "consentStatus": "Recorded" }

5. Later payment with agreementId, and the older way side by side

Both work. Store the agreementId and the token when the card is registered.

With the agreement (the agreement's trace id and processor references are used):

{
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "accountId": "81de44cb-4b70-4207-9f5e-54355491a5cc",
  "currency": "EUR",
  "amount": 10,
  "merchantRef": "9e31818e-407b-48d8-8bbe-eb19fa565733",
  "tokenData": { "token": "08524FF1F8BE79B7EA0CE19204E81BF2" },
  "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10",
  "authorisationType": "AuthCapture",
  "recurrence": "Unscheduled",
  "initiation": "MIT"
}

The older way, still valid (token and traceId of the registering payment):

{
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "accountId": "81de44cb-4b70-4207-9f5e-54355491a5cc",
  "currency": "EUR",
  "amount": 10,
  "merchantRef": "9e31818e-407b-48d8-8bbe-eb19fa565734",
  "tokenData": { "token": "08524FF1F8BE79B7EA0CE19204E81BF2", "traceId": "0102030405060708090A0B0C0D0E0F" },
  "authorisationType": "AuthCapture",
  "recurrence": "Unscheduled",
  "initiation": "MIT"
}

An agreementId is needed when one card has several agreements and you want a payment made under a particular one. It must belong to your merchant and to that token, otherwise AGR08. See Payment Actions.

6. Record consent for a card you already hold

For a token created before agreements existed (or imported with TokenizeCard), when the cardholder gave consent in your own journey.

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", "ip": "203.0.113.9", "evidenceRef": "consent-2026-09-01-4711" }
  }
}'
{
  "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10",
  "status": "Created",
  "agreementRef": "TOPUP-1",
  "consentStatus": "Recorded"
}
  • The consent time may be in the past (when it was given), never in the future.
  • The same call again (same token, customer and agreementRef) returns Updated with the same agreementId; a different agreementRef creates another agreement. RecordConsent registers unscheduled agreements: a scheduled agreement is registered and changed only by a payment (agreement.schedule here gives AGR11). When you send maxAmount also send currency (one of your account currencies, with the decimals it allows; AGR06 otherwise). consent.ip must be an IP address (AGR07).
  • PayLolly copies the token's trace id and processor references into the agreement when it is created (or when it holds none), so it keeps working even if the token's own values change later. A repeat of the call never replaces the references of the agreement's own registering payment.
  • The token must be yours (TOK07 otherwise). The call has no effect on payments that use only the token.
  • This is also how you make cards saved before agreements existed appear again in the hosted lookup.

7. Cancel an agreement

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'
{ "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10", "status": "Cancelled" }

The agreement is flagged and no longer offered on the hosted page. Payments that quote it are counted and still processed (the cardholder's withdrawal of consent is your responsibility to honour: do not initiate payments under an agreement you cancelled). An unknown id, or one of another merchant, gives AGR08.

8. Get an agreement

Read an agreement back: what it allows, the consent evidence held for it, and the card it applies to (masked). Use it to check that consent is on record before you start charging, to answer a customer or a dispute, or to see whether the scheme reference is held.

curl -X 'GET' \
  'https://api.dev.paylolly.app/api/rest/v1.0/Agreement/Get?agreementId=0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10' \
  -H 'accept: application/json' \
  -H 'MerchantKey: 35236fcf-12f4-4c94-b4ba-5d236457b68a'
{
  "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10",
  "status": "Active",
  "agreementType": "Unscheduled",
  "agreementRef": "TOPUP-1",
  "customerReference": "CUST-1",
  "description": "Wallet top-ups",
  "maxAmount": 100,
  "currency": "EUR",
  "expiresAt": "2027-12-31T00:00:00Z",
  "maskedPAN": "400000*0002",
  "tokenExpiresAt": "2030-12-31T23:59:59.9999999Z",
  "registrationPaymentId": "8bea8040-dee7-441c-a35f-d6ce47d6c7f3",
  "schemeReference": "Present",
  "consent": {
    "status": "Recorded",
    "source": "HostedPage",
    "textVersion": "hosted-v1:3f6a1c9d",
    "timestamp": "2026-10-15T09:00:00Z",
    "ip": "203.0.113.9"
  },
  "threeDS": {
    "version": "2.2.0", "eci": "5", "transStatus": "Y",
    "method": "02", "authenticatedAt": "2026-10-15T09:00:03Z",
    "dsTransId": "6b3f2a1e-3c52-4d0e-9a5b-1f2d3c4b5a69", "acsTransId": "0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d"
  },
  "createdAt": "2026-10-15T09:00:04Z",
  "lastUpdated": "2026-10-15T09:00:04Z",
  "lastUsedAt": "2026-10-15T09:00:04Z"
}
Field Meaning
status Active, or Cancelled (see Cancel)
agreementType Unscheduled, or Scheduled (see use case 10)
schedule, paymentsMade, nextPaymentDue Scheduled agreements only: the agreed amount and interval, the approved payments with an amount made under it, and when the next one is expected (a date; empty when complete, cancelled or past its end). You make the charge, PayLolly only shows the expectation
customerReference Your cardHolder.reference, upper cased and trimmed
maxAmount, currency, expiresAt The limits you agreed with the cardholder, when there are any
maskedPAN The card, first 6 and last 4 digits. The card number is never returned
tokenExpiresAt The last moment the card can be used: the end of its expiry month (UTC). Worked out from the card expiry, not stored
lastUsedAt When the agreement was last used: the registering payment, or a later approved payment that quoted the agreementId. Declined payments, payments that do not quote it, and RecordConsent do not count. Not present when never used
lastUpdated When the agreement itself last changed (the same customer, card and agreementRef registered again, or cancelled)
registrationPaymentId The payment that registered the agreement. Not present when the agreement came from RecordConsent
schemeReference Present, or Missing when the processor returned no scheme reference (Trace ID) for the registering payment. The agreement and its consent are recorded either way, but a later merchant initiated payment cannot then be linked to the original payment by the scheme, and the issuer may decline it
consent.status Recorded, or LegacyUnrecorded when no consent evidence is held
consent.source HostedPage (the cardholder ticked the box on the hosted page), MerchantAttested (you recorded it) or None
consent.textVersion, timestamp, ip, evidenceRef The evidence: the version of the text shown, when it was given, the cardholder's IP when known, and your own reference
threeDS Version, ECI and transaction status of the registering payment, when there was one (never the cryptogram), and how the cardholder was authenticated: method (01 frictionless, 02 challenge), authenticatedAt (UTC), dsTransId and acsTransId. If you run 3D Secure yourself for a later customer present payment, send them as requestorPriorAuthenticationInfo (method, timestamp as yyyyMMddHHmm, threeDSReqPriorRef = acsTransId, threeDSReqPriorDsTransId = dsTransId; the last one only on 3DS 2.3.1). PayLolly does this itself for async and hosted payments, see 3D Secure configuration
threeDSRecurring Scheduled agreements: the recurring 3D Secure fields derived from the schedule (authenticationInd, recurringExpiry, recurringFrequency, purchaseInstalData), to use when you authenticate the registering payment yourself

An unknown id, or one that belongs to another merchant, gives AGR08. Merchants without agreements enabled get AGR09.

9. Find agreements in the Portal and through MCP

The Portal has an Agreements page (menu item Agreements) for administrators and for users with the Agreements role. It is read only. The merchant is the one selected in the top bar; without one, an administrator sees every merchant and any other user the merchants they are assigned to. Filters:

  • agreement id, customer reference (case and surrounding spaces ignored), agreement ref
  • status, consent status and consent source, only agreements without a scheme reference
  • created from / to, not used since (never used counts), card first 6 and last 4, card expires before

Each row shows the customer, agreement ref, status, masked card, when the card expires, consent, created and last used. Details shows, for a scheduled agreement, the schedule with the payments made and the next expected payment, and the consent evidence (text version, time, IP, your evidence reference), the registering payment and the 3D Secure result of the registering payment. The customer reference is shown in full. The card number, the scheme reference itself, processor references and 3D Secure identifiers are never shown.

The same data is available to MCP clients with two read only tools, with the same role and merchant rules: search_agreements (the same filters, newest first, paged; the agreement reference is matched without regard to case; filters on the type, consent and scheme reference read the agreements and are refused above 5,000 matches, the others page in the database at any size) and get_agreement (one agreement with its consent evidence). Neither can change or cancel an agreement.

10. Scheduled agreements: subscriptions and instalments

A scheduled agreement has a fixed amount and a fixed interval, for example 10.00 EUR every month for 12 months. It is registered like the others, with a customer present payment, but with recurrence Scheduled and an agreement.schedule. The cardholder agrees to exactly that schedule (on the hosted page the sentence they tick is generated from the schedule fields).

Note

You collect every payment. PayLolly does not schedule or charge anything: each payment is a merchant initiated sync payment (initiation MIT, recurrence Recurring) that quotes the agreementId, sent by you when it is due. The schedule is what the cardholder agreed to; PayLolly records it, checks your payments against it and shows what it expects next.

Warning

Scheduled agreements are only accepted for accounts whose processor was verified for them. Until then a request with recurrence Scheduled is rejected with RTE04. Ask PayLolly which of your accounts are enabled.

Registering (async shown, hosted is the same without consent):

{
  "currency": "EUR",
  "amount": 10,
  "merchantRef": "2425363c-5541-4c37-a698-77447650610d",
  "cardHolder": { "reference": "CUST-1", "email": "test@test.com", "name": "test user" },
  "authorisationType": "AuthCapture",
  "recurrence": "Scheduled",
  "initiation": "CIT",
  "agreement": {
    "agreementRef": "GYM-1",
    "description": "Gym membership",
    "expiresAt": "2027-11-30T00:00:00Z",
    "schedule": {
      "amount": 10,
      "interval": { "unit": "Month", "count": 1 },
      "firstPaymentDate": "2026-12-01",
      "instalments": 12,
      "cancellationUrl": "https://shop.example/cancel"
    },
    "consent": { "textVersion": "v4", "timestamp": "2026-11-15T09:00:00Z" }
  }
}
Field Rules
schedule.amount The fixed amount of every payment, greater than 0, in the payment currency. maxAmount is not allowed together with a schedule (AGR12): a price change is a new agreement with a new consent
schedule.interval unit Day, Week, Month or Year, and a count of 1 to 999 units between payments
schedule.firstPaymentDate Optional, today or later. Without it the registering payment is the first payment and its amount must equal schedule.amount. With it, the registering amount may be anything, 0 for a free trial or a card check. A zero amount requires firstPaymentDate (AGR18): a card check is not a payment, so the start of the schedule has to be stated. Dates without a time zone (2026-12-01) are UTC dates
schedule.instalments Optional, 2 to 999 payments. Without it the agreement runs until expiresAt
agreement.expiresAt Optional when instalments is given. One of the two is required (AGR13), and when both are sent the instalments must fit before expiresAt A schedule runs at most 10 years from its first payment (AGR13).
schedule.cancellationUrl Optional, https, up to 200 characters. Shown to the cardholder on the hosted page
agreement.consent As for async. Not allowed on hosted, where PayLolly records the tick

On the hosted page the consent is always mandatory (the AskTokenize mode is rejected with AGR15), and a saved card is asked again when the schedule differs from the one its agreement holds (the same rule as for every agreement). The sentence is built from your fields, for example:

I agree that my card details are saved and EUR 10.00 will be charged every month, starting 2026-12-01, for 12 payments, until 2027-11-30. Gym membership I can cancel at https://shop.example/cancel

The text version stored as evidence is hosted-s1: followed by a short hash of the exact sentence shown.

Later payments are ordinary merchant initiated payments:

{
  "merchantId": "dbdab964-82ee-4b09-a26b-68403c31afa7",
  "accountId": "81de44cb-4b70-4207-9f5e-54355491a5cc",
  "currency": "EUR",
  "amount": 10,
  "merchantRef": "9e31818e-407b-48d8-8bbe-eb19fa565735",
  "tokenData": { "token": "08524FF1F8BE79B7EA0CE19204E81BF2" },
  "agreementId": "0198ab5c-6f37-7a02-9d7e-3a5e2c1f4b10",
  "authorisationType": "AuthCapture",
  "recurrence": "Recurring",
  "initiation": "MIT"
}

Scheduled itself is only for the registering payment: a merchant initiated payment with recurrence Scheduled is rejected (VAL08), use Recurring.

Checks when you charge. A payment under a scheduled agreement is compared with what was agreed. A payment is never refused for it; each deviation is counted so that it can be followed up, and enforcement can later be switched on per merchant:

Deviation Counted when
amount the amount is not the schedule.amount
currency the currency is not the agreement currency
too early the payment comes more than 3 days before its due date: the first payment date (or the registering payment) plus one interval for each payment made. A late payment does not make the next one early, and a card check does not move the due date
before the first payment the firstPaymentDate has not arrived
instalments all instalments were already paid
cancelled, expired as for every agreement

A zero amount card check is never compared.

Following the schedule. Agreement/Get (and the Portal and MCP) show the schedule, paymentsMade and nextPaymentDue. paymentsMade counts approved payments with an amount made under the agreement, including the registering payment when it was the first payment. nextPaymentDue is worked out from the first payment date (or the registering date) plus the payments made times the interval, so a late payment does not move the following dates. It is empty when the agreement is complete, cancelled or past its end.

Rejected requests are listed below.

Rejected requests

Request Error
initiation MIT or MOTO on an async or hosted payment VAL13 (these payments are always cardholder initiated)
initiation MIT with recurrence OneClick or OneTime VAL08 ("a merchant initiated payment cannot be OneClick, use Unscheduled or Recurring")
initiation MOTO with any recurrence other than OneTime VAL08 ("a MOTO payment must be OneTime")
agreement without cardHolder.reference (or longer than 64) AGR01
agreement with a recurrence other than OneClick (hosted: or OneTime with AskTokenize) AGR02
hosted without agreement.description AGR03
async or RecordConsent without a valid consent (textVersion and a timestamp not in the future) AGR04
hosted with agreement.consent AGR05
maxAmount not positive or too many decimals, expiresAt not in the future AGR06
recurrence Scheduled without agreement.schedule (or without the agreement object) AGR10
agreement.schedule with a recurrence other than Scheduled AGR11
bad schedule amount, interval or instalments; maxAmount together with a schedule; a registering amount that is neither the schedule amount nor 0 when there is no firstPaymentDate AGR12
neither expiresAt nor instalments, instalments that do not fit before expiresAt, or a schedule that runs more than 10 years from its first payment AGR13
firstPaymentDate in the past AGR14
hosted Scheduled with AskTokenize AGR15
agreementId without tokenData AGR16
agreementId on a hosted payment AGR17
initiation MIT with recurrence Scheduled VAL08
Scheduled and no account of the merchant supports it RTE04
schedule.cancellationUrl not https or longer than 200 AGR07
invalid agreementRef format, or a field longer than allowed AGR07
unknown agreementId, or one of another card or merchant AGR08
agreements not enabled for the merchant AGR09
token not yours or invalid TOK07

Example (AGR01):

{
  "type": "AGR01",
  "title": "Agreement requires cardHolder.reference (1 to 64 characters)",
  "status": 500,
  "traceId": "00-e0851274983d581c7837f1a7ae895e99-86117ae4f235f4f9-00"
}

Every code is in Errors.

In this article
Back to top Generated by DocFX