PaymentsCard processingRecurring

How to process a recurring card payment

This how-to guide will show you how to successfully process recurring payments with a registered card.

Prerequisites

  • A ClientId and an API key – if you don’t have these, contact Sales to get access to the Mangopay Dashboard
  • A User object created for your end user, and their associated Wallet
  • A registered card (Visa, Mastercard, CB, or AMEX), which is VALID or registered less than 24 hours ago, to make the payments

Setting up a recurring card payment is necessary when the platform repeatedly charges the end user at regular intervals, such as in subscription models or payments in installments.

A recurring card payment has two phases:

  • Customer-initiated transaction (CIT) - An initial transaction in the presence of the cardholder, for which SCA is required.
  • Merchant-initiated transactions (MIT) - Subsequent transactions made in the absence of the cardholder, initiated by the platform (and not subject to SCA unless required by the issuer)
Learn more about recurring card payments

1. Create the Recurring PayIn Registration

The Recurring PayIn Registration object will define key information about the recurring payments such as:

  • The start and end date, as well as the frequency
  • Whether the amount is the same for each payment
  • Whether you want to offer zero-amount payments to your end user at the start of the recurrence (for example, during trial subscription offers)

For this guide, we’ll define a fixed monthly amount but not provide an end date.

POST /v2.01/{ClientId}/recurringpayinregistrations

In the response, you will need the Id of the Recurring PayIn Registration for the next steps.

1{
2 "Id": "recpayinreg_m_01JJP2KS2A47A0P7S7CEBQPHT9",
3 "Status": "CREATED",
4 "ResultCode": null,
5 "ResultMessage": null,
6 "CurrentState": {
7 "PayinsLinked": 0,
8 "CumulatedDebitedAmount": {
9 "Currency": "EUR",
10 "Amount": 0
11 },
12 "CumulatedFeesAmount": {
13 "Currency": "EUR",
14 "Amount": 0
15 },
16 "LastPayinId": null
17 },
18 "RecurringType": "CUSTOM",
19 "TotalAmount": null,
20 "CycleNumber": null,
21 "AuthorId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
22 "CardId": "card_m_UsklnOoXBWyyqhsN",
23 "CreditedUserId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
24 "CreditedWalletId": "wlt_m_01JJ70WZ9JRAZ9GE0DA36Q84NQ",
25 "Billing": {
26 "FirstName": "Alex",
27 "LastName": "Smith",
28 "Address": {
29 "AddressLine1": "6 rue de la Cité",
30 "AddressLine2": "Appartement 3",
31 "City": "Paris",
32 "Region": "île-de-France",
33 "PostalCode": "75003",
34 "Country": "FR"
35 }
36 },
37 "Shipping": {
38 "FirstName": "Alex",
39 "LastName": "Smith",
40 "Address": {
41 "AddressLine1": "6 rue de la Cité",
42 "AddressLine2": "Appartement 3",
43 "City": "Paris",
44 "Region": "île-de-France",
45 "PostalCode": "75003",
46 "Country": "FR"
47 }
48 },
49 "EndDate": null,
50 "Frequency": "Monthly",
51 "FixedNextAmount": true,
52 "FractionedPayment": false,
53 "FreeCycles": 0,
54 "FirstTransactionDebitedFunds": {
55 "Currency": "EUR",
56 "Amount": 10000
57 },
58 "FirstTransactionFees": {
59 "Currency": "EUR",
60 "Amount": 500
61 },
62 "NextTransactionDebitedFunds": null,
63 "NextTransactionFees": null,
64 "Migration": false,
65 "PaymentType": "CARD_DIRECT"
66}

2. Process the first recurring payment (CIT)

Make the request

Request the first payment, linking it to the registration object by using the Id returned in the previous step as the RecurringPayinRegistrationId.

In our example, the first transaction amounts have been defined at the registration level. Because of this, we don’t need to define the DebitedFunds or Fees at the pay-in level.

