Skip to main content

Recurring payments with cards and wallets

View as Markdown

Merchant Initiated Transactions (MIT) are typical of business models in which payments are made at a later time than the purchase.

In these scenarios the buyer authorises the merchant to make future charges by accepting the terms and conditions set out in the contractual agreement between the parties.

Use cases
  • Fixed amount and frequency: subscriptions, digital services.
  • Variable amount or frequency: utility bills, pay-per-use services.

A recurring payment flow consists of two types of transaction:

TransactionInitiated byCustomer presentAuthentication
First – Customer Initiated Transaction (CIT)The customerYesStrong Customer Authentication (SCA) always mandatory
Next – Merchant Initiated Transaction (MIT)The merchantNoNot required

The First transaction verifies the payer's identity and generates the reference identifier needed to process the Next transactions. The payment method token can be requested together with the First, or a previously generated token can be used. Next transactions are processed by the merchant without the customer being present.

Token request

The token can also be generated separately from the recurring transaction and used later for the First. For how to request it, see the Tokenization section.

Regulatory scope

MIT transactions are considered out of scope of PSD2 and therefore do not require two-factor authentication.


Recurrence types​

Fabrick Payment Orchestra supports two types of recurring payment. The choice determines the value of the transDetails.type field for all the transactions in the series.

ScheduledUnscheduled
AmountFixedVariable
FrequencyConstant and definedVariable, not scheduled
Use casesSubscriptions and digital servicesUtility bills, pay-per-use services, no-show fees, damage charges for rented goods
First type01F03F
Next type01N03N

Supported payment methods​

MethodFirst (CIT)Next (MIT)
CardHosted integrations or API Only, with card data or an existing tokenToken generated or used in the First
Apple PayHosted integrations or API Only, with the Apple Pay payload or an existing tokenToken generated or used in the First
Google PayHosted integrations or API Only, with the Google Pay payload or an existing tokenToken generated or used in the First
Click to PayHosted integrations onlyToken generated or used in the First

For Next transactions the flow is the same for all methods. Wallets are handled as cards: the token generated or used during the First must always be sent in the paymentTypeDetails.creditcard.token field.


Common requirements​

Next transactions are valid only if all these conditions are met:

  • there is an agreement between merchant and buyer authorising the charges
  • each Next includes the reference to the First transaction (paymentID)
  • each Next is submitted with the same shopLogin as the First
  • the First has not been cancelled: otherwise the recurring chain would no longer be valid
  • the First was authenticated with SCA
Tokenization is mandatory

Each recurring series is associated with a payment method token, to be used for the Next transactions. The token can be requested together with the First, or a previously generated token can be used for a card or wallet that has already been tokenized: in this case the First does not request a new tokenization (see API Only integration). For how to request a token, see the Tokenization section.


First flow (CIT)​

Request fields​

To tell the system that the transaction is the first of a recurring series, add the transDetails object to the payment/create call, in addition to the mandatory fields:

FieldScheduled 01FUnscheduled 03FDescription
transDetails.type01F03FRecurrence type
transDetails.authenticationAmount✅✅Maximum amount expected under the agreement between the parties
transDetails.recurringTransaction.expiry✅❌Expiry date of the agreement, YYYYMMDD format. No Next can be processed after this date
transDetails.recurringTransaction.frequency✅❌Minimum number of days between two charges of the same series
Maximum authorised amount

If authenticationAmount is not populated, or if amount is greater than authenticationAmount, the system uses amount as the maximum authorised amount for the Next transactions and, at the same time, charges the initial payment for that amount.

Zero initial amount (ASI)​

If the service includes a free trial period or a deferred charge, you can set amount to zero. In this case the request is called ASI (Account Status Inquiry) and authenticationAmount must be populated with the maximum amount set out in the agreement for the Next transactions.

The amount in authenticationAmount may be shown to the buyer during authentication, depending on their bank's settings; alternatively, the amount in the amount field may be shown.

ASI

