Enrolling a customer with SlimPay checkout
SlimPay’s Checkout solution offers merchants a frictionless and intuitive payment experience for their customers. Clients can be enrolled through a seamless payment journey, where SEPA mandate signatures can be obtained and payments can be collected in a single transaction.
This step-by-step guide will show you how to enroll a customer for direct debit payments by signing a SEPA mandate using our Checkout solution. This involves creating the Checkout transaction, displaying the Checkout to the customer and informing you as the merchant when the transaction is completed.
Please note
This guide does not cover the basics of API authentication or the format of requests and responses. Please review these sections if you are unfamiliar with these concepts.
All of the code examples in our guides are written in PHP and are based on our HAPI Client, developed by SlimPay to reduce the code complexity of interfacing with our API. Please refer to our HTTP client page for more details on using these libraries.
Step 1: Create the Checkout transaction
To enroll a customer for SEPA direct debits, you will need to have at a minimum:
- your creditor reference
- the reference of your subscriber
- the customer's data
You also need to know the payment scheme you intend to use for this customer. If you’re not sure what that is, you probably need to use SEPA Direct Debit CORE.
All the data you provide must conform to the constraints outlined in our comprehensive #create-order in API reference.
With these parameters, you create the Checkout transaction through the create-orders relation available at the API entry point, using the orders and order items (of type signMandate and/or document) resources. Below is an example of the create-orders API call body for signing a mandate and a document (we can also sign a mandate only or a document only) :
The property userApprovalMode specify the approval mode to use. This property accepts
POPIN, IFRAME or API.
For redirection mode, please use POPIN or don't specify this
field
Example for popin
{
"started": 1,
"paymentScheme": "SEPA.DIRECT_DEBIT.CORE",
"userApprovalMode": "popin",
"otpChannelType": "sms",
"creditor": {
"reference": "{{creditor-reference}}"
},
"subscriber": {
"reference": "{{creditor-reference}}"
},
"items": [
{
"type": "signMandate",
"signatureApproval": {
"paymentProcessor": "slimpay",
"method": {
"type": "otp"
}
},
"mandate": {
"signatory": {
"honorificPrefix": "Mr",
"familyName": "Doe",
"givenName": "John",
"telephone": "{{tel}}",
"email": "{{email}}",
"billingAddress": {
"street1": "27 rue des fleurs",
"street2": "Bat 2",
"postalCode": "75008",
"city": "Paris",
"country": "FR"
},
"bankAccount": {
"iban": "{{iban}}"
}
}
}
},
{
"type": "document",
"document": {
"signatory": {
"honorificPrefix": "Mr",
"familyName": "Doe",
"givenName": "John",
"telephone":"{{tel}}",
"email": "{{email}}",
"billingAddress": {
"street1": "27 rue des fleurs",
"street2": "Bat 2",
"postalCode": "75008",
"city": "Paris",
"country": "FR"
}
},
"binaryContent": {
"content": "JVBERi0xLjQKJeLjz9MKNCAwIG9iago8PC9NSzw8L0JDWzEgMSAxXS9CR1sxIDEgMV0+Pi9GIDQvVHlwZS9Bbm5vdC9TdWJ0eXBlL1dpZGdldC9SZWN0WzIwMCA2MzIgMTQ0IDc4MF0vRlQvU2lnL0RSPDw+Pi9UKFNpZ25hdHVyZURlYnRvcikvQVA8PC9OIDIgMCBSPj4vUCAxIDAgUj4+CmVuZG9iago1IDAgb2JqCjw8L0xlbmd0aCA4Mi9GaWx0ZXIvRmxhdGVEZWNvZGU+PnN0cmVhbQp4nCvkcgrhMjZTsDAwUwhJ4TJQ0DW0ADH03QwVDI0UQtK4NHwT81ISSxRSUhVKUotLNEOygKoMUBRrBGem5yWWlBalWikgybuGcAVyAQBzAxfgCmVuZHN0cmVhbQplbmRvYmoKMSAwIG9iago8PC9QYXJlbnQgNiAwIFIvQ29udGVudHMgNSAwIFIvVHlwZS9QYWdlL1Jlc291cmNlczw8L1Byb2NTZXQgWy9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUldL0ZvbnQ8PC9GMSAzIDAgUj4+Pj4vTWVkaWFCb3hbMCAwIDU5NSA4NDJdL0Fubm90c1s0IDAgUl0+PgplbmRvYmoKMyAwIG9iago8PC9CYXNlRm9udC9IZWx2ZXRpY2EvVHlwZS9Gb250L0VuY29kaW5nL1dpbkFuc2lFbmNvZGluZy9TdWJ0eXBlL1R5cGUxPj4KZW5kb2JqCjIgMCBvYmoKPDwvVHlwZS9YT2JqZWN0L1Jlc291cmNlczw8L1Byb2NTZXQgWy9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUldPj4vU3VidHlwZS9Gb3JtL0JCb3hbMCAwIDcyIDQ4XS9NYXRyaXggWzEgMCAwIDEgMCAwXS9MZW5ndGggMjYvRm9ybVR5cGUgMS9GaWx0ZXIvRmxhdGVEZWNvZGU+PnN0cmVhbQp4nDPQM1UwAGJzQyBhYg4kilIVghUANCwEqgplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwvVHlwZS9QYWdlcy9Db3VudCAxL0tpZHNbMSAwIFJdPj4KZW5kb2JqCjcgMCBvYmoKPDwvRmllbGRzWzQgMCBSXS9EQSgvSGVsdiAwIFRmIDAgZyApL0RSPDw+Pj4+CmVuZG9iago4IDAgb2JqCjw8L1R5cGUvQ2F0YWxvZy9BY3JvRm9ybSA3IDAgUi9QYWdlcyA2IDAgUj4+CmVuZG9iago5IDAgb2JqCjw8L1Byb2R1Y2VyKGlUZXh0riA1LjQuMSCpMjAwMC0yMDEyIDFUM1hUIEJWQkEgXChBR1BMLXZlcnNpb25cKSkvTW9kRGF0ZShEOjIwMTUwNzIzMTEzMjAxKzAyJzAwJykvQ3JlYXRpb25EYXRlKEQ6MjAxNTA3MjMxMTMyMDErMDInMDAnKT4+CmVuZG9iagp4cmVmCjAgMTAKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMzE4IDAwMDAwIG4gCjAwMDAwMDA1NzcgMDAwMDAgbiAKMDAwMDAwMDQ4OSAwMDAwMCBuIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDAxNzAgMDAwMDAgbiAKMDAwMDAwMDgwMiAwMDAwMCBuIAowMDAwMDAwODUzIDAwMDAwIG4gCjAwMDAwMDA5MTQgMDAwMDAgbiAKMDAwMDAwMDk3NCAwMDAwMCBuIAp0cmFpbGVyCjw8L1Jvb3QgOCAwIFIvSUQgWzw0NjJjYWU2OGMzYWMyNTI4ZWI2NjI0YWYxOWM2N2ZiZj48OTUwZGIzYTllNDZhMGUwNTIwOTZhMmJhZDc1OTk4OWY+XS9JbmZvIDkgMCBSL1NpemUgMTA+PgolaVRleHQtNS40LjEKc3RhcnR4cmVmCjExMjcKJSVFT0YK"
},
"label": "label-7631859"
}
}
]
}
The order returned by the SlimPay server should look something like this:
{
"_links": {
"self": {
"href": "https://api.preprod.slimpay.com/orders/dc13cc2c-4b4b-11ef-8bd2-000000000000"
},
"profile": {
"href": "https://api.preprod.slimpay.com/alps/v1/orders"
},
"https://api.slimpay.net/alps#get-creditor": {
"href": "https://api.preprod.slimpay.com/creditors/rmadridfc"
},
"https://api.slimpay.net/alps#get-subscriber": {
"href": "https://api.preprod.slimpay.com/orders/dc13cc2c-4b4b-11ef-8bd2-000000000000/subscriber"
},
"https://api.slimpay.net/alps#get-order-items": {
"href": "https://api.preprod.slimpay.com/orders/dc13cc2c-4b4b-11ef-8bd2-000000000000/order-items"
},
"https://api.slimpay.net/alps#user-approval": {
"href": "https://checkout.preprod.slimpay.com/userApproval?accessCode=spjFCLDmFMnHqvPO4oEUK8tMFSTE0MwsxxzUscwVENoao0708O3RxsYjRlftVI"
},
"https://api.slimpay.net/alps#extended-user-approval": {
"href": "https://api.preprod.slimpay.com/creditors/rmadridfc/orders/dc13cc2c-4b4b-11ef-8bd2-000000000000/extended-user-approval{?mode}",
"templated": true
},
"https://api.slimpay.net/alps#cancel-order": {
"href": "https://api.preprod.slimpay.com/orders/dc13cc2c-4b4b-11ef-8bd2-000000000000/cancellation"
}
},
"id": "dc13cc2c-4b4b-11ef-8bd2-000000000000",
"reference": "dc13cc2c-4b4b-11ef-8bd2-000000000000",
"state": "open.running",
"started": true,
"userApprovalMode": "popin",
"otpChannelType": "sms",
"sendUserApproval": false,
"registrationType": "signature",
"dateCreated": "2024-07-26T12:37:45.854+0000",
"dateStarted": "2024-07-26T12:37:45.854+0000",
"paymentScheme": "SEPA.DIRECT_DEBIT.CORE",
"checkoutActor": "end_user"
}
Then, for the redirection, it's the link within https://api.slimpay.net/alps#user-approval
Once the redirection is starter, several steps are needed :
Case OTP
- First, IBAN verification and validation
- Then, Phone verification and validation
- Then, OTP verification and validation
- Succeed (please note that signing is asynchronous, even if all succeed, the real signing
is confirmed only after receiving a notification)
Case Checkbox
- First, IBAN verification and validation
- Then, the checkbox needs to be checked
- Succeed (please note that signing is asynchronous, even if all succeed, the real signing
is confirmed only after receiving a notification)
Step 2: Display the Checkout to the user
At this stage, the customer is directed to the SlimPay Checkout where they will provide and confirm their bank account details and approve their use for recurring direct debits:
$url = $order->getLink('https://api.slimpay.net/alps#user-approval')->getHref();
header('Location: ' . $url);
exit;
An alternative to redirecting the customer to a URL is to embed an iframe into your own application or website, or use an iframe popin to display the Checkout to the user. SlimPay’s HAPI Client can take care of the implementation of this, all you need to do is decode the HTML using base 64.
$rel = new Hal\CustomRel('https://api.slimpay.net/alps#extended-user-approval');
$follow = new Http\Follow($rel, 'GET', [
'mode' => 'iframepopin' // Or iframeembedded
]);
$htmlCode = $hapiClient->sendFollow($follow, $order)->getState()['content'];
echo base64_decode($htmlCode);
The iframe popin will adapt to the size of the window, while an embedded iframe will take the size (width and height) of the parent container with a minimum of 320 pixels in height.
A further option is to send a link directing the customer to the SlimPay Checkout in a fully-customisable email. This link is valid for a period of 60 days, during which time a customer can click on the link up to five times to complete the Checkout process. Each time the customer clicks on the link, the Checkout session is active for 30 minutes.
At this stage, it is now up to the customer to complete or cancel the Checkout process.
Step 3: Be informed about the Checkout status
When a customer completes or cancels a Checkout transaction, a POST request is sent to your notification URL (if you provided one when configuring your app).
To retrieve the order in the notification URL, we need to decode the message body as a JSON object:
$body = file_get_contents('php://input');
$order = \HapiClient\Hal\Resource::fromJson($body);
Immediately after this synchronous notification ends, the customer can click on the continue button of the Checkout, which redirects them to the return URL (if you provided one when configuring your app).
To retrieve the order in the return URL, we must follow the get-orders relation using the order reference that was stored at the end of the first step:
$rel = new Hal\CustomRel('https://api.slimpay.net/alps#get-orders');
$follow = new Http\Follow($rel, 'GET', [
'creditorReference' => 'yourCreditorReference',
'reference' => 'theOrderReference'
]);
$order = $hapiClient->sendFollow($follow);
Please note: While the notification of the completed Checkout journey is synchronous, SlimPay employs an asynchronous signature process, offering merchants greater protection against failed signatures. As such, although you will receive the success notification as soon as the Checkout journey is validated, it may take a few seconds before a signed mandate is available to be retrieved using the get-mandate relation.
An alternative to configuring a returnURL is to configure a number of dynamic URLs for handling specific use cases. These include:
- a failureUrl, which is a web page a customer is redirected to following an order failure during Checkout
- a successUrl, which is a web page a customer is redirected to following a successful order during Checkout
- a cancelUrl, which is a web page a customer is redirected to following a cancelled order during Checkout
Further documentation on URL management can be found on the SlimPay Help Center.
Once we’ve retrieved the customer’s order (whether it was cancelled or completed), let’s
check its state
to trigger the appropriate action:
if (strpos($order->getState()['state'], 'closed.aborted') === 0) {
// The user did not complete the Checkout
// ... trigger some action(s) depending on your need
header('Location: failure-page.php');
exit;
} elseif (strpos($order->getState()['state'], 'closed.completed') === 0) {
// The user completed the Checkout successfully
// The mandate reference (needed to create payments)
$rel = new Hal\CustomRel('https://api.slimpay.net/alps#get-mandate');
$follow = new Http\Follow($rel);
$mandate = $hapiClient->sendFollow($follow, $order);
$mandateReference = $mandate->getState()['reference'];
// The mandate PDF file
$rel = new Hal\CustomRel('https://api.slimpay.net/alps#get-binary-content');
$follow = new Http\Follow($rel);
$binaryContent = $hapiClient->sendFollow($follow, $mandate);
$pdfContent = base64_decode($binaryContent->getState()['content']);
file_put_contents("mandate-$mandateReference.pdf", $pdfContent);
// The subscriber reference that you provided
$rel = new Hal\CustomRel('https://api.slimpay.net/alps#get-subscriber');
$follow = new Http\Follow($rel);
$subscriber = $hapiClient->sendFollow($follow, $order);
$subscriberReference = $subscriber->getState()['reference'];
// ... trigger some action(s) depending on your need
header('Location: success-page.php');
exit;
} else {
throw new Exception('Checkout is still open. State expected to be "closed".');
}
The example code above includes some suggestions for follow-up requests based on a successful transaction (like retrieving the signed mandate and its contents).
It’s important to store the mandate reference as it will be needed to create payments or to update the mandate with a new IBAN.
The most common order states include:
closed.complete
: the customer has completed a successful orderclosed.aborted.aborted_byclient
: the customer has abandoned the orderclosed.aborted.aborted_byserver
: the order was cancelled by the server
Sign By Link
SlimPay has a feature that allows merchants to email a link to their customers, where they can sign a SEPA mandate to authorize direct debit payments. By following this link, customers will be directed to the Checkout in order to provide and confirm their bank account details according to the process described above.
To make use of this feature via API, simply include the sendUserApproval property in the order resource, setting its value to true.
$rel = new Hal\CustomRel('https://api.slimpay.net/alps#create-orders');
$follow = new Http\Follow($rel, 'POST', null, new Http\JsonBody(
[
'started' => true,
'locale' => 'fr',
'paymentScheme' => 'SEPA.DIRECT_DEBIT.CORE',
'sendUserApproval' => true,
'creditor' => [
'reference' => 'yourCreditorReference'
],
'subscriber' => [
'reference' => 'theSubscriberReference'
],
'items' => [
[
// Your already existing order item of type signMandate
// As defined in the Setting Up Direct Debits guide
]
]
]
Remember to include the customer’s email address in the signatory object where the Checkout link will be sent.
Signing a SEPA mandate by link can also be accomplished using the Dashboard. Further documentation regarding signing by link via the Dashboard can be found on our Help Center. This documentation also describes how to sign mandates by delegation (for example, on the customer’s behalf following telephone orders).
Signing a SEPA mandate by link can also be accomplished using our File API. Dozens, hundreds or even thousands of new customers can be enrolled for direct debit payments in a single operation, by depositing a file into our SFTP server. Further documentation regarding signing by link via file can be found here.
Retrieving and managing SEPA mandates
Once a mandate has been signed and created, SlimPay allows merchants to retrieve the mandate in order to manage it (update the IBAN, revoke the mandate etc). To do this by API, you can follow the get-order relation available at the entry point, providing your creditor reference and the order reference as parameters. Then simply follow the get-mandate relation that is returned by the server.
Alternatively, you can follow the search-subscribers relation available at the entry point, providing your creditor reference and the subscriber reference as parameters. Then you can follow the get-mandate relation associated with the subscriber.
Lastly, you can retrieve the mandate directly by following the get-mandates relation available at the entry point, providing your creditor reference and the mandate reference as parameters.
Mandates can also be retrieved and managed using the SlimPay Dashboard. Further documentation on managing mandates via the Dashboard can be found on our Help Center.
Mandate templates
SlimPay offers merchants a range of customisation options using mandate templates. Specific documentation regarding mandate templates can be found on our Help Center.
Document templates
SlimPay offers merchants a range of customisation options using document templates. Specific documentation regarding document templates can be found on our Help Center.
Testing your integration
In order to test your implementation in our preprod environment, SlimPay has a range of test data available, such as test IBANs. Specific documentation regarding this test data can be found on the SlimPay Dev Center and Help Center.
Please note: Do no use real data (IBAN, phone number, address etc) during your preprod tests. However, any email addresses provided and used in our preprod environment must be valid, meaning you cannot use false or artificial email addresses in your tests.