POST /v2.01/{ClientId}/payins/recurring/card/direct


1{
2 "Id": "payin_m_01JJP2PDQWD7S2W42RR6S21VZE",
3 "Tag": "Created using Mangopay API Postman Collection",
4 "CreationDate": 1738055301,
5 "AuthorId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
6 "CreditedUserId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
7 "DebitedFunds": {
8 "Currency": "EUR",
9 "Amount": 10000
10 },
11 "CreditedFunds": {
12 "Currency": "EUR",
13 "Amount": 9500
14 },
15 "Fees": {
16 "Currency": "EUR",
17 "Amount": 500
18 },
19 "Status": "CREATED",
20 "ResultCode": null,
21 "ResultMessage": null,
22 "ExecutionDate": null,
23 "Type": "PAYIN",
24 "Nature": "REGULAR",
25 "CreditedWalletId": "wlt_m_01JJ70WZ9JRAZ9GE0DA36Q84NQ",
26 "DebitedWalletId": null,
27 "PaymentType": "CARD",
28 "ExecutionType": "DIRECT",
29 "SecureMode": null,
30 "CardId": "card_m_UsklnOoXBWyyqhsN",
31 "SecureModeReturnURL": "https://example.com/?transactionId=payin_m_01JJP2PDQWD7S2W42RR6S21VZE",
32 "SecureModeRedirectURL": "https://api.sandbox.whenthen.co/payment-gateway/whenthen/threeDS/54b0c206-0a67-43d4-ace6-14a25697cf85/challenge?id=d7a9a1dd-80aa-4252-b2b4-221e1898d67f&url=aHR0cHM6Ly9hcGkuc2FuZGJveC53aGVudGhlbi5jby9wYXltZW50cy8zRFNlY3VyZS81NGIwYzIwNi0wYTY3LTQzZDQtYWNlNi0xNGEyNTY5N2NmODUvYzA1YTBhYzktNjBmZC00NDQyLWEzYzAtYjlmOTVlN2I1ODk5&amount=MzMzNDE&currency=RVVS",
33 "SecureModeNeeded": true,
34 "Culture": "EN",
35 "SecurityInfo": {
36 "AVSResult": "NO_CHECK"
37 },
38 "StatementDescriptor": "Example123",
39 "BrowserInfo": {
40 "AcceptHeader": "text/html, application/xhtml+xml, application/xml;q=0.9, /;q=0.8",
41 "JavaEnabled": true,
42 "Language": "FR-FR",
43 "ColorDepth": 4,
44 "ScreenHeight": 1800,
45 "ScreenWidth": 400,
46 "TimeZoneOffset": 60,
47 "UserAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
48 "JavascriptEnabled": true
49 },
50 "IpAddress": "3a55:f45c:d44e:ff6a:c63b:f2ec:3a31:eb3e",
51 "Billing": {
52 "FirstName": "Alex",
53 "LastName": "Smith",
54 "Address": {
55 "AddressLine1": "6 rue de la Cité",
56 "AddressLine2": "Appartement 3",
57 "City": "Paris",
58 "Region": "île-de-France",
59 "PostalCode": "75003",
60 "Country": "FR"
61 }
62 },
63 "Shipping": {
64 "FirstName": "Alex",
65 "LastName": "Smith",
66 "Address": {
67 "AddressLine1": "6 rue de la Cité",
68 "AddressLine2": "Appartement 3",
69 "City": "Paris",
70 "Region": "île-de-France",
71 "PostalCode": "75003",
72 "Country": "FR"
73 }
74 },
75 "Requested3DSVersion": null,
76 "Applied3DSVersion": "V2_1",
77 "RecurringPayinRegistrationId": "recpayinreg_m_01JJP2KS2A47A0P7S7CEBQPHT9",
78 "PreferredCardNetwork": "MASTERCARD",
79 "CardInfo": {
80 "BIN": "497010",
81 "IssuingBank": "LA BANQUE POSTALE",
82 "IssuerCountryCode": "MA",
83 "Type": "CREDIT",
84 "Brand": "MASTERCARD",
85 "SubType": null
86 }
87}