The ASI is intended to verify the payment method and initialise the recurring series: the transaction cannot be captured or cancelled.

Choosing the integration mode​

The First can be handled in two ways, which differ in who collects the payment details and in the number of calls needed:

ScenarioIntegrationCalls
The customer enters the card or chooses a wallet (Apple Pay, Google Pay, Click to Pay) through the hosted integrationsHosted (Checkout Page, Pay By Link, Lightbox, Web Component)payment/create
The card or wallet has already been tokenizedAPI Onlypayment/create without requestToken + payment/submit with the token
The customer enters the card details in a payment form on the merchant's websiteAPI Onlypayment/create + payment/submit with the card data
The customer pays with Apple Pay or Google Pay directly from the checkout of the merchant's websiteAPI Onlypayment/create + payment/submit with the wallet payload
Click to Pay

Click to Pay is available with hosted integrations only. Unlike Apple Pay and Google Pay, it does not require a dedicated payload and follows the same flow as the card.

Authentication always mandatory

The First always requires Strong Customer Authentication (SCA). Exemptions cannot be requested, regardless of the integration mode and of whether a token is available. With hosted integrations authentication is handled by Fabrick; with API Only the redirect to the customer's bank is the merchant's responsibility.

Mandatory notice to the buyer

The First involves the tokenization of the payment method: the buyer must be informed before the transaction is submitted.

  • With hosted integrations (Checkout Page, Pay By Link, Lightbox, Web Component) the notice is already handled by Fabrick and the message is shown automatically.
  • With a custom payment page (API Only) the notice is the merchant's responsibility.

The messages shown by the hosted integrations are described in the Tokenization section.


Hosted integration​

With hosted integrations the customer is shown the card and the enabled wallets. The payment/create call is enough: depending on the method chosen by the customer, the token to be used for the Next transactions is returned at the end of the payment.

Step 1 — Creating the request​

Call payment/create on the server side, including:

  • requestToken set to MASKEDPAN, to request tokenization
  • paymentType set to CREDITCARD, to limit the page to the card and wallets
Card and wallets on the same page

With paymentType set to CREDITCARD, the page also shows Apple Pay, Google Pay and Click to Pay, if enabled on the shopLogin. The request does not change depending on the method: the customer chooses on the page, and the token returned matches the method used.

paymentChannel object

The examples use Pay By Link. With Lightbox or Web Component, remove the paymentChannel object from the call.

Request

POST /api/v1/payment/create
Host (sandbox): sandbox.gestpay.net
Host (production): ecomms2s.sella.it
Authorization: apikey ****************
Content-Type: application/json
{
"shopLogin": "GESPAY12345",
"amount": "0",
"currency": "EUR",
"shopTransactionID": "FBK-C01F_OrderID",
"paymentChannel": { "channelType": ["LINK"] }, // Pay By Link only
"paymentType": ["CREDITCARD"],
"requestToken": "MASKEDPAN",
"transDetails": {
"type": "01F",
"authenticationAmount": "100",
"recurringTransaction": {
"expiry": 20261231,
"frequency": 15
}
}
}

Step 2 — Presenting the payment page​

The payment/create response contains paymentToken and paymentID; with Pay By Link, the redirect link is returned in payload.userRedirect.href.

Redirect the customer to the link in payload.userRedirect.href.

Response

{
"error": {
"code": "0",
"description": "request correctly processed"
},
"payload": {
"paymentToken": "8a901523-67a5-4aca-bbd2-c7c412934289",
"paymentID": "1360119538182",
"userRedirect": {
"href": "https://sandbox-web.axerve.com/orchestra/checkout/a/dc1e181fe487435c86a09120550327a9/b/925e8ec8839a1baf2da2d49f5ecf87cf..."
},
"qrCode": null
}
}

Step 3 — Payment outcome​

At the end of the payment, the behaviour depends on the integration:

IntegrationBehaviour
Pay By LinkThe customer is redirected to the positive or negative outcome URL (see Pay By Link)
Web ComponentThe customer is redirected to the positive or negative outcome URL (see Web Component)
LightboxAutomatic redirect to the positive or negative outcome URL or, if the callback object is used, URL available in the responseURL field (see Lightbox)

Continue with checking the outcome and retrieving the token.


API Only integration​

With the API Only integration the merchant collects the payment details on their own page and sends them to Fabrick with payment/submit. Handling the redirect for authentication is the merchant's responsibility.

Step 1 — Creating the request​

Call payment/create on the server side: the request is the same for card, Apple Pay and Google Pay. Click to Pay is not available with this integration.

When to use requestToken

Add requestToken set to MASKEDPAN only in payment/create, and only if in step 2 you send the card data or the Apple Pay or Google Pay payload.

If the First uses an existing token instead, omit the field: the payment method is already tokenized and the same token is used for the Next transactions. If requestToken is present, payment/submit with the token returns the error:

1107 - Unexpected parameter name. Please double check Fields and Parameters configuration in Back Office

Request

POST /api/v1/payment/create
Host (sandbox): sandbox.gestpay.net
Host (production): ecomms2s.sella.it
Authorization: apikey ****************
Content-Type: application/json
{
"shopLogin": "GESPAY12345",
"amount": "0",
"currency": "EUR",
"shopTransactionID": "FBK-C01F_OrderID",
"requestToken": "MASKEDPAN", // Do not use if a token is used in the submit
"transDetails": {
"type": "01F",
"authenticationAmount": "100",
"recurringTransaction": {
"expiry": 20261231,
"frequency": 15
}
}
}

Response

{
"error": {
"code": "0",
"description": "request correctly processed"
},
"payload": {
"paymentToken": "8a901523-67a5-4aca-bbd2-c7c412934289",
"paymentID": "1360119538182",
"userRedirect": null,
"qrCode": null
}
}

The response contains paymentToken, to be used in the header of payment/submit, and paymentID, to be used to check the outcome and as the reference for the Next transactions.

Step 2 — Sending the payment details​

Send the payment details with payment/submit, setting the PaymentToken header to the value received in the previous step. The body depends on the payment method and is the same for 01F and 03F.

If the card or wallet has already been tokenized, send the token in the paymentTypeDetails.creditcard.token field: wallets are handled as cards. The call can be made on the server side, because no card data is transmitted.

In this case the payment/create in step 1 must not contain the requestToken field.

Request

POST /api/v1/payment/submit
Host (sandbox): sandbox.gestpay.net
Host (production): ecomms2s.sella.it
PaymentToken: 8a901523-67a5-4aca-bbd2-c7c412934289
Content-Type: application/json
{
"shopLogin": "GESPAY12345",
"paymentType": "CREDITCARD",
"paymentTypeDetails": {
"creditcard": {
"token": "40ZUU8NXALR33101"
}
}
}

Step 3 — Handling the response​

The payment/submit response can present three scenarios:

The transactionErrorCode field returns 8006: you must redirect the customer to their bank's authentication page, using the link in payload.userRedirect.href.

Response

{
"error": {
"code": "0",
"description": "request correctly processed"
},
"payload": {
"transactionErrorCode": "8006",
"transactionErrorDescription": "Verify By Visa",
"paymentID": "1360119538182",
"userRedirect": {
"href": "https://sandbox.gestpay.net/pagam/pagam3d.aspx?a=GESPAY12345&b=8a901523-67a5-4aca-bbd2-c7c412934289&axerve3D=True&IsLightBox=False"
}
}
}

Checking the outcome and retrieving the token​

At the end of the payment the system sends a server-to-server (S2S) notification with the outcome and the paymentToken and paymentID values, together with any redirect of the customer. The notification lets you update the payment status even if the customer does not return to the website.

https://merchant-url.com?a=GESPAY12345&Status=OK&paymentID=1360119538182&paymentToken=8a901523-67a5-4aca-bbd2-c7c412934289

