This guide is for current implementations. For legacy implementations see Recurring Payments (Legacy). There is also a migration guide at Migration to Secupay Acquiring.
Prerequisites
As a prerequisite, you should understand:
- secuconnect API Fundamentals
- Create the Smart Transaction
- Pay with Credit Card
- Pay with SEPA Direct Debit
You should also understand if you may have searched for Subscriptions.
Abstract
Your contract needs to be activated for recurring payments. Otherwise the subsequent payment with MIT cannot be authorised.
To use a credit card for recurring payments, you must:
- Make the first payment with a Customer Initiated Transaction (CIT). You must also request a Network Token, and record both Payment Container ID (PCT_…) and Payment Transaction ID (PCI_…).
- Make the subsequent payments as Merchant Initiated Transactions (MIT). You must also pass the recorded IDs at different stages of the process.
Subsequent Payments can be captured without customer interaction. The Strong Customer Authentication (SCA) by the Revised Payment Services Directive (PSD2) is omitted.
To make recurring payments with direct debit, you only need to record the Payment Container ID and pass it back later.
The following examples are for the more compley case of repeated credit card payments. For direct debit please disregard everything special except storing and using the Payment Conatiner ID.
Make the Initial Payment
Create the Smart Transaction
When you make the first payment, you must add the needed "mit_instructions" and "container_instructions" to the "payment_context" when you create the Smart Transaction. The first payment is made with customer interaction, and thus called and regulated a Customer-Initiated Transaction (CIT).
There are these two cases:
- Scheduled: A series of recurring payments with a fixed amount and frequency, such as a subscription service.
- Unscheduled: A series of irregular transactions using stored card details, such as an automatic account top-up or a rideshare fee. Often this is referred to as Unscheduled Card On File, or for short UCOF.
For the API integration, this makes only a difference for the first payment.
First an example for unscheduled recurring payments:
POST /api/v2/Smart/Transactions HTTP/1.1Host: connect-testing.secuconnect.comAuthorization: Bearer qb56tjj1bcvo9n2nj4u38k84loContent-Type: application/jsonAccept: application/json{ "contract": { "id": "GCR_KTSST836QYITQJM1JGYIZ4F4OLKI04" }, "customer": { "contact": { "company_name": "Musterfirma GmbH" "forename": "Max", "surname": "Mustermann", "address": { "street": "Musterallee", "street_number": "23-25", "postal_code": "09005", "city": "Musterstadt", "country": "DE" }, "email": "m.muster@example.net", "mobile": "+491775555555", "phone": "+495555555555" } }, "transactionRef": "Bestellung am 25.02.2026 bei ACME Buero-Paradies auf Example.com", "merchantRef": "20000345", "basket": { "products": [ { "id": 1, "articleNumber": 30037, "ean": "4999012345678", "desc": "Druckerpapier Eco A4 80g", "quantity": 10, "priceOne": 7900, "tax": 19 }, { "id": 2, "item_type": "shipping", "desc": "Versand Spedition", "quantity": 1, "priceOne": 500, "tax": 19 } ] }, "basket_info": { "sum": 8400, "currency": "EUR" }, "payment_context": { "auto_capture": true, "dynamic_descriptor": { "merchant_name": "ACME Buero-Paradies", "merchant_city": "Bielefeld" }, "mit_instructions": { "type": "cit", "standing_instruction": "ucof" }, "container_instructions": { "request_token": true, "notification_url": "https://shop.example.com/network-token/update?orderid=12345" } }}Please note the elements "mit_instructions" and "container_instructions" inside "payment_context" at line 66 .. 75.
Now the same example with only the necessary or changed fields for scheduled recurring payments:
POST /api/v2/Smart/Transactions HTTP/1.1Host: connect-testing.secuconnect.comAuthorization: Bearer qb56tjj1bcvo9n2nj4u38k84loContent-Type: application/jsonAccept: application/json{ // ... "payment_context": { // ... "mit_instructions": { "type": "cit", "standing_instruction": "recurring", "recurring_expiry": "2029-07-31", "recurring_frequency": "30" }, "container_instructions": { "request_token": true, "notification_url": "https://shop.example.com/network-token/update?orderid=12345" } }}If everything is fine, the API responds with 200 OK and the created Smart Transaction.
Details of the related fields:
Field | Type | Meaning |
|---|---|---|
| object | Instructions for MIT transactions needed when making the payment in the next step. |
| object | Instructions considered when creating the Payment Container in the next step. |
Details of "mit_instructions":
Field | Type | Meaning |
|---|---|---|
| string | Marks a transaction as the Customer-Initiated Transaction ( |
| string | Tells whether there is a fix or flexible standing transaction:
|
| string | ISO-8601 date; expiry date for the card Note: Please consider more reasons for it to become invalidated |
| string | Frequency of the subsequent payments in days |
Details of "container_instructions":
Field | Type | Meaning |
|---|---|---|
| boolean | Requests to save the credit card reference securely on the servers of a credit card network like VISA or MasterCard (“Network Token“) |
| string | Callback URL on your server for status updates for the Payment Container related to the Network Token |
Authorise and Capture the Payment
Imagine you have authorised the Smart Transaction for the first order by using this call, for example:
POST /api/v2/Smart/Transactions/STX_3Z8EUQX0A2PBHRJV9FRY7P56GEDZAK/prepare/creditcard HTTP/1.1Host: connect-testing.secuconnect.comAuthorization: Bearer qb56tjj1bcvo9n2nj4u38k84loContent-Type: application/jsonAccept: application/json{ "container": { "type": "credit_card", "private": { "owner": "Max Mustermann", "pan": "463544XXXXXX2298", "expiration_date": "2034-02-01T00:00:00+00:00", "issuer": "VISA", "transact_container": "MzkzOTQ0MGI1YTBmMDg2ZDkxYTEwNzIyZTMwNTgwNGZjYTU3...", "transact_skey_pubkey": "8ebccbb725d89d6286f227e672f24155e8b50b9688e7a45b...", "transact_skey_keyname": "spp_2025.pem", "transact_hash": "671439c1a91466df0249d8ab1b3595b682def08b1aea05a2d66e6adcf3d37a98" } }, "callback_urls": { "success_url": "https://shop.example.com/payment/success?nonce=ciix8j3qbqffg8dcdc7b", "failure_url": "https://shop.example.com/payment/failure?nonce=ciix8j3qbqffg8dcdc7b" }}If everything was fine, the API would have responded with something with 200 OK and the updated Smart Transaction:
HTTP/1.1 200 OKContent-Type: application/json{ "object": "smart.transactions", "id": "STX_3Z8EUQX0A2PBHRJV9FRY7P56GEDZAK", // ... "container": { "object": "payment.containers", "id": "PCT_3JU4VGYZF2XY8EJHH9FQ7WGYNZGJA4", "type": "credit_card" // ... "token_status": { "status": "requested", // ... }, "transactions": [ { "object": "payment.transactions", "id": "PCI_W026W643US3TWCGZA0AVZ248W8TSMW", "trans_id": 123456789, "transaction_hash": "abcdefghijkl12345678" } ], "created": "2025-02-25T15:55:58+01:00", "updated": "2025-02-25T15:56:16+01:00", "status": "created", // ... "payment_method": "creditcard", "trans_id": 123456789, "iframe_url": "https://connect-testing.secuconnect.com/spp/challenge/?token=5ab8b08...", // ...}For direct debit it would look similar but there is no 3-D Secure, and thus no iframe_url. Credit card payments require a 3-D Secure check if not exempted. So the iframe_url may be present or not. If auto_capture is set, the payment would be captured immediately after successful authorisation.
Please note the fields with the Payment Container ID (container.id) and the Payment Transaction ID (transactions[0].id). (If there is more than one transaction, please use first one.)
In case of credit card payment, you need to save both IDs in relation to your customer account. You would also need to manage the life cycle of the Payment Container ID.
In case of direct debit, you only need to save the Payment Container ID.
Handle Failed Token Request upon Initial Payment
When you authorise (and perhaps auto-capture) the first payment, the payment may succeed whilst the Network Token request would fail. In this case the Payment Container details would be useless, and standing order or subscription would not work.
Please take these considerations into account:
- The Network Token creation might fail from the beginning
- The Network Token might be invalidated later for a number of reasons (token expiry, card not renewed, etc.)
You must handle this situation.
One way to split the initial payment, or that for a token renewal, from the order, is to make a credit card authorisation with an amount of zero.
Imagine this authorisation request:
POST /api/v2/Smart/Transactions/STX_3Z8EUQX0A2PBHRJV9FRY7P56GEDZAK/prepare/creditcard HTTP/1.1Host: connect-testing.secuconnect.comAuthorization: Bearer qb56tjj1bcvo9n2nj4u38k84loContent-Type: application/jsonAccept: application/json{ "container": { "type": "credit_card", "private": { "owner": "Max Mustermann", "pan": "463544XXXXXX2298", "expiration_date": "2034-02-01T00:00:00+00:00", "issuer": "VISA", "transact_container": "MzkzOTQ0MGI1YTBmMDg2ZDkxYTEwNzIyZTMwNTgwNGZjYTU3...", "transact_skey_pubkey": "8ebccbb725d89d6286f227e672f24155e8b50b9688e7a45b...", "transact_skey_keyname": "spp_2025.pem", "transact_hash": "671439c1a91466df0249d8ab1b3595b682def08b1aea05a2d66e6adcf3d37a98" } }, "callback_urls": { "success_url": "https://shop.example.com/payment/success?nonce=ciix8j3qbqffg8dcdc7b", "failure_url": "https://shop.example.com/payment/failure?nonce=ciix8j3qbqffg8dcdc7b" }}In this case the API might respond with 200 OK and the updated Smart Transaction like this:
HTTP/1.1 200 OKContent-Type: application/json{ "object": "smart.transactions", "id": "STX_3Z8EUQX0A2PBHRJV9FRY7P56GEDZAK", // ... "container": { "object": "payment.containers", "id": "PCT_3JU4VGYZF2XY8EJHH9FQ7WGYNZGJA4", "type": "credit_card", // ... "token_status": { "status": "failed", // ... } }, "transactions": [ { "object": "payment.transactions", "id": "PCI_W026W643US3TWCGZA0AVZ248W8TSMW", "trans_id": 123456789, "transaction_hash": "abcdefghijkl12345678" } ], "created": "2025-02-25T15:55:58+01:00", "updated": "2025-02-25T15:56:16+01:00", "status": "created", // ... "payment_method": "creditcard", "trans_id": 123456789, "iframe_url": "https://connect-testing.secuconnect.com/spp/challenge/?token=5ab8b08...", // ...}Please note container.token_status.status being "failed" (line 14).
In this case don't save the Payment Container details, and manage the situation.
Make the Subsequent Payments
Create the Smart Transaction
When you make later payments, you must also add different "mit_instructions" to the "payment_context" when you create the Smart Transaction:
POST /api/v2/Smart/Transactions HTTP/1.1Host: connect-testing.secuconnect.comAuthorization: Bearer qb56tjj1bcvo9n2nj4u38k84loContent-Type: application/jsonAccept: application/json{ "contract": { "id": "GCR_KTSST836QYITQJM1JGYIZ4F4OLKI04" }, "customer": { "contact": { "company_name": "Musterfirma GmbH" "forename": "Max", "surname": "Mustermann", "address": { "street": "Musterallee", "street_number": "23-25", "postal_code": "09005", "city": "Musterstadt", "country": "DE" }, "email": "m.muster@example.net", "mobile": "+491775555555", "phone": "+495555555555" } }, "transactionRef": "Nachlieferung am 10.05.2026 bei ACME Buero-Paradies auf Example.com", "merchantRef": "20000456", "basket": { "products": [ { "id": 1, "articleNumber": 30037, "ean": "4999012345678", "desc": "Druckerpapier Eco A4 80g", "quantity": 8, "priceOne": 6380, "tax": 19 }, { "id": 2, "item_type": "shipping", "desc": "Versand Spedition", "quantity": 1, "priceOne": 500, "tax": 19 } ] }, "basket_info": { "sum": 6880, "currency": "EUR" }, "payment_context": { "auto_capture": true, "dynamic_descriptor": { "merchant_name": "ACME Buero-Paradies", "merchant_city": "Bielefeld" }, "mit_instructions": { "type": "mit", "cit_reference": "PCI_6UKN8UE29BH6EKF42JS6325AG34WMY" } }}If everything is fine, the API responds with 200 OK and the created Smart Transaction.
Please note the following different elements inside "mit_instructions" at line 66 .. 70:
Field | Type | Meaning |
|---|---|---|
type | string | MIT transactions ( |
cit_reference | string | Payment Transaction ID (PCI_…) of the first payment |
The other object "container_instructions" is no longer needed.
If everything is fine, the API responds with 200 OK and the created Smart Transaction. There is nothing special in the responded Smart Transaction.
Authorise and Capture the Payment
With the call to authorise the payment, you would pass the Payment Container ID only instead of all the details:
POST /api/v2/Smart/Transactions/STX_HUXEQ5X302PBHTEYWP66F9AX0N44A4/prepare/creditcard HTTP/1.1Host: connect-testing.secuconnect.comAuthorization: Bearer qb56tjj1bcvo9n2nj4u38k84loContent-Type: application/jsonAccept: application/json{ "container": { "id": "PCT_3JU4VGYZF2XY8EJHH9FQ7WGYNZGJA4", }, "callback_urls": { "success_url": "https://shop.example.com/payment/success?nonce=ciix8j3qbqffg8dcdc7b", "failure_url": "https://shop.example.com/payment/failure?nonce=ciix8j3qbqffg8dcdc7b" }}If everything is fine, the API responds again with 200 OK and the updated Smart Transaction:
HTTP/1.1 200 OKContent-Type: application/json{ "object": "smart.transactions", "id": "STX_HUXEQ5X302PBHTEYWP66F9AX0N44A4", // ... "container": { "object": "payment.containers", "id": "PCT_3JU4VGYZF2XY8EJHH9FQ7WGYNZGJA4", "type": "credit_card" // ... "token_status": { "status": "active", // ... } }, "transactions": [ { "object": "payment.transactions", "id": "PCI_54UPYB6SGWC7PQCBXHX99248W8UWMJ", "trans_id": 123456791, "transaction_hash": "bcdefghijklm223456789" } ], "created": "2026-05-10T16:58:34+01:00", "updated": "2026-05-10T17:00:40+01:00", "status": "ok", // ... "payment_method": "creditcard", "trans_id": 123456791, // ...}The payment is authorised or already captured (if accompanied by the auto_capture flag). Please check the payment status.
Network Token Lifecycle
Manage Status Changes of the Network Token
Beginning with our new acquiring solution, we will also start to send push notifications for Network Token status changes. This can be used to activate or to remove the Payment Container. The push notification is sent for the Payment Container holding the Network Token.
All details are found here: Network Token Status Notifications
Archiving the Network Token
Beginning with our new acquiring solution, you can request the deletion or archiving the network token.
All details are found here: Archiving the Network Token