Redirect the user to 3DS protocol

The CIT transaction always requires 3DS (the SecureModeNeeded value is set to true), so you need to redirect the end user to the SecureModeRedirectURL value to complete the authentication.

For more information on how to handle 3DS redirection, see Steps 6 and 7 of the How to process a card payment guide.

3. Process the subsequent recurring payments (MIT) at the defined intervals

Once the first pay-in has been successfully authorized, the platform can initiate payments without the end user being present to authenticate (but note that, at any time, the issuer may request SCA - see Step 5).

Create the recurring pay-in at the set interval with the dedicated endpoint. Note that in our example, we didn’t define the next transaction amounts at the registration level. As a consequence, we need to pass the DebitedFunds and Fees parameters at the pay-in level.

POST /v2.01/{ClientId}/payins/recurring/card/direct


200
1{
2 "Id": "payin_m_01JJP59QGFVTMF9Y6YP0K3DXR0",
3 "Tag": "Created using Mangopay API Postman Collection",
4 "CreationDate": 1738058031,
5 "AuthorId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
6 "CreditedUserId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
7 "DebitedFunds": {
8 "Currency": "EUR",
9 "Amount": 10000
10 },
11 "CreditedFunds": {
12 "Currency": "EUR",
13 "Amount": 9500
14 },
15 "Fees": {
16 "Currency": "EUR",
17 "Amount": 500
18 },
19 "Status": "SUCCEEDED",
20 "ResultCode": "000000",
21 "ResultMessage": "Success",
22 "ExecutionDate": 1738058032,
23 "Type": "PAYIN",
24 "Nature": "REGULAR",
25 "CreditedWalletId": "wlt_m_01JJ70WZ9JRAZ9GE0DA36Q84NQ",
26 "DebitedWalletId": null,
27 "PaymentType": "CARD",
28 "ExecutionType": "DIRECT",
29 "SecureMode": null,
30 "CardId": "card_m_UsklnOoXBWyyqhsN",
31 "SecureModeReturnURL": null,
32 "SecureModeRedirectURL": null,
33 "SecureModeNeeded": false,
34 "Culture": "EN",
35 "SecurityInfo": {
36 "AVSResult": "NO_CHECK"
37 },
38 "StatementDescriptor": "Example123",
39 "BrowserInfo": null,
40 "IpAddress": null,
41 "Billing": {
42 "FirstName": "Alex",
43 "LastName": "Smith",
44 "Address": {
45 "AddressLine1": "6 rue de la Cité",
46 "AddressLine2": "Appartement 3",
47 "City": "Paris",
48 "Region": "île-de-France",
49 "PostalCode": "75003",
50 "Country": "FR"
51 }
52 },
53 "Shipping": {
54 "FirstName": "Alex",
55 "LastName": "Smith",
56 "Address": {
57 "AddressLine1": "6 rue de la Cité",
58 "AddressLine2": "Appartement 3",
59 "City": "Paris",
60 "Region": "île-de-France",
61 "PostalCode": "75003",
62 "Country": "FR"
63 }
64 },
65 "Requested3DSVersion": null,
66 "Applied3DSVersion": "V2_1",
67 "RecurringPayinRegistrationId": "recpayinreg_m_01JJP2KS2A47A0P7S7CEBQPHT9",
68 "PreferredCardNetwork": "MASTERCARD",
69 "CardInfo": {
70 "BIN": "497010",
71 "IssuingBank": "LA BANQUE POSTALE",
72 "IssuerCountryCode": "MA",
73 "Type": "CREDIT",
74 "Brand": "MASTERCARD",
75 "SubType": null
76 }
77}

4. Update the registration (if required)

Some information regarding the recurring registration may be modified during the recurrence:

  • CardId - Changing this will require a new CIT for SCA
  • Billing and Shipping