Use payment/detail to check the outcome and retrieve the token, of the card or of the wallet, in the payload.token field. For more information about the token, you can read the payload.tokenDetails object, which returns the same value in TokenValue together with the expiry date and last digits of the card (CardDetails).

Response details

Request

GET /api/v1/payment/detail/{paymentID}
Host (sandbox): sandbox.gestpay.net
Host (production): ecomms2s.sella.it
Authorization: apikey ****************
Content-Type: application/json

Response

{
"error": {
"code": "0",
"description": "request correctly processed"
},
"payload": {
"transactionType": "detail",
"transactionResult": "APPROVED",
"transactionState": "AUT",
"transactionErrorCode": "0",
"transactionErrorDescription": "Transaction correctly processed",
"bankTransactionID": "492",
"shopTransactionID": "FBK-C01F_OrderID",
"shopTransactionID_2": "",
"authorizationCode": "188190",
"paymentID": "1360119538182",
"currency": "EUR",
"country": "ITALIA",
"company": "VISA",
"tdLevel": "FULL",
"threeDS": {
"authenticationResult": {
"authenticationLevel": "2C",
"authenticationStatus": "Y",
"authStatusReason": "",
"challengeResultTransStatus": "",
"XID": "12e6e4ce-8ccc-49f9-b5a4-18b486f1d29d",
"AV": "MTIzNDU2Nzg5MDA5ODc2NTQzMjE=",
"ECI": "05",
"AVAlgorithm": "",
"threeDsVersion": "2.1.0"
},
"transDetails": {
"authData": "",
"authMethod": "02",
"authTimeStamp": "202407111313",
"acsID": "48a413bf-fe27-4de2-a39e-dc6039e4aef7"
}
},
"events": [
{
"event": {
"eventtype": "AUT",
"eventamount": "0.00",
"eventdate": "11/07/24 13:13:56",
"eventARN": "",
"eventID": "",
"eventReferred": ""
}
}
],
"buyer": {
"name": "",
"email": ""
},
"risk": {
"riskResponseCode": "",
"riskResponseDescription": ""
},
"customInfo": null,
"alertCode": "",
"alertDescription": "",
"cvvPresent": "TRUE",
"dcc": null,
"maskedPAN": "",
"paymentMethod": "VISA",
"productType": "Credit",
"token": "40ZUU8NXALR33101",
"tokenExpiryMonth": "05",
"tokenExpiryYear": "27",
"tokenDetails": {
"TokenValue": "40ZUU8NXALR33101",
"TokenExpiryMonth": "05",
"TokenExpiryYear": "27",
"TokenProvider": "AXERVE",
"CardDetails": {
"CardSuffix": "3101",
"CardExpiryMonth": "05",
"CardExpiryYear": "27",
"CardHolderName": null
},
"CardAssets": {
"CardArt": {
"Type": null,
"MediaContents": null,
"Height": null,
"Width": null
},
"BrandLogo": {
"Type": null,
"MediaContents": null,
"Height": null,
"Width": null
}
}
},
"fraudPrevention": {
"check": "FALSE",
"state": "",
"description": "",
"order": ""
},
"automaticOperation": {
"type": "CAN",
"date": "05/08/24 00:00:00",
"amount": "0"
}
}
}

Data to store for the Next transactions​

DataWhere to find itTypeUse in the Next transactions
paymentIDpayment/create response01F, 03FtransDetails.previousTransDetails.paymentID
tokenpayment/detail → payload.token, or the existing token used in the First01F, 03FpaymentTypeDetails.creditcard.token
authenticationAmountValue sent in the First01F, 03FMaximum amount that can be charged
expiryValue sent in the First01FDate after which no Next may be processed
frequencyValue sent in the First01FMinimum number of days between two Next transactions
paymentID

Fabrick returns the paymentID in the response to the payment/create call. If the transaction is successful, this value becomes the identifier to use as the reference for the Next transactions. To charge a different payment method, a new First must be processed.

Token management

For more information on managing the token, see the Tokenization section.