Use the PUT Update a Recurring PayIn Registration endpoint to modify these details.

5. Handle re-authentication (when required)

At any moment during the recurrence, the issuer may request that the end user authenticates again. This also occurs when changing the CardId in the Recurring PayIn Registration (see Step 4).

The need for re-authentication is indicated by the registration object’s Status changing to AUTHENTICATION_NEEDED.

You can be notified of this by setting up webhook notifications for the following event type:

  • RECURRING_REGISTRATION_AUTH_NEEDED

In this case, you need to guide the end user through authentication during a new CIT in the same way as Step 2.

6. Check the recurring payments’ current state

The CurrentState of the Recurring PayIn Registration provides key information about the recurring payments:

  • Number of pay-ins made against the registration
  • Cumulated amounts of debited funds and fees
  • Last pay-in made against the registration

Use the GET View a Recurring PayIn Registration endpoint to get this information.

GET /v2.01/{ClientId}/recurringpayinregistrations/{RecurringPayinRegistrationId}


API response
1{
2 "Id": "recpayinreg_m_01JJP2KS2A47A0P7S7CEBQPHT9",
3 "Status": "IN_PROGRESS",
4 "ResultCode": null,
5 "ResultMessage": null,
6 "CurrentState": {
7 "PayinsLinked": 2,
8 "CumulatedDebitedAmount": {
9 "Currency": "EUR",
10 "Amount": 20000
11 },
12 "CumulatedFeesAmount": {
13 "Currency": "EUR",
14 "Amount": 1000
15 },
16 "LastPayinId": "payin_m_01JJP59QGFVTMF9Y6YP0K3DXR0"
17 },
18 "RecurringType": "CUSTOM",
19 "TotalAmount": null,
20 "CycleNumber": null,
21 "AuthorId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
22 "CardId": "card_m_UsklnOoXBWyyqhsN",
23 "CreditedUserId": "user_m_01JHX34N3Y9BCQP7KR9QWWETDQ",
24 "CreditedWalletId": "wlt_m_01JJ70WZ9JRAZ9GE0DA36Q84NQ",
25 "Billing": {
26 "FirstName": "Alex",
27 "LastName": "Smith",
28 "Address": {
29 "AddressLine1": "6 rue de la Cité",
30 "AddressLine2": "Appartement 3",
31 "City": "Paris",
32 "Region": "île-de-France",
33 "PostalCode": "75003",
34 "Country": "FR"
35 }
36 },
37 "Shipping": {
38 "FirstName": "Alex",
39 "LastName": "Smith",
40 "Address": {
41 "AddressLine1": "6 rue de la Cité",
42 "AddressLine2": "Appartement 3",
43 "City": "Paris",
44 "Region": "île-de-France",
45 "PostalCode": "75003",
46 "Country": "FR"
47 }
48 },
49 "EndDate": null,
50 "Frequency": "Monthly",
51 "FixedNextAmount": true,
52 "FractionedPayment": false,
53 "FreeCycles": 0,
54 "FirstTransactionDebitedFunds": {
55 "Currency": "EUR",
56 "Amount": 10000
57 },
58 "FirstTransactionFees": {
59 "Currency": "EUR",
60 "Amount": 500
61 },
62 "NextTransactionDebitedFunds": null,
63 "NextTransactionFees": null,
64 "Migration": false,
65 "PaymentType": "CARD_DIRECT"
66}

7. End the recurring payments

Recurring payments may come to an end either automatically (when an EndDate was defined) or because the end user requests it.

To end the recurring payments manually, use the Update a Recurring Registration endpoint to change the Status to ENDED.

PUT /v2.01/{ClientId}/recurringpayinregistrations/{RecurringPayinRegistrationId}

REST
1{
2 "Status": "ENDED"
3}

When you do this, no more recurring pay-ins can be created based on the registration.

Set up webhook notifications for the following event type to be notified when a registration is ended (for example, by the end user):

  • RECURRING_REGISTRATION_ENDED