After the First: capture, refund and cancellation​

Once the First is completed and the required data stored, you can capture or refund the authorised amount.

CaseBehaviour
First with a €0.00 amount (ASI)The system does not allow cancellation: it would break the chain and prevent the Next transactions
First with an amount greater than zero and separated MOTODo not cancel the transaction through payment/cancel or the Dashboard. To refund the customer, capture the full amount and then process a refund: the chain remains active
Never cancel the First

Cancelling the First, through the payment/cancel API or the Dashboard, makes it impossible to process the Next transactions.


Next flow (MIT)​

Next transactions are the payments that follow the First and are processed on the basis of the authorisation given during the First. They are processed without the customer being present and do not require the payment page to be shown or any interaction on their part.

Next transactions are not processed automatically by Fabrick: the merchant must schedule, initiate and manage each charge, in accordance with the contractual agreements.

Same flow for card and wallets

The Next flow is identical for card, Apple Pay, Google Pay and Click to Pay: wallets are handled as cards, so in all cases the token obtained during the First is used, sent in the paymentTypeDetails.creditcard.token field.

Request fields​

CallFieldDescription
payment/createtransDetails.type01N for scheduled, 03N for unscheduled
payment/createtransDetails.previousTransDetails.paymentIDpaymentID of the First
payment/submitpaymentTypeDetails.creditcard.tokenToken obtained during the First
shopLogin of the First

The paymentID of the First is valid only on the shopLogin on which it was generated: a Next submitted on another shopLogin cannot be processed.

To collect the recurring payments on another shopLogin, you must generate a new authenticated First on the new shopLogin and use its paymentID for all the following Next transactions.

Step 1 — Creating the request​

Call payment/create on the server side, specifying the reference to the First.

Request

POST /api/v1/payment/create
Host (sandbox): sandbox.gestpay.net
Host (production): ecomms2s.sella.it
Authorization: apikey ****************
Content-Type: application/json
{
"shopLogin": "GESPAY12345",
"amount": "100",
"currency": "EUR",
"shopTransactionID": "FBK-C01N_OrderID",
"transDetails": {
"type": "01N",
"previousTransDetails": {
"paymentID": "1360119538182"
}
}
}

Response

{
"error": {
"code": "0",
"description": "request correctly processed"
},
"payload": {
"paymentToken": "7ebd948a-c9ad-44c9-ac43-02b0beb55a7a",
"paymentID": "1541109548247",
"userRedirect": null,
"qrCode": null
}
}

Step 2 — Sending the token​

Call payment/submit on the server side, sending the token obtained during the First. The request is the same for 01N and 03N.

Request

POST /api/v1/payment/submit
Host (sandbox): sandbox.gestpay.net
Host (production): ecomms2s.sella.it
PaymentToken: 7ebd948a-c9ad-44c9-ac43-02b0beb55a7a
Content-Type: application/json
{
"shopLogin": "GESPAY12345",
"paymentType": "CREDITCARD",
"paymentTypeDetails": {
"creditcard": {
"token": "40ZUU8NXALR33101"
}
}
}

Step 3 — Handling the response​

The outcome of the Next is returned immediately in the payment/submit response and, at the same time, through the S2S notification. You can optionally query the transaction with payment/detail: the response structure is the same as shown for the First.

Response

{
"error": {
"code": "0",
"description": "request correctly processed"
},
"payload": {
"transactionType": "submit",
"transactionResult": "OK",
"transactionErrorCode": "0",
"transactionErrorDescription": "Transaction correctly processed",
"bankTransactionID": "569",
"shopTransactionID": "FBK-C01N_OrderID",
"authorizationCode": "188190",
"paymentID": "1541109548247",
"currency": "EUR",
"country": "ITALIA",
"company": "VISA",
"productType": "Credit",
"userRedirect": {
"href": "https://sandbox.gestpay.net/pagam/AxerveThankYou.aspx"
}
}
}

Once the positive outcome is confirmed, you can capture or refund the transaction.