General use
Twikey has put in place several services enabling software partners, companies with own ERP or CRM systems, banks and other 3rd parties to exchange information. This page describes the different calls that are available to you. The calls allow integration in a number of ways.
Since there are numerous ways a company can allow its customers to pay, we also provided a couple of high level use-cases to get you up and running in no time.
All exchanges require a valid AuthorizationToken passed on as a header named "Authorization". The AuthorizationToken can be retrieved via the login call and is valid for 24h. We suggest that the call to the login is done when the actual call you wish to make is returning a 401. This way you don't need to handle the lifecycle of your token yourself.
Exchanges can be in both JSON & XML responses. By default they will be in JSON, but by giving the "Accept" header a value of 'application/xml', you can get an xml payload.
Errors can be divided into 2 categories. The first category are errors based on user input for which we return a 400 error with the code of the error mentioned in the response header "ApiError'. The translated error can be found in the body of the required exchange. The language is provided by the "Accept-Language" header or defaults to English. The second category of errors is one that you normally shouldn't run into a lot. In this case we return a 500 error which means that something went wrong on our end. We'll probably already know about it when you see the error.
Sample use cases
The fitness scenario
Imagine you're going to the fitness where you exercise every once in a while. Since this doesn't come free you pay a monthly subscription fee. This subscription fee is a recurring payment (we'll come back to that later). But since all those exercises get you thirsty, you want to drink there too. But of course, there are hotter and colder days. So how much you drink can vary.
Regardless of what you consume, the fitness wants to get paid. But you'd like to avoid getting out your wallet when you're all sweaty. So your fitness made the great decision to use direct debits to allow you to pay. At the end of the month they add the recurring amount to the one-off's (the drinks). They send the payment request to the bank. Everyone's happy and relax.
What did the fitness do to achieve this relaxed way of working:
First of all, everything starts with a mandate. When a customer enrolls at the fitness he fills in the details for the internal bookkeeping of the fitness. The same information is sent to the prepare call. This returns a URL (representing an unsigned mandate) that opens up after entering all details in the enrollment screen. Since the fitness has an internal subscription number they want to use to track payments and have multiple subscriptions (eg. with and without personal trainer) they add both parameters in the prepare call. Making it visible in the mandate overview.
Once the customer filled in the account info and signed the mandate he's sent back to the fitness website with a "thank you" message. When a customer ask for a drink at the bar, the cash register calls the transaction endpoint with the details and amount. These are one-off transactions. Recurring transactions can either be handled the same way or if a subscription parameter was added in the prepare call, a recurring transaction is automatically added every month to get this subscription paid. At the end of each month, the file is created and sent to the bank manually via the collect call or automatically every night. Your bill is paid and the bank sends you the money. When the bank sends us back the account information, it is marked in your transaction overview that the transaction was paid. This information can be retrieved by the payment call. This call returns all new payment information since the last call. If a payment didn't succeed, you can configure what will happen next in the interface in the dunning section.
The parking app scenario
Because my customers don't like running in the rain looking for a parking meter while there's an app for that. How can I use Twikey to get my parking fees paid? First of all, you need a mandate . There are three possible options to have this mandate signed:
Use an in-app browser with the link retrieved via the prepare call Use the sign call to invite the user to sign via an sms confirmation Use the sign call adding the manual signature as a png-image in the payload Once the mandate is signed, in-app purchases can be sent from the backend of the app, collected the same way as mentioned in the fitness scenario.
The (off-line) webshop scenario
I have a shop where people come in physically but I also have a webshop. I want people who signed a mandate (either online via the above flow or physically) to be able to purchase something from the online shop without requiring them to use their credit card and if possible give them the sameconvenience in the physical shop. This way I can send them an invoice every month by only registering their purchases and collecting the payment via direct debit.
In the past, I had to send out all invoices and patiently waited for them to be paid. Since I'm not the most patient person on earth and even a bit chaotic at times, I'd rather collect the money directly from my customers. This way they can't forget to pay and I don't need to remind them to do so. How convenient this is for both my customers and I.
Authentication
Login
When using the API the login call will provide you with an AuthorizationToken, which is to be send upon every subsequent call (via the authorization header) in order to use the api. If the creditor opted for enhanced security, the private key allows the generation of a Time-based One-time password. See Appendix C of the Creditor API documentation for a more detailed explanation or sample code on how to calculate this OTP (samples in various languages are available).
Normally this call is made on request of another call that returned a 401 (UNAUTHORIZED) indicating that there was no session token or that it expired.
Requires an API Key which can be found in the Twikey Creditor Dashboard
curl -X POST https://api.twikey.com/creditor /
-d apiToken=**API KEY**
$host = "https://api.twikey.com";
$apitoken = "**API_KEY**";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,"apiToken=$apitoken");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
$authorization = $result->{'Authorization'} ;
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
apitoken = "**API_KEY**",
authorization = null,
options = {
host: host,
port: '443',
path: '/creditor',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body:{
'apiToken' : apitoken
}
};
var req = https.request(options, function (res) {
authorization = res.headers.authorization;
console.log("authorization : ",authorization);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
apiToken = "**API_KEY**";
public void logIn(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("apiToken", apiToken)
.build();
Request request = new Request.Builder()
.url(host + "/creditor")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
apiToken ="**API_KEY**";
public void logIn(){
RestClient client = new RestClient(host + "/creditor");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded",
"apiToken=" + apiToken,
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"Authorization": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
}
This AuthorizationToken acts as a session token and has a validity of 24h.
HTTP Request
POST https://api.twikey.com/creditor
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
apiToken | API key | Yes | string |
otp | Value calculated based on salt and private key (if enhanced security) | No | long |
HTTP Response
Code | Description |
---|---|
200 | For security reasons, the http status is always 200, however for returning error codes specific to the call 2 additional response headers were added "ApiError" and "ApiErrorCode" which are added on every response that contains errors. Notible exceptions are authentication errors and authorisation errors that don't have these 2 headers. |
Logout
Invalidates the AuthorizationToken by making a GET request to /creditor
curl https://api.twikey.com/creditor \
-H 'authorization: authorization'
$host = "https://api.twikey.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setOpt($ch, CURLOPT_HTTPHEADER, array(
"authorization: $authorization"
);
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
options = {
host: host,
port: '443',
path: '/creditor',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
});
public class TwikeyAPI {
private String host = "https://api.twikey.com";
public void logOut(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "creditor")
.get()
.addHeader("cache-control", "no-cache")
.addHeader("Authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyApi {
private String host = "https://api.twikey.com";
public void logOut(){
RestClient client = new RestClient(host + "/creditor");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("authorization", authorisation);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
GET https://api.twikey.com/creditor
HTTP Response
Code | Description |
---|---|
204 | Logged out succesfully |
Mandate
Invite a customer
Necessary to start with an eMandate or to create a contract. The end-result is a signed or protected shortlink that will allow the end-customer to sign a mandate or contract. The (short)link can be embedded in your website or in an email or in a paper letter. We advise to use the shortlink as the data is not exposed in the URL's. The parameters are as described in detail on the page "Create contracts".
After signing the end-customer is either presented with a thank-you page or is redirected to an exit url defined on the template. This url can contain variables that are filled in depending on the outcome. See exit urls
In case you need to immediately create a plan on a mandate, it is also possible to pass on the plan details in this call. The parameters can be found here.
Requires a ct_id which can be found in the Twikey Creditor Template overview
curl -X POST https://api.twikey.com/creditor/invite \
-H 'authorization: **authorization**' \
-d 'ct=**ct_id**' \
-d 'l=nl' \
-d 'email=support@twikey.com' \
-d 'lastname=Support' \
-d 'firstname=Twikey' \
-d 'mobile=32479123123' \
-d 'address=Derbystraat 43' \
-d 'zip="9051"' \
-d 'city=Sint Denijs Westrem' \
-d 'country=BE'
$host = "https://api.twikey.com";
$ct = **ct_id**;
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/invite");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"ct=$ct"
."&l=nl"
."&email=support%40twikey.com"
."&lastname=Support"
."&firstname=Twikey"
."&address=Derbystraat%2043"
."&zip=9051"
."&city=Sint%20Denijs%20Westrem"
."&country=BE"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
$url = $result->{'url'} ;
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
ct = "**ct_id**",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/invite',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
data: {
"ct": ct,
"l": "nl",
"email": "support@twikey.com",
"lastname": "Support",
"firstname": "Twikey",
"address": "Derbystraat 43",
"zip": "9051",
"city": "Sint Denijs Westrem",
"country": "BE"
}
};
var req = https.request(options, function (res) {
res.on('data', function (chunk) {
console.log("Redirect to : " + chunk)
});
});
public class TwikeyApi{
private string host = "https://api.twikey.com";
private String ct = "**ct_id**";
private String authorisation = null; //collected through logIn
public void invite(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody formBody = new FormBody.Builder()
.add("ct", ct)
.add("l", "nl")
.add("email", "support@twikey.com")
.add("firstname", "Twikey")
.add("lastname", "Support")
.add("address", "Derbystraat 43")
.add("zip", "9051")
.add("city", "Sint-Denijs-Westrem")
.add("country", "BE")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/invite")
.post(formBody)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Authorization", authorisation)
.addHeader("Cache-Control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct ="**ct_id**",
authorisation = null; // collected through logIn
public void invite(){
RestClient client = new RestClient(host + "/creditor/invite");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded",
"ct=" + ct +
"&l=nl" +
"&email=support%40twikey.com" +
"&lastname=Support" +
"&firstname=Twikey" +
"&address=Derbystraat%2043" +
"&zip=9051" +
"&city=Sint%20Denijs%20Westrem" +
"&country=BE"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"mndtId": "COREREC01",
"url": "http://twikey.to/myComp/ToYG",
"key": "ToYG"
}
HTTP Request
POST https://api.twikey.com/creditor/invite
note: If there is a default plan assigned to your template, the parameters to add a custom plan can also be used in this request.
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Contract template to use | Yes | integer |
l | Language (en/fr/nl/de/pt/es/it) | No | string |
iban | International Bank Account Number of the debtor | No | string |
bic | Bank Identifier Code of the IBAN | No | string |
mandateNumber | Mandate Identification number (if not generated) | No | string |
customerNumber | The customer number (strongly advised) | No | string |
Email of the debtor | No | string | |
lastname | Lastname of the debtor | No | string |
firstname | Firstname of the debtor | No | string |
mobile | Mobile number required for sms (International format +32499123445) | No | string |
address | Address (street + number) | No | string |
city | City of debtor | No | string |
zip | Zipcode of debtor | No | string |
country | ISO format (2 letters) | No | string |
companyName | The company name (if debtor is company) | No | string |
vatno | The enterprise number (if debtor is company) | No | string |
contractNumber | The contract number which can override the one defined in the template. | No | string |
campaign | Campaign to include this url in | No | string |
prefix | Optional prefix to use in the url (default companyname) | No | string |
check | If an existing collectable mandate exists, don't prepare a new (based on email + template(=ct)) | No | boolean |
reminderDays | Send a reminder if contract was not signed after number of days | No | number |
sendInvite | Send out invite email directly | No | boolean |
document | Add a contract in base64 format | No | string |
amount | In euro for a transaction via a first payment or post signature via an SDD transaction | No | string |
token | (optional) token to be returned in the exit-url (lenght<100) | No | string |
requireValidation | Always start with the registration page, even with all known mandate details | No | boolean |
Special cases:
Recurring Credit Card
For this you have to include an amount, ct type credit card and optional method (mastercard/visa) in the request.
HTTP Response
Code | Description |
---|---|
200 | If the check option is provided and an existing collectable mandate is available it will be returned. Otherwise an url and key will be returned. |
400 | User error if parameter is given but not valid or collectable (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_such_ct | No template found (or not active) |
err_invalid_domain | Invalid domain |
err_mandatenumber_required | No mandatenumber was given, while setting does not allow generation |
err_double_mandatenumber | Signed mandate with the same mandatenumber already exists |
err_missing_params | Attributes are missing while configured as mandatory |
Sign a mandate
Create a contract with an invitation/signature directly via API. Note that this call can require different parameters depending on the method of signature. All parameters are described in Create contracts When enabled for your contract it is possible to negiotiate mandates with their signature directly via API. Depending on the method the set of required parameters and/or handling may differ. Methods currently supported :
- sms: require the mobile parameter
- digisign: wet signature encoded as a base64 png (max 150 k)
- import: import the mandate with a specific signdate
curl -X POST https://api.twikey.com/creditor/sign \
-H 'authorization: **authorization**' \
-d 'method=sms' \
-d '&place=Gent' \
-d '&ct=**ct_id**' \
-d '&iban=BE68068897250734' \
-d '&bic=GKCCBEBB' \
-d '&email=sms%40twikey.com' \
-d '&lastname=Twikey' \
-d '&firstname=SMS' \
-d '&mobile=%2B32479123123' \
-d '&address=Derbystraat%2043' \
-d '&city=Gent' \
-d '&zip=9051' \
-d '&country=BE'
$host = "https://api.twikey.com";
$ct = **ct_id**;
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/sign");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"method=sms"
."&place=Gent"
."&ct=1323"
."&iban=BE68068897250734"
."&bic=GKCCBEBB"
."&email=sms%40twikey.com"
."&lastname=Twikey"
."&firstname=SMS"
."&mobile=%2B32479123123"
."&address=Derbystraat%2043"
."&city=Gent"
.'&zip=9051'
."&country=BE"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
$mandateId = $result->{'MndtId'} ;
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
ct = "**ct_id**",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/sign',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
data: {
"method": "sms",
"place": "Gent",
"ct": ct,
"l": "nl",
"email": "support@twikey.com",
"lastname": "Support",
"firstname": "Twikey",
"mobile": "+32479123123",
"address": "Derbystraat 43",
"zip": "9051",
"city": "Sint Denijs Westrem",
"country": "BE"
}
};
var req = https.request(options, function (res) {
res.on('data', function (chunk) {
console.log("manatenumber: " + chunk)
});
});
public class TwikeyApi{
private string host = "https://api.twikey.com";
private String ct = "**ct_id**";
private String authorisation = null; //collected through logIn
public void inviteAndSign(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("ct",ct)
.add("method", "sms")
.add("place"="Gent")
.add("mobile","+32479123123")
.add("l","nl")
.add("email","support%40twikey.com")
.add("lastname","Support")
.add("firstname","Twikey")
.add("address","Derbystraat%2043")
.add("zip","9051")
.add("city","Sint Denijs Westrem")
.add("country","BE")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/sign")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct ="**ct_id**",
authorisation = null; // collected through logIn
public void inviteAndSign(){
RestClient client = new RestClient(host + "/creditor/sign");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded",
"method=sms" +
"&place=Gent"
"&ct="+ ct +
"&iban=BE68068897250734" +
"&bic=GKCCBEBB" +
"&email=sms%40twikey.com" +
"&lastname=Twikey" +
"&firstname=SMS" +
"&mobile=%2B32479123123" +
"&address=Derbystraat%2043" +
"&city=Gent" +
"&zip=9051" +
"&country=BE" +
, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
}
}
{
"MndtId": "MyMandateId"
}
HTTP Request
POST https://api.twikey.com/creditor/sign
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Contract template to use | Yes | number |
l | Language (en/fr/nl/de/pt/es/it) | No | string |
method | Method to sign (sms/digisign/import/...) | Yes | string |
mandateNumber | Mandate Identification number (if not generated) | No | string |
iban | Yes | string | |
bic | Yes | string | |
Email of the debtor (maximum length 70 characters) | No | string | |
lastname | No | string | |
firstname | No | string | |
mobile | mobile number required for sms (International format +32499123445) | No | string |
address | Address (street + number) | No | string |
city | No | string | |
zip | No | string | |
country | ISO format (2 letters) | No | string |
companyName | the company name (if debtor is company) | No | string |
vatno | the enterprise number (if debtor is company) | No | string |
form | the legal form of the company (if debtor is company) | No | string |
contractNumber | the contract number which can override the one defined in the template. | No | string |
customerNumber | The customer number (if applicable) | No | string |
signDate | Date of signature (xsd:dateTime), sms uses date of reply | No | string |
place | Place of signature | No | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error code
Code | Description |
---|---|
err_no_such_ct | No template found (or not active) |
err_invalid_domain | Invalid domain |
err_mandatenumber_required | No mandatenumber was given, while setting does not allow generation |
err_double_mandatenumber | Signed mandate with the same mandatenumber already exists |
err_missing_params | Attributes are missing while configured as mandatory |
err_invalid_signature | No valid method was provided |
Update Feed
Returns a List of all updated mandates (new, changed or cancelled) since the last call. From the moment there are changes (eg. a new contract/mandate or an update of an existing contract) this call provides all related information to the creditor. The service is initiated by the creditor and provides all MRI information (and extra metadata) to the creditor. This call can either be triggered by a callback once a change was made or periodically when no callback can be made. This information can serve multiple purposes:
- Updating a CRM system to take appropriate actions (eg. call the customer on cancel..)
- Integrate the info in an ERP system to create the correct SDD files (in case of mandates)
If your system is out of sync or the full mandate database needs to be refreshed an optional "X-RESET" header can be passed. The format can be a timestamp like "2015-08-20T13:02:03Z". After that you will receive (all) mandate updates since that time again.
In order to make a split or fetch a specific type of document you need to pass "X-TYPES" in the header with following parameters in upper case only. (CONTRACT - CORE - B2B).
In order too avoid polling, a #19-callbacks can be setup to notify the client when new information is available. This hook can be configured in the Settings > API.
There are 3 possible updates.
- The first one is when a new signed mandate is available.
- The second is an amendment on a mandate (like address change). Indicated by the existence of an "AmdmntRsn".
- Last one is a cancellation of a mandate. Indicated by the existence of a "CxlRsn"
curl https://api.twikey.com/creditor/mandate \
-H 'authorization: **authorization**' \
-H 'x-reset: 2018-08-29T00:00:00.000Z'
$host = "https://api.twikey.com";
$ct = **ct_id**;$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/mandate");
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/mandate',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void updateFeed(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/mandate")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("x-reset", "2017-08-29T00:00:00.000Z")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void updateFeed(){
RestClient client = new RestClient(host + "/creditor/mandate");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("x-reset", "2017-08-29T00:00:00.000Z");
request.AddHeader("authorization", authorisation);
IRestResponse response = client.Execute(request);
}
}
{
"GrpHdr": {
"CreDtTm": "2015-08-20T13:02:03Z"
},
"Messages": [
{
"EvtTime": "2015-06-23T11:31:51Z",
"Mndt": {
"Cdtr": {
"CtctDtls": {
"EmailAdr": "info@creditor.com"
},
"CtryOfRes": "BE",
"Id": "BE0533800797",
"Nm": "Twikey N.V.",
"PstlAdr": {
"AdrLine": "Veldstraat 11",
"Ctry": "BE",
"PstCd": "9000",
"TwnNm": "Gent"
}
},
"CdtrSchmeId": "BE54ZZZ0533800797",
"Dbtr": {
"CtctDtls": {
"EmailAdr": "admin@debtorcpy.be"
},
"CtryOfRes": "BE",
"Id": "BE123456789",
"Nm": "debtorCompany Inc.",
"PstlAdr": {
"AdrLine": "Street 52",
"Ctry": "BE",
"PstCd": "1000",
"TwnNm": "Brussels"
}
},
"DbtrAcct": "BE493104522",
"DbtrAgt": {
"FinInstnId": {
"BICFI": "BBRUBEBB",
"Nm": "ING BELGIUM NV/SA"
}
},
"LclInstrm": "CORE",
"MaxAmt": "0",
"MndtId": "1600650622",
"Ocrncs": {
"Drtn": {
"FrDt": "2015-06-13"
},
"Frqcy": "ADHO",
"SeqTp": "RCUR"
},
"RfrdDoc": "1000",
"SplmtryData": [
{
"Key": "SignerPlace#0",
"Value": "Brussels"
},
{
"Key": "SignerDate#0",
"Value": "2015-06-22T21:00:00Z"
}
]
}
},
{
"CxlRsn": {
"Orgtr": {
"Nm": "Test Naam",
"PstlAdr": {
"AdrLine": "Derbystraat 43",
"PstCd": "9051",
"TwnNm": "Sint Denijs Westrem",
"Ctry": "BE"
},
"CtryOfRes": "BE",
"CtctDtls": {
"EmailAdr": "test@twikey.com",
"MobNb": "+32123456789"
}
},
"Rsn": "testing"
},
"OrgnlMndtId": "1700650622",
"CdtrSchmeId": "BE54ZZZ0533800797",
"EvtTime": "2017-10-31T14:14:51Z"
},
{
"AmdmntRsn": {
"Orgtr": {
"Nm": "Test Naam",
"PstlAdr": {
"AdrLine": "Andere straat 34",
"PstCd": "9000",
"TwnNm": "Gent",
"Ctry": "Gent"
},
"CtryOfRes": "NL",
"CtctDtls": {
"EmailAdr": "jonathan@twikey.nl",
"MobNb": "+32474519130"
}
},
"Rsn": "_T51"
},
"Mndt": {
"MndtId": "1500650622",
"LclInstrm": "CORE",
"Ocrncs": {
"SeqTp": "RCUR",
"Frqcy": "ADHO",
"Drtn": {
"FrDt": "2017-10-31"
}
},
"CdtrSchmeId": "BE54ZZZ0533800797",
"Cdtr": {
"Nm": "test Creditor",
"PstlAdr": {
"AdrLine": "test",
"PstCd": "test",
"TwnNm": "test",
"Ctry": "BE"
},
"Id": "BE0369258147",
"CtryOfRes": "BE",
"CtctDtls": {
"EmailAdr": "info@debtor.com"
}
},
"Dbtr": {
"Nm": "Test Test",
"PstlAdr": {
"AdrLine": "Derbystraat 43",
"PstCd": "9000",
"TwnNm": "Gent",
"Ctry": "BE"
},
"CtryOfRes": "NL",
"CtctDtls": {
"EmailAdr": "inf@debtor.com",
"MobNb": "+32474519130"
}
},
"DbtrAcct": "BE000000000000000",
"DbtrAgt": {
"FinInstnId": {
"BICFI": "BICCODE1",
"Nm": "Testbank"
}
},
"RfrdDoc": "General terms and conditions"
},
"OrgnlMndtId": "1500650622",
"CdtrSchmeId": "BE54ZZZ0533800797",
"EvtTime": "2017-10-31T14:19:09Z"
}
]
}
HTTP Request
GET https://api.twikey.com/creditor/mandate
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
chunkSize | Amount of mandates to return per call (max 100) | No | long |
Response
Code | Description |
---|---|
200 | The request has succeeded |
Cancel a mandate
A contract can be cancelled by either debtor or creditor, this can be done via the website or the api. However, there may be circumstances in which the creditor receives the cancel not through Twikey. In order to avoid extra costs & stale information, Twikey requires the update of its systems. The creditor, the creditor bank or the debtor bank, can initiate this request. Afterwards the update is distributed to all parties.
curl -X DELETE https://api.twikey.com/creditor/mandate?mndtId123&rsn=test \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$ct = **ct_id**;$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/mandate".
"?mndtId=mndtId123&rsn=some%20reason"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
curl_setOpt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/mandate?mndtId=**mdntId**&rsn=some%20reason',
method: 'DELETE',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void cancelMandate(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/mandate?mndtId=**mndtId&rsn=some%20reason")
.delete(null)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void cancelMandate(){
RestClient client = new RestClient(host + "/creditor/mandate" +
"?mndtId=mndtId123" +"
&rsn=some%20reason"
);
RestRequest request = new RestRequest(Method.DELETE);
request.AddHeader("x-reset", "2017-08-29T00:00:00.000Z");
request.AddHeader("authorization", authorisation);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
DELETE https://api.twikey.com/creditor/mandate
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
rsn | Reason of cancellation (Can be R-Message) | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | No contract was selected or invalid mndtId supplied |
err_invalid_state | Contract had wrong status (eg. already cancelled) or not authorised |
err_no_contract | No mandate was found |
err_provide_reason | Please provide reason |
Fetch mandate details
Retrieve details of a specific mandate. Since the structure of the mandate is the same as in the update feed but doesn't include details about state, 2 extra headers are added.
Note: Rate limits apply, though this is perfect for one-offs, for updates we recommend using the feed (see above).
Header name | Description |
---|---|
X-STATE | State of the mandate |
X-COLLECTABLE | Whether this mandate can be used for collections (true/false) |
Possible states | Description |
---|---|
PREPARED | User created the mandate, but the mandate is not signed yet |
SIGNED | Client signed the mandate |
EXPIRED | Mandate is beyond it's final date |
Cancelled | Mandate has been revoked |
SIGNED_PENDING_DEBTOR_BANK | only in case of B2B - debtor bank needs to validate the mandate |
REFUSED_BY_DEBTOR_BANK | only in case of B2B - signed but debtor bank refused the mandate |
REQUIRES_MORE_SIGNATURES | mandate needs to be signed by a 2nd person - option needs to be activated on template level |
only in case of B2B - mandate has been printed by debtor | |
PENDING_MERCHANT_APPROVAL | mandate has been uploaded by debtor but needs to be validated by merchant |
Possible events | Description |
---|---|
Cancel | depending on the state of a mandate |
Accepted Bank | depending on the state of a mandate |
Reject Bank | depending on the state of a mandate |
Sign | depending on the state of a mandate |
depending on the state of a mandate | |
Uploaded | depending on the state of a mandate |
Debtor Upload | depending on the state of a mandate |
Expired | depending on the state of a mandate |
curl https://api.twikey.com/creditor/mandate/detail?mndtId=mndtId123 \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/mandate/detail" . "
?mndtId=mndtId123"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
curl_setOpt($ch, CURLOPT_CUSTOMREQUEST, "GET");
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/mandate/detail?mndtId=mndtId123',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void getMandateDetail(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.get()
.url(host +
"/creditor/mandate/detail" +
"?mndtId=mndtId123"
)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void getMandateDetail(){
RestClient client = new RestClient(host +
"/creditor/mandate/detail" +
"?mndtId=mndtId123"
);
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("authorization", authorisation);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
GET https://api.twikey.com/creditor/mandate/detail
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
force | Also include non-signed states | No | boolean |
Response
Code | Description |
---|---|
200 | Details of the mandate (see /creditor/mandate) |
400 | User error if parameter is given but not valid (available in apierror header and response) |
429 | Too many requests |
Error codes
Code | Description |
---|---|
err_no_contract | No contract was selected or invalid mndtId supplied |
err_no_contract | No contract was found |
err_invalid_state | Contract was not signed (ignored when force=true) |
Update mandate details
You can change details of a mandate. Note: Include email only when changing it's value. bic code is generated automatically based on iban if not included. Custom attributes that are defined in the template can also be updated.
Note: Company name and language are always updated on the mandate itself, not the owner. Important: If the customer has accepted our Terms and Conditions, when updating only the mandate is updated except the email and mobile number. This is updated on both owner and mandate.
HTTP Request
POST https://api.twikey.com/creditor/mandate/update
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
state | active or passive (activated or suspend mandate) | No | String |
mobile | Owner's mobile number | No | String |
iban | Debtor's IBAN | No | String |
bic | Debtor's BIC code | No | String |
email address of debtor | No | String | |
firstname | Firstname of the debtor | No | String |
lastname | Lastname of the debtor | No | String |
companyName | Company name on the mandate | No | String |
vatno | The enterprise number (can only be changed if companyName is changed) | No | String |
customerNumber | The customer number (can be added, updated or used to move a mandate) | No | string |
l | language on the mandate (ISO 2 letters) | No | String |
To update the address all fields below are required | Yes | - | |
address | Address (street + number) | No | String |
city | City of debtor | No | String |
zip | Zipcode of debtor | No | String |
country | ISO format (2 letters) | No | String |
HTTP Response
Code | Description |
---|---|
204 | The server has fulfilled the request but does not need to return an entity-body, and might want to return updated meta-information |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | No contract was found |
err_invalid_country | Invalid country code or not in ISO format (2 letters) |
Move a mandate
It is possible to move the mandate to another customer (owner).
Include the customer number of the target in the request.
- The email address is updated on the mandate using the new owner's one.
- The mobile number is updated on the mandate using the new owner's one.
- Address and name are preserved on the mandate.
- payment links and invoices remain stored on the original owner.
This can be done for both pending and signed mandates.
Customer access
You may want to give your customer access to the mandate details without actually requiring him to get a Twikey account. You can do this by using this call. This call returns a url that you can redirect the user to for a particular mandate.
curl -X POST https://api.twikey.com/creditor/customeraccess \
-H 'authorization: **authorization**' \
-d 'mndtId=mndtId123'
$host = "https://api.twikey.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/customeraccess");
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
curl_setOpt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setOpt($ch, CURLOPT_POSTFIELDS, array(
"mndtId" => "mdntId123"
);
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
?>
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/customeraccess',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body:{
'mndtId': 'mndtId123'
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void updateMandate(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("mndtId", "mndtId123")
.build();
Request request = new Request.Builder()
.post(body)
.url(host + "/creditor/customeraccess")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void updateMandate(){
RestClient client = new RestClient(host + "/creditor/customeraccess);
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("authorization", authorisation);
request.AddParameter("application/x-www-form-urlencoded",
"mndtId=mndtId123" ,
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"token": "A4DE98FD091....",
"url": "https://merchant.twikey.com/p/customeraccess?token=A4DE98FD0915F"
}
HTTP Request
POST https://api.twikey.com/creditor/customeraccess
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
Update planned transactions
Sometimes a plan on an existing mandate needs to be updated. This endpoint allows to update a plan, just by passing the new plan data. Each parameter can be passed individually, only a plan name is required (or be passed empty to remove a plan).
curl -X POST https://api.twikey.com/creditor/mandate/plan \
-H 'authorization: **authorization**' \
-d 'mndtId=mdntId123'\
-d 'plan=planName'\
-d '_pls=2017-11-09'\
-d '_pli=1m'\
-d '_plo=4'\
-d '_plt=5'\
-d '_pla=50.00'\
-d '_pld=description for the plan'\
-d '_plr=your reference'
$host = "https://api.twikey.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/mandate/plan");
curl_setOpt($ch, CURLOPT_HTTPHEADER, array("authorization: $authorization"));
curl_setOpt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setOpt($ch, CURLOPT_POSTFIELDS, array(
"mndtId" => "mdntId123",
"plan" => "planName",
"_pls" => "2017-11-09",
"_pli" => "1m",
"_plo" => "4",
"_plt" => "5",
"_pla" => "50.00",
"_pld" => "description for the plan",
"_pld" => "your refrence")
);
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
?>
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/mandate/plan',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body:{
'mndtId': 'mndtId123',
'plan': 'planName',
'_pls': '2017-11-09',
'_pli': '1m',
'_plo': '14',
'_plt': '5',
'_pla': '50.00',
'_pld': 'description for the plan',
'_plr': 'your reference'
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void updateMandate(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("mndtId", "mndtId123")
.add("plan", "planName")
.add("_pls", "2017-11-09")
.add("_pli", "1m")
.add("_plo", "4")
.add("_plt", "5")
.add("_pla", "50.00")
.add("_pld", "description for the plan")
.add("_plr", "your reference")
.build();
Request request = new Request.Builder()
.post(body)
.url(host + "/creditor/mandate/plan")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void updateMandate(){
RestClient client = new RestClient(host + "/creditor/mandate/update");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("authorization", authorisation);
request.AddParameter("application/x-www-form-urlencoded",
"mndtId=mndtId123" +
"&plan=planName" +
"&_pls=2017-11-09" +
"&_pli=1m" +
"&_plo=14" +
"&_plt=5" +
"&_pla=50.00" +
"&_pld=description for the plan" +
"&_plr=your reference",
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
POST https://api.twikey.com/creditor/mandate/plan
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
plan | Name of the plan (can be empty in order to remove the plan) | Yes | string |
_pls | Startdate for the plan | No | string |
_pli | Periodicity of the plan, possible values are 1w, 2w, 1m, 2m, 3m, 4m, 6m, 12m | No | string |
_plo | The week day of the periodicity on wich the plan needs to be executed (1-7) | No | string |
_plt | Number of times the plan should be executed | No | string |
_pla | Amount associated with the plan | No | string |
_pld | Communication to debtor you send when a plan is executed | No | string |
_plr | Your internal reference you send | No | string |
HTTP Response
Code | Description |
---|---|
204 | The server has fulfilled the request but does not need to return an entity-body, and might want to return updated meta-information |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_plan_name | The plan parameter was not provided or an invalid planparameter supplied |
err_invalid_state | Mandates are editable only when in Prepared/Print state or CORE or not authorised |
err_no_contract | No contract was found |
Retrieve pdf
Retrieve pdf of a mandate
curl https://api.twikey.com/creditor/mandate/pdf?mndtId123 \
-H 'authorization: **authorization**'
# Example for downloading the content straight to a file
curl -v -X GET https://api.twikey.com/creditor/mandate/pdf?mndtId=mndtId123 -H 'authorization: **authorization**' --output test.pdf
$host = "https://api.twikey.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/mandate/pdf?mndtId=mndtId123");
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
curl_setOpt($ch, CURLOPT_CUSTOMREQUEST, "GET");
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/mandate/pdf?mndtId=mdntId123',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void retrievePdf(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.get()
.url(host + "/creditor/mandate/pdf?mndtId=mndtId123")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void retrievePdf(){
RestClient client = new RestClient(
host +
"/creditor/mandate/pdf" +
"?mndtId=mndtId123"
);
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("authorization", authorisation);
request.AddParameter("application/x-www-form-urlencoded",
"mandate.pdf",
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
GET https://api.twikey.com/creditor/mandate/pdf
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | PDF is available in the body of the response |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | No contract was found |
Upload pdf
Import existing mandate pdf (eg. scan of a printed document)
After import the mandate is set on signed state.
curl -X POST https://api.twikey.com/creditor/mandate/pdf \
-H 'authorization: **authorization**' \
-d 'mndtId=mndtId123' \
-d @mndtId123.pdf
$host = "https://api.twikey.com";
$post = array(
"file_box"=>"@/path/to/mndtId123.pdf",
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/mandate/pdf?mndtId=mndtId123");
curl_setOpt($ch, CURLOPT_HTTPHEADER, array(
"authorization: $authorization",
"Content-Type: application/pdf',
"Content-Length: ' . strlen($post))
);
curl_setOpt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setOpt($ch, CURLOPT_POSTFIELDS, $post);
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null; //collected through login
var requestUrl = 'path/to/import.json';
var request = new XMLHttpRequest();
request.open('GET', requestUrl);
request.responseType = 'json';
request.send();
request.onload = function (){
var options = {
host: host,
port: '443',
path: '/creditor/mandate/pdf?mndtId=mndtId123',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
data: request.response
};
var req = https.request(options, function (res) {
console.log(res);
});
};
import java.io.FileReader;
import java.io.BufferedReader;
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void uploadPdf(){
String pdf;
try{
FileReader fr = new FileReader("/path/to/mndtId123.pdf");
BufferedReader br = new BufferedReader(fr);
String s;
while((s = br.readLine()) != null) {
pdf+=s;
}
fr.close();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.post(pdf)
.url(host + "/creditor/mandate/pdf?mndtId=mndtId123")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
} catch (FileNotFoundException e){
System.out.printLn(e);
}
}
}
using System.IO;
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
String pdf = file.ReadAllText("\path\to\mndtid123.pdf");
public void uploadPdf(){
RestClient client = new RestClient(
host +
"/creditor/mandate/pdf" +
"?mndtId=mndtId123"
);
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("authorization", authorisation);
request.AddParameter("application/x-www-form-urlencoded",
pdf,
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
POST https://api.twikey.com/creditor/mandate/pdf
Query Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | Import of the pdf was done |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | Contract not found |
err_invalid_iban | no (valid) iban on the mandate |
Retrieve legal terms
Retrieve legal terms
curl https://api.twikey.com/creditor/legal?locale=nl_BE \
-H 'authorization: authorization'
$host = "https://api.twikey.com";
$authorisation = null; // collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/legal?locale=nl_BE");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
host = "api.twikey.com",
authorization = null, // collected through login
options = {
host: host,
port: '443',
path: '/creditor/legal?locale=nl_BE',
headers: {
'Content-Type': 'application/json'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; // collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
Request request = new Request.Builder()
.url(host + "/creditor/legal?locale=nl_BE")
.addHeader("content-type", "application/json")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/legal?locale=nl_BE");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/json");
IRestResponse response = client.Execute(request);
}
}
{
"tcUrl": "https://www.beta.twikey.com/nl/tc.html",
"bySigning": "Door ondertekening van dit mandaatformulier ...",
"rightsCore": "U kunt een Europese domiciliëring laten terugbetalen. Vraag ...",
"rightsB2b": "Dit mandaat is uitsluitend bedoeld voor betalingen tussen bedrijven. U hebt ...",
"infoCorrect": ""
}
Parameters
Name | Description | Required | Type |
---|---|---|---|
locale | the locale (fr, fr_FR, fr_BE, de, nl, nl_BE, nl_NL, es, pt, it) | no (defaults to en) | string |
Responses
Code | Description |
---|---|
200 | The request has succeeded |
Transactions
New transaction
Add transaction to an existing mandate. This transaction will be sent to the bank when the collection is sent to the bank either automatically or manually.
HTTP Request
POST /creditor/transaction
curl -X POST https://api.twikey.com/creditor/transaction \
-H 'authorization: **authorization**'\
-d 'mndtId=mndtId123' \
-d 'message=Monthly payment' \
-d 'amount=10'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,"mndtId=mndtId123"
."&message=Monthly payment"
."&amount=10");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body :{
'mndtId' : 'mndtId123',
'message': 'Monthly payment',
'amount': '10'
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void addTransaction(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("mndtId", "mndtId123")
.add("message", "Monthly payment")
.add("amount", "10")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transaction")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; //collected through logIn
public void addTransaction(){
RestClient client = new RestClient(host + "/creditor/transaction");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
request.AddParameter("application/x-www-form-urlencoded",
"mndtId=mndtId123" +
"message=Monthly payment" +
"amount=10"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"Entries": [
{
"id": 381563,
"contractId": 325638,
"mndtId": "MNDT123",
"contract": "Algemene voorwaarden",
"amount": 10.0,
"msg": "Monthly payment",
"place": null,
"ref": null,
"date": "2017-09-16T14:32:05Z"
}
]
}
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
mndtId | Mandate Reference | Yes | string |
date | Date of the billable event or now when empty | No | string |
reqcolldt | Requested date of the billable event | No | string |
message | Message to the customer (if only 1 entry) or structural message if 12 characters long [*1] | Yes | string |
ref | Your reference | No | string |
amount | Amount to be billed | Yes | string |
place | Optional place | No | string |
[*1]: This is the message that both you and your customer will see on their bank statement. (More info..)[/r/admin#/c/reportingFiles]
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | No mandate found |
err_invalid_state | The mandate is not active |
err_invalid_date | Invalid Date |
err_invalid_sepachars | Invalid characters in message to debtor |
err_invalid_amount | Invalid Amount given |
err_billing_overdrawn | Maximum amount reached according to risk rules |
Transaction feed
Retrieve list of transactions that had changes since the last call. If your system is out of sync or the full transaction database needs to be refreshed an optional "X-RESET" header can be passed. The format can be a timestamp like "2018-08-20T13:02:03Z". After that you will receive (all) transaction updates since that time again.
curl https://api.twikey.com/creditor/transaction \
-H 'authorization: **authorization**' \
-H 'x-reset: 2018-08-29T00:00:00.000Z'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction");
curl_setopt($ch, CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization');
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void getTransactions(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transaction")
.get()
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void getTransactions(){
RestClient client = new RestClient(host + "/creditor/transaction");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
GET /creditor/transaction
{
"Entries": [
{
"amount": 99.99,
"bkdate": "2017-03-21T08:13:21Z",
"contract": "contractNumber",
"contractId": 10001,
"final": true,
"id": 123456789,
"mndtId": "mandateReference",
"msg": "transaction message",
"place": "web",
"ref": null,
"reqcolldt": "2017-03-23",
"state": "PAID"
},
{
"amount": 100,
"bkdate": "2016-09-21T08:13:21Z",
"bkerror": "MS03",
"bkmsg": "No reason specified",
"contract": "contractNumber",
"contractId": 2002,
"final": false,
"id": 987654321,
"mndtId": "mandateReference",
"msg": "transaction message",
"place": "web",
"ref": "INVOICE001",
"reqcolldt": null,
"state": "ERROR"
},
{
"amount": 49.99,
"bkdate": "2016-08-29T13:14:40Z",
"bkerror": "AC04",
"bkmsg": "Account closed",
"contract": "contractNumber",
"contractId": 3003,
"final": true,
"id": 56789123,
"mndtId": "mandateReference",
"msg": "buy item X",
"place": "web",
"ref": null,
"reqcolldt": null,
"state": "ERROR"
},
"..."
]
}
Possible states
Possible states | Description |
---|---|
OPEN | The transaction is created but not processed by the bank |
PAID | The transaction has been executed + final flag info |
ERROR | The transaction has not been executed + final flag info |
Final flag state
Possible states | Description |
---|---|
TRUE | An action required from your part, paid or error like f.e. debtor deceased |
FALSE | More actions are pending to debit the debtor's account |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Transaction status
Retrieve the status of transactions at a certain point in time, this may change at any time. We recommend using the feed to keep up to date.
Note: Rate limits apply, though this is perfect for one-offs, for updates we recommend using the update feed (see above).
curl https://api.twikey.com/creditor/transaction/detail?id=1234 \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction/detail?id=1234");
curl_setopt($ch, CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction/detail?id=1234',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void getTransactionDetail(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transaction/detail?id=1234")
.get()
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void getTransactionDetail(){
RestClient client = new RestClient(host + "/creditor/transaction/detail?id=1234");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
{
"Entries": [
{
"amount": 10.0,
"contract": "Algemene voorwaarden",
"contractId": 325638,
"date": "2017-09-16T14:32:05Z",
"id": 381563,
"mndtId": "MNDT123",
"msg": "Monthly payment",
"place": null,
"ref": null,
"state": "OPEN"
}
]
}
HTTP Request
GET /creditor/transaction/detail
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | 1 or more ids of a transaction | No | string |
ref | 1 or more refs of a transaction | No | string |
mndtId | 1 or more mandate references | No | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
429 | Too many requests |
Error codes
Code | Description |
---|---|
err_invalid_params | Either id or ref or mndtId is invalid or is empty |
Action a transaction
Execute an action on a transaction, this will allow you to change the status or start a specific flow for the given transaction.
HTTP Request
POST /creditor/transaction/action
curl -X POST https://api.twikey.com/creditor/transaction/action \
-H 'authorization: **authorization**'\
-d 'id=345' \
-d 'action=REOFFER'
$host = "https://api.twikey.com";
$authorization = null; // collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction/action");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,"id=345"
."&action=REOFFER");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction/action',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body :{
'id' : '345',
'action': 'REOFFER'
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void addTransaction() {
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("id", "345")
.add("action", "REOFFER")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transaction/action")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void addTransaction() {
RestClient client = new RestClient(host + "/creditor/transaction/action");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
request.AddParameter("application/x-www-form-urlencoded",
"id=345" +
'action=REOFFER"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
Request Parameters
Name | Description | Required | Type | Options |
---|---|---|---|---|
id | Transaction id | Yes | string | |
action | Action to execute for the given transaction | Yes | string | PAID, REOFFER, TRANSFER, ARCHIVE |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
201 | Deletion of the transaction has succeeded |
400 | User error if parameter is given but not valid (available in api error header and response) |
Error codes
Code | Description |
---|---|
err_no_transaction | No transaction found |
err_no_contract | No mandate found (or not active) |
err_invalid_params | one of the parameters provided contains invalid data |
Update a transaction
Update parameters for an existing transaction.
HTTP Request
PUT /creditor/transaction
curl -X PUT https://api.twikey.com/creditor/transaction \
-H 'authorization: **authorization**'\
-d 'id=345' \
-d 'message=Monthly payment' \
-d 'amount=10'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS,"id=345"
."&message=Monthly payment"
."&amount=10");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction',
method: 'PUT',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body :{
'id' : '345',
'message': 'Monthly payment',
'amount': '10'
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void updateTransaction(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("id", "345")
.add("message", "Monthly payment")
.add("amount", "10")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transaction")
.put(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void updateTransaction(){
RestClient client = new RestClient(host + "/creditor/transaction");
RestRequest request = new RestRequest(Method.PUT);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
request.AddParameter("application/x-www-form-urlencoded",
"id=345" +
"message=Monthly payment" +
'amount=10"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | Transaction id | Yes | string |
reqcolldt | Requested date of the billable event | No | string |
message | Message to the customer | No | string |
ref | Your reference | No | string |
amount | Amount to be billed | No | string |
place | Optional place | No | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in api error header and response) |
Error codes
Code | Description |
---|---|
err_no_transaction | No transaction found |
err_no_contract | No mandate found (or not active) |
err_invalid_params | one of the parameters provided contains invalid data |
err_invalid_date | Invalid Date |
err_invalid_amount | Invalid Amount given |
Refund a transaction
If the beneficiary account does not already exist, the account is added to the customer.
The IBAN of the refund account is the one registered on the mandate linked to the transaction.
After a refund request, the refund batch need to be prepared to be proccessed.
curl -X POST https://api.twikey.com/creditor/transaction/refund \
-H 'authorization: **authorization**'\
-d 'id=345' \
-d 'iban=BE12356798' \
-d 'bic=BBRUBEBB' \
-d 'message=refund payment' \
-d 'amount=10'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction/refund");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS,"id=345"
."&message=Refund payment"
."&iban=BE12356798"
."&bic=BBRUBEBB"
."&amount=10");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction/refund',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body :{
'id' : '345',
'message': 'Refund payment',
'amount': '10',
'iban': 'BE12356798',
'bic': 'BBRUBEBB'
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void refundTransaction(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("id", "345")
.add("message", "Refund payment")
.add("amount", "10")
.add("iban", "BE12356798")
.add("bic", "BBRUBEBB")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transaction/refund")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void refundTransaction(){
RestClient client = new RestClient(host + "/creditor/transaction/refund");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
request.AddParameter("application/x-www-form-urlencoded",
"id=345" +
"&message=Refund payment" +
"&amount=10"
"&iban=BE12356798"
"&bic=BBRUBEBB"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
POST /creditor/transaction/refund
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | The transaction id | Yes | String |
message | Message for the refund | Yes | String |
amount | Amount to be refunded | Yes | Number |
ref | Add a reference for the refund | No | String |
place | Place of refund | No | String |
iban | Iban of the Beneficiary account (optional otherwise iban from the mandate) | No | String |
bic | Bic of the Beneficiary account | No | String |
{
"Entries": [
{
"id": "9FD3492820210119162251192138",
"iban": "BE123456789",
"bic": "GKCCBEBB",
"amount": 10.0,
"msg": "Refund payment",
"place": "Ghent",
"ref": "refund reference 123",
"date": "2021-01-19"
}
]
}
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_invalid_params | Missing request parameters or invalid values |
err_msg_missing | message parameter missing |
Remove a transaction
Remove a transaction that wasn't collected yet
curl -X DELETE https://api.twikey.com/creditor/transaction \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transaction");
curl_setopt($ch, CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transaction',
method: 'DELETE',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void removeTransaction(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transaction")
.delete(null)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void removeTransaction(){
RestClient client = new RestClient(host + "/creditor/transaction");
RestRequest request = new RestRequest(Method.DELETE);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
DELETE /creditor/transaction
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | a transactionId as returned in the post | No | string |
mndtId | all open transactions linked to the mandateReference | No | string |
ref | transactionReference as provided in the post to be removed | No | string |
HTTP Response
Code | Description |
---|---|
204 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | Contract not found |
Transaction reporting
Get transaction reporting, this API call will be activated on request.
Returns all reporting *since the last call. *
When you want to go back in history and retrieve past records you can pass an optional "X-RESET" header. The format can be a timestamp like "2018-10-16T13:02:03Z".
HTTP Request
GET /creditor/reporting
curl -X GET https://api.twikey.com/creditor/reporting \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorization = null; // collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/reporting");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, // collected through login
options = {
host: host,
port: '443',
path: '/creditor/reporting',
method: 'GET',
headers: {
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void updateTransaction(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transaction")
.get()
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void updateTransaction(){
RestClient client = new RestClient(host + "/creditor/reporting");
RestRequest request = new RestRequest(Method.PUT);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Error codes
Code | Description |
---|
{
"Statements": [
{
"id": 146406841,
"type": "PMNT/RCDT/ESCT",
"date": "2018-11-20",
"amount": 12.58,
"iban": "BE01234567890123",
"bic": "GEBABEBB",
"msg": "Testing",
"mndtId": "TST123",
"party": "Koen BVBA"
}
]
}
Collections
Execute Collection
Prepare a collection file and sent to collecting agent if available with the account data specified in the contract template.
HTTP Request
POST /creditor/collect
curl -X POST https://api.twikey.com/creditor/collect \
-d ct=123 \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$ct = "**ct_id**";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/collect");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"ct=$ct"
."clltndt=2017-09-15"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
ct = "**ct_id**",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/collect',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: {
"ct":"$ct",
"clltndt":"2017-09-15"
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
private String ct = "**ct_id**";
public void executeCollect(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody formBody = new FormBody.Builder()
.add("ct", ct)
.add("clltndt","2017-09-15")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/collect")
.post(formBody)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void executeCollect(){
RestClient client = new RestClient(host + "/creditor/collect");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded",
"ct=" + ct +
"clltndt="2017-09-15"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Contract template for which to do the collection | Yes | number |
colltndt | Collection date (default=earliest possible) | No | string |
mndtId | Optional array of mandateId's (default = all with billable entries) | No | array |
prenotify | Optional parameter, it's existence will trigger the prenotification towards the debtor (true/false) | No | boolean |
HTTP Response
Code | Description |
---|---|
200 | Returns the id referencing both first and recurring sdd send to bank |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_such_ct | No template specified |
err_invalid_ct | Invalid template specified |
err_provide_account | No account specified in template |
err_no_access_subscription | No connection to the bank in your subscription |
err_invalid_date | Invalid date |
Status collection
Retrieve all payments obtained so far from collecting agent per collection batch
HTTP Request
GET /creditor/payment
curl https://api.twikey.com/creditor/payment \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/payment");
curl_setOpt($ch, CURLOPT_HTTPHEADER, "authorization: $authorization");
curl_setOpt($ch, CUSTOMREQUEST, 'GET');
$server_output = curl_exec ($ch);
$result = json_decode($server_output);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/payment',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log(res);
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void statusCollection(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/collect/sdd")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("x-reset", "2017-08-29T00:00:00.000Z")
.addHeader("authorization", authorisation)
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorisation = null; // collected through logIn
public void statusCollection(){
RestClient client = new RestClient(host + "/creditor/payment");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("x-reset", "2017-08-29T00:00:00.000Z");
request.AddHeader("authorization", authorisation);
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
id | Specific SDD reference | No | number |
detail | Include details (true = default/false) | No | boolean |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Invoices
Create invoice
Create a new invoice for a customer. The invoice can be sent to your customer automatically or manually. Depending on the selected options in the template, different payment options will be provided to the debtor.
Define the customer by using the 'customer{}' object.
Or refer to a customer by mandatenumber: 'customerByDocument'.
Or refer to a customer by customerNumber: 'customerByRef'.
When using "id" the string must be in the UUID format.
HTTP Request
POST /creditor/invoice
curl -X POST https://api.twikey.com/creditor/invoice \
-H 'authorization: **authorization**' \
-H "Content-Type: application/json" \
-H 'x-reset: 2018-08-29T00:00:00.000Z' \
-d '{
"number": "Inv20200001",
"title": "Invoice July",
"remittance": "596843697521",
"ct": 1988,
"amount": 100,
"date": "2020-01-31",
"duedate": "2020-02-28",
"customer": {
"customerNumber": "customer123",
"email": "no-reply@twikey.com",
"firstname": "Twikey",
"lastname": "Support",
"address": "Derbystraat 43",
"city": "Gent",
"zip": "9000",
"country": "BE",
"l": "nl",
"mobile": "32498665995"
},
"pdf": "JVBERi0xLj....RU9GCg=="
}'
Response:
'{
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"number": "Inv20200001",
"title": "Invoice July",
"ct": 1988,
"amount": 100.00,
"date": "2020-01-31",
"duedate": "2020-02-28",
"status": "BOOKED",
"url": "https://yourpage.beta.twikey.com/invoice.html?fec44175-b4fe-414c-92aa-9d0a7dd0dbf2"
}'
** Or by referencing an existing document or customerNumber **
curl -X POST https://api.twikey.com/creditor/invoice \
-H 'authorization: **authorization**' \
-H "Content-Type: application/json" \
-H 'x-reset: 2018-08-29T00:00:00.000Z' \
-d '{
"number": "Inv20200001",
"title": "Invoice July",
"remittance": "596843697521",
"ct": 1988,
"amount": 100,
"date": "2020-01-31",
"duedate": "2020-02-28",
"customerByRef": "customer123" // or "customerByDocument": "MandateReference123"
"pdf": "JVBERi0xLj....RU9GCg=="
}'
$client = new http\Client;
$request = new http\Client\Request;
$request->setRequestUrl('http://api.twikey/creditor/invoice');
$request->setRequestMethod('POST');
$body = new http\Message\Body;
$body->append('{
"number": "Invss123",
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"title": "Invoice April",
"remittance": "123456789123",
"ct": 60,
"amount": 100,
"date": "2020-03-20",
"duedate": "2020-04-28",
"customer": {
"customerNumber": "customer123",
"email": "no-reply@twikey.com",
"firstname": "Twikey",
"lastname": "Support",
"address": "Derbystraat 43",
"city": "Gent",
"zip": "9000",
"country": "BE",
"lang": "nl",
"mobile": "32498665995"
}
}');
$request->setBody($body);
$request->setOptions(array());
$request->setHeaders(array(
'Authorization' => '...',
'Content-Type' => 'application/json'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();
Response:
'{
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"number": "Inv20200001",
"title": "Invoice July",
"ct": 1988,
"amount": 100.00,
"date": "2020-01-31",
"duedate": "2020-02-28",
"status": "BOOKED",
"url": "https://yourpage.beta.twikey.com/invoice.html?fec44175-b4fe-414c-92aa-9d0a7dd0dbf2"
}'
var request = require('request');
var options = {
'method': 'POST',
'url': 'http://api.twikey/creditor/invoice',
'headers': {
'Authorization': '.....',
'Content-Type': ['application/json']
},
body: '{
"number": "Invss123",
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"title": "Invoice April",
"remittance": "123456789123",
"ct": 60,
"amount": 100,
"date": "2020-03-20",
"duedate": "2020-04-28",
"customer": {
"customerNumber": "customer123",
"email": "no-reply@twikey.com",
"firstname": "Twikey",
"lastname": "Support",
"address": "Derbystraat 43",
"city": "Gent",
"zip": "9000",
"country": "BE",
"lang": "nl",
"mobile": "32498665995"
}
}'
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Response:
'{
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"number": "Inv20200001",
"title": "Invoice July",
"ct": 1988,
"amount": 100.00,
"date": "2020-01-31",
"duedate": "2020-02-28",
"status": "BOOKED",
"url": "https://yourpage.beta.twikey.com/invoice.html?fec44175-b4fe-414c-92aa-9d0a7dd0dbf2"
}'
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n" +
" \"number\": \"Invss123\",\n" +
" \"id\" : \"fec44175-b4fe-414c-92aa-9d0a7dd0dbf2\",\n" +
" \"title\": \"Invoice April\",\n" +
" \"remittance\": \"123456789123\",\n" +
" \"ct\": 60,\n" +
" \"amount\": 100,\n" +
" \"date\": \"2020-03-20\",\n" +
" \"duedate\": \"2020-04-28\",\n" +
" \"customer\": {\n" +
" \"customerNumber\": \"customer123\",\n" +
" \"email\": \"no-reply@twikey.com\",\n" +
" \"firstname\": \"Twikey\",\n" +
" \"lastname\": \"Support\",\n" +
" \"address\": \"Derbystraat 43\",\n" +
" \"city\": \"Gent\",\n" +
" \"zip\": \"9000\",\n" +
" \"country\": \"BE\",\n" +
" \"lang\": \"nl\",\n" +
" \"mobile\": \"32498665995\"\n" +
" }\n" +
"}");
Request request = new Request.Builder()
.url("https://api.twikey.com/creditor/invoice")
.method("POST", body)
.addHeader("Authorization", "701fbbfd-2681-47c3-8077-59345df335f2")
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
// Response:
'{
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"number": "Inv20200001",
"title": "Invoice July",
"ct": 1988,
"amount": 100.00,
"date": "2020-01-31",
"duedate": "2020-02-28",
"status": "BOOKED",
"url": "https://yourpage.beta.twikey.com/invoice.html?fec44175-b4fe-414c-92aa-9d0a7dd0dbf2"
}'
var client = new RestClient("http://api.twikey/creditor/invoice");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "701fbbfd-2681-47c3-8077-59345df335f2");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n" +
" \"number\": \"Invss123\",\n" +
" \"id\" : \"fec44175-b4fe-414c-92aa-9d0a7dd0dbf2\",\n" +
" \"title\": \"Invoice April\",\n" +
" \"remittance\": \"123456789123\",\n" +
" \"ct\": 60,\n" +
" \"amount\": 100,\n" +
" \"date\": \"2020-03-20\",\n" +
" \"duedate\": \"2020-04-28\",\n" +
" \"customer\": {\n" +
" \"customerNumber\": \"customer123\",\n" +
" \"email\": \"no-reply@twikey.com\",\n" +
" \"firstname\": \"Twikey\",\n" +
" \"lastname\": \"Support\",\n" +
" \"address\": \"Derbystraat 43\",\n" +
" \"city\": \"Gent\",\n" +
" \"zip\": \"9000\",\n" +
" \"country\": \"BE\",\n" +
" \"lang\": \"nl\",\n" +
" \"mobile\": \"32498665995\"\n" +
" }\n" +
"}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
// Response
Response:
'{
"id": "fec44175-b4fe-414c-92aa-9d0a7dd0dbf2",
"number": "Inv20200001",
"title": "Invoice July",
"ct": 1988,
"amount": 100.00,
"date": "2020-01-31",
"duedate": "2020-02-28",
"status": "BOOKED",
"url": "https://yourpage.beta.twikey.com/invoice.html?fec44175-b4fe-414c-92aa-9d0a7dd0dbf2"
}'
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | UUID of the invoice (optional) | No | string |
number | Invoice number | Yes | string |
title | Message to the debtor [*1] | Yes | string |
remittance | Payment message, if empty then title will be used [*2] | No | string |
ct | Template to be used | Yes | string |
amount | Amount to be billed | Yes | number |
date | Invoice date | Yes | date |
duedate | Due date | Yes | date |
Base64 encoded document | No | string | |
Customer | |||
customerNumber | The customer number to link this invoice too (strongly advised) | No | string |
Debtor's email | Yes | string | |
firstname | Debtor's first name - if not known we will put unknown | No | string |
lastname | Debtor's last name - if not known we will put unknown | No | string |
companyName | Name of the company | No | string |
coc | Enterprise number of the company | No | string |
lang / l | Debtor's language | No | string |
address | Debtor's address (street + number)e | No | string |
city | Debtor's city | No | string |
zip | Debtor's zipcode | No | string |
country | Debtor's country | No | string |
mobile | Debtor's mobile number place | No | string |
By existing customer | |||
customerByRef | The customer number to link this invoice too | No | string |
customerByDocument | The mandate number to link this invoice too | No | string |
[1]: This is the message that your customer will see on their bank statement. (More info..)[/r/admin#/c/reportingFiles] [2]: This will be the code used in the bank statements Twikey provides that you'll be able to import in your accounting package.
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_contract | No mandate found |
err_debtor_not_found | Debtor was not found |
err_invalid_state | The mandate is not active |
err_invalid_date | Invalid Date |
err_invalid_sepachars | Invalid characters in message to debtor |
err_invalid_amount | Invalid Amount given |
err_billing_overdrawn | Maximum amount reached according to risk rules |
Update invoice
Update invoice details. Use the unique invoice id in the request url.
HTTP Request
PUT /creditor/invoice/{{id}}
curl -X PUT https://api.twikey.com/creditor/invoice/{{id}}
-H 'authorization: **authorization**' \
-H "Content-Type: application/json" \
-d '{
"title": "Invoice Updated",
"date": "{{invoiceDate}}",
"duedate": "{{dueDate}}",
"ref": "reference",
"pdf": "JVBERi...RU9GCg==",
"status": "paid"
}'
Request parameters
Name | Description | Required | Type |
---|---|---|---|
title | Title of the invoice | No | String |
date | Invoice date | Yes | String |
duedate | Invoice due date | Yes | String |
ref | Invoice reference | No | String |
Base64 encoded document | No | String | |
status | Mark invoice as "booked", "archived", "paid" | No | String |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Error codes
Code | Description |
---|---|
err_invalid_params | No invoice id passed in the request |
err_not_found | Invoice id not found |
err_invalid_date | date or due date is invalid |
Invoice feed
Retrieve the list of updates on invoices that had changes since the last call. If your system is out of sync or the full transaction database needs to be refreshed an optional "X-RESET" header can be passed. The format can be a timestamp like "2018-08-20T13:02:03Z". After that you will receive (all) transaction updates since that time again.
curl https://api.twikey.com/creditor/invoice \
-H 'authorization: **authorization**' \
-H 'x-reset: 2018-08-29T00:00:00.000Z'
$host = "https://api.twikey.com";
$authorization = null; //collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/invoice");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/invoice',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void getTransactions(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/invoice")
.get()
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void getTransactions(){
RestClient client = new RestClient(host + "/creditor/invoice");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
GET /creditor/invoice
HTTP Request
GET /creditor/invoice
{
"Invoices": [
{
"id": "495b4af5-c422-4fb4-a44c-308690696401",
"number": "Inv20200001",
"title": "Invoice July",
"remittance": "596843697521",
"ref": "Reference",
"state": "PAID",
"amount": 100,
"date": "2020-01-31",
"duedate": "2020-02-28",
"ct": 6
},
"..."
]
}
Request Parameters
The parameter 'include' can be reused in the url several times with a different value.
Name | Value | Description | Required | Type |
---|---|---|---|---|
include | meta | Include meta data in the response (more information below) | No | string |
include | customer | Include customer details | No | string |
HTTP Request
GET /creditor/invoice?include=customer&include=meta
{
"Invoices": [
{
"id": "b3340469-2bc6-4d20-b717-5d3015979038",
"number": "INVOICE_8317363890",
"title": "B8 Sales, Inc.",
"remittance": "B7-64-3C-22-37-4C",
"ref": "my reference",
"state": "PAID",
"amount": 1.8,
"date": "2020-10-12",
"duedate": "2020-10-13",
"ct": 2223,
"url": "https://mycompany.beta.twikey.com/nl/invoice.html?b3340469-2bc6-4d20-b717-5d3015979038",
"customer": {
"email": "support@twikey.com",
"firstname": "Twikey",
"lastname": "Support",
"address": "Derbystraat 100",
"city": "Gent",
"zip": "9000",
"country": "NL",
"ref": "customernumber",
"l": "nl",
"mobile": "+321231231"
},
"meta": {
"reminderLevel": "1",
"partial": "70553"
}
]
}
Possible states
Possible states | Description |
---|---|
BOOKED | The invoice created but not processed by the bank |
PENDING | The payment is in progress |
PAID | The invoice has been paid |
EXPIRED | The invoice has expired |
ARCHIVED | The invoice has been archived |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Meta data
parameter | Description |
---|---|
reminderLevel | the number of reminders sent out |
partial | payment link id used to pay a partial amount of the invoice |
lastError | last error received from the bank in case of an SDD transaction |
name | Company name of the debtor |
Action on Invoice
Action request enables to send the invitation or reminder to a customer.
This can be done by sms or email.
The reminder level (1 - 4) is based accordingly on prior reminders already send to the customer.
Type smsreminder has only one reminder level.
HTTP Request
POST /creditor/invoice/{{id}}/action
curl -X POST https://api.twikey.com/creditor/invoice/${invoiceId}/action \
-H 'authorization: **authorization**' \
-d 'type=sms'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.twikey.com/creditor/invoice/$invoiceId/action",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "type=sms",
CURLOPT_HTTPHEADER => array(
"Authorization: $authorization",
"Content-Type: application/x-www-form-urlencoded"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "type=sms");
Request request = new Request.Builder()
.url("https://api.twikey.com/creditor/invoice/" + invoiceId)
.method("POST", body)
.addHeader("Authorization", authorization)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/invoice/{invoiceId}/action");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "{authorization}");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("type", "sms");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
type | The type of invite or reminder to send | yes | string |
Type values
Name | Description |
---|---|
Send invitation by email | |
sms | Send invitation by sms |
emailreminder | Send a reminder by email |
smsreminder | Send a reminder by sms |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Error codes
Code | Description |
---|---|
err_invalid_email | Debtor has no email configured |
err_invalid_mobile | Debtor has no mobile number configured |
err_invalid_type | Type was not defined or invalid |
Reconciliation
Generate Files
Generate reconciliation files in coda or camt53 format.
Payment link files can be generated the following day after payment.
SDD (Sepa Direct Debit) files can be generated each day, there is a delay of 3 days:
- E.g: transactions sent to the bank on Monday then the file is available to generate on Wednesday.
- This is due to standard bank processing time (like any other bank transfer)
- note: to activate this http request, contact Twikey support*
- note: when using Mollie for settlements, the frequency to be able to generate files can vary. For more information please contact Mollie.*
HTTP Request
POST /creditor/files
......
$ch = curl_init();
$authorization = null; // collected through logIn
curl_setopt_array($ch, array(
CURLOPT_URL => "https://api.beta.twikey.com/creditor/files",
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "sdd=true&paylink=true&format=coda",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
'Authorization: $authorization'
),
));
$server_output = curl_exec($ch);
curl_close($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/files',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body :{
'sdd:' 'true',
'paylink:' 'true',
'format:' : 'coda'
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
....
....
Query parameters
Name | Description | Required | Type |
---|---|---|---|
sdd | Set true to generate sdd files | Yes | boolean |
paylink | Set true to generate paylink files | Yes | boolean |
format | the format of the file (camt or coda) | Yes | String |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_invalid_params | Parameters are invalid (see "Extra") |
Download Files
Download the generated reconciliation files
Note: once the file has been downloaded trough GUI, it cannot be downloaded again.
HTTP Request
GET /creditor/files/filename
......
......
......
......
......
Query parameters
Name | Description | Required | Type |
---|---|---|---|
filename | the filename | Yes | file |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Payments
The payment information can be retrieved in 2 ways. This can either be done by polling the transaction feed or by the status of the collection. Both can be polled periodically or triggered by a callback.
Per transaction
{
"Entries": [
{
"id": 123456789,
"contractId": 10001,
"mndtId": "mandateReference",
"contract": "contractNumber",
"amount": 99.99,
"msg": "transaction message",
"place": "web",
"ref": null,
"final": true,
"state": "PAID",
"bkdate": "2017-03-21T08:13:21Z",
"reqcolldt": "2017-03-23T08:13:21Z"
},
{
"id": 987654321,
"contractId": 2002,
"mndtId": "mandateReference",
"contract": "contractNumber",
"amount": 100,
"msg": "transaction message",
"place": "web",
"ref": "INVOICE001",
"final": false,
"state": "ERROR",
"bkerror": "MS03",
"bkmsg": "Geen reden opgegeven",
"bkdate": "2016-09-21T08:13:21Z",
"reqcolldt": null
},
{
"id": 56789123,
"contractId": 3003,
"mndtId": "mandateReference",
"contract": "contractNumber",
"amount": 49.99,
"msg": "buy item X",
"place": "web",
"ref": null,
"final": true,
"state": "ERROR",
"bkerror": "AC04",
"bkmsg": "Rekening afgesloten",
"bkdate": "2016-08-29T13:14:40Z",
"reqcolldt": null
}
]
}
This endpoint allows to retrieve a list of all the transactions for which new payment information has been received since the last call. This endpoint doesn't require any parameters. If we receive an error from the bank, we mark the transaction with status "error" or "paid". We also add a final flag which can either be true or false. True (being final) means that we can't do anything with it anymore. This could be the case for paid transactions as well as for errors like debtor deceased. An action will be required on your part. False means that we still have actions pending to debit the debtor's account.
Possible states
Possible states | Description |
---|---|
OPEN | The transaction is created but not processed by the bank |
PAID | The transaction has been executed + final flag info |
ERROR | The transaction has not been executed + final flag info |
Final flag state
Possible states | Description |
---|---|
TRUE | An action required from your part, paid or error like f.e. debtor deceased |
FALSE | More actions are pending to debit the debtor's account |
Per Collection
{
"Sdds":[
{
"id":1437939405111,
"pmtinfid": "mypmtid",
"tx":4, // Number of transactions
"amount":120.0, // Total amount of the transactions
"Entries": [
{
"e2eid": "mye2e",
"amount": 30.0,
"contractId": 7488, // internal reference to the contract
"mandateRef": "TWIKEYCORE22", // mandate reference
"msg": "testing",
"final": false, // Does Twikey have any outstanding actions ?
"state": "open" // No payment information received as of yet
},
{
"e2eid": "mye2e",
"amount": 30.0,
"contractId": 7488,
"mandateRef": "TWIKEYCORE22",
"msg": "testing",
"final": true,
"state": "paid", // Transaction was paid
"bkamount": 30.0, // Booked amount as stated in account information
"bkdate": "2015-07-27", // Booking date as stated in account information
"bkerror": null // No errors
},
{
"e2eid": "mye2e",
"amount": 30.0,
"contractId": 6358,
"mandateRef": "TWIKEYCORE21",
"msg": "test",
"final": false, // This is FYI, since we haven't exhausted yet all possibilities (will re-offer)
"state": "error", // Transaction was paid
"bkamount": 30.0,
"bkdate": "2015-07-27",
"bkerror": "MSO3" // Actual error code
},
{
"e2eid": "mye2e",
"amount": 30.0,
"contractId": 6358,
"mandateRef": "TWIKEYCORE21",
"msg": "test",
"final": true, // Could not collect, please contact your customer
"state": "error",
"bkamount": 30.0,
"bkdate": "2015-07-27",
"bkerror": "AG01"
}
]
}
]
}
This endpoint allows to retrieve a list of SDD's for which new payment information is given. If the parameter 'id' is passed, it will also return the details of the mandates contained in the referenced SDD. If the 'detail' parameter is passed (regardless of its value) then the call with the 'id' parameter is obsolete as the details are included in the general call. In case we receive an error from the bank, we mark the transaction with status "error" or "paid", but on top of it we add a final flag which will either be true or false. True (being final) means that we can't do anything with it anymore. This could be the case for paid transactions as well as for errors like debtor deceased. An action would be required from your part. False means that we still have actions pending to debit the debtor's account.
Possible states
Possible states | Description |
---|---|
OPEN | The transaction is created but not processed by the bank |
PAID | The transaction has been executed + final flag info |
ERROR | The transaction has not been executed + final flag info |
Final flag state
Possible states | Description |
---|---|
TRUE | An action required from your part, paid or error like f.e. debtor deceased |
FALSE | More actions are pending to debit the debtor's account |
Paymentlinks
Paymentlinks can facilitate a one-off payment that needs to happen or can be used in the dunning process. For the latter you don't need to use these endpoints. However if you want to use the former, these endpoints will be of service to you. We don't provide a list endpoint as updates should be retrieved upon receiving a webhook.
Create paymentlink
Create a payment link for an affiliated customer (via email) or via a name (in which case no customer is linked).
It is possible to create a -consolidated- paymentlink by using the parameter txref.
Unique transaction references are required!
In this case you create a paymentlink linked over several transactions based on their transaction reference. Once paid, every transaction will be marked as paid as well.
When specifying a redirectUrl, use http:// or https:// to refer to the website.
If an email address is added, the debtor is also added as a customer in Twikey.
HTTP Request
POST /creditor/payment/link
curl -X POST https://api.twikey.com/creditor/payment/link \
-H 'authorization: **authorization**'\
-d 'email=no-repy@twikey.com'\
-d 'message=Faulty payments last month'\
-d 'amount=100'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/payment/link");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"email=no-repy@twikey.com"
."&message=Monthly payment"
."&amount=10");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/payment/link',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
},
body :{
'email': 'no-repy@twikey.com',
'message': 'Monthly payment',
'amount': '10'
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void addTransaction(){
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("email=no-repy@twikey.com")
.add("message", "Monthly payment")
.add("amount", "10")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/payment/link")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; //collected through logIn
public void addTransaction(){
RestClient client = new RestClient(host + "/creditor/payment/link");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
request.AddParameter("application/x-www-form-urlencoded",
"email=no-repy@twikey.com" +
"message=Monthly payment" +
'amount=10"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"id": 1,
"amount": 55.66,
"msg": "Test",
"url": "https://mycompany.twikey.com/payment/tr_l2iKz0LT8HvRrmf0"
}
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
customerNumber | The customer number (strongly advised) | No | string |
Email of the debtor | No (Required to send invite) | string | |
lastname | Yes | string | |
firstname | Yes | string | |
l | Language (en/fr/nl/de/pt/es/it) | No | string |
mobile | mobile number | No | String |
ct | contract template | No | String |
title | Message to the debtor [*1] | Yes | string |
remittance | Payment message, if empty then title will be used [*2] | No | string |
amount | Amount to be billed | Yes | string |
redirectUrl | Optional redirect after pay url (must use http(s)://) | No | url |
place | Optional place | No | string |
expiry | Optional expiration date | No | date |
sendInvite | Send out invite email or sms directly (email, sms) | No | String |
address | Address (street + number) | No | string |
city | City of debtor | No | string |
zip | Zipcode of debtor | No | string |
country | ISO format (2 letters) | No | string |
txref | References from existing transactions | No | string |
method | Circumvents the payment selection with PSP (bancontact/ideal/maestro/mastercard/visa/inghomepay/kbc/belfius) | No | string |
invoice | create payment link for specific invoice number | No | String |
note: A timestamp can also be included in the expiry date, but this is only supported by certain PSP's.
For more information contact our support.
Our standard UTC is -1 hour.
[1]: This is the message that your customer will see on their bank statement. (More info..)
[2]: This will be the code used in the bank statements Twikey provides that you'll be able to import in your accounting package.
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_invalid_amount | Invalid Amount given |
err_invalid_date | Invalid Expiry Date |
err_duplicate_tx | Duplicate transaction |
err_not_found | Invoice not found or invoice amount is exceeded |
err_invalid_state | Invoice state is not booked or expired |
Special cases:
Send payment links using sms.
For this you have to include a mobile number and email address in the request.
The parameter 'sendInvite' has to be set on 'sms'.Create payment link for invoices
It is possible to create payment links for booked or expired invoices.
This can be done for the total amount of the invoice, or a partial amount.In case of a partial payment, the payment link id is displayd in the invoice feed meta data ('partial': 'link-id').
Add the parameter 'invoice' and use the invoice number to create a payment link for invoices.Important: When the customer use that link and pays, the invoice is marked as paid even in case of a partial amount.
Payment link for a SDD transaction
In order to create a payment link for SDD transactions use either 'tx' (for the id of the transaction) or 'txref' for the reference. Note however that the transaction can only be linked when it is in 'failed' state.
Status paymentlink
Get status of a payment link
HTTP Request
GET /creditor/payment/link
curl https://api.twikey.com/creditor/transaction?id=123 \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/payment/link?id=123");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/payment/link?id=123',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void addTransaction(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/payment/link/id=123")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; //collected through logIn
public void addTransaction(){
RestClient client = new RestClient(host + "/creditor/payment/link?id=123");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
[{
"id": 1,
"amount": 55.66,
"msg": "Test",
"ref": "My Ref",
"state": "paid" // one of created, started, declined, paid, pending, expired
}]
Request Parameters
Either id or ref is mandatory.
Name | Description | Required | Type |
---|---|---|---|
id | Id of the link | No | string |
ref | Your reference | No | string |
Possible states
States | Description |
---|---|
Created | The payment link has been created but the customer did not do anything with it yet. |
Started | The customer has clicked on the payment link you transmitted him but did not complete the payment. In the Twikey dashboard the state will be shown as clicked. |
Pending | The customer started to pay, but did not complete the payment process. (only for iDeal, Paypal & Tikkie) |
Declined | The customer completed the payment process but the payment wasn't successful |
Paid | The customer paid the amount asked. |
Expired | The customer did not complete the payment before the expiration date you defined when creating the payment link. |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_missing_params | No parameter given |
err_no_transaction | No link found |
Paymentlink Feed
Get payment link feed since the last retrieval
HTTP Request
GET /creditor/payment/link/feed
curl -X GET https://api.twikey.com/creditor/payment/link/feed \
-H 'authorization: **authorization**'\
-H 'x-reset: 2018-08-29T00:00:00.000Z'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/payment/link/feed?all="");
curl_setopt($ch, CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/payment/link/feed',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void getTransactions(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/payment/link/feed")
.get()
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void getTransactions(){
RestClient client = new RestClient(host + "creditor/payment/link/feed");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
[{
"amount": 17.95,
"id": 3354,
"msg": "Betaling Factuur 123",
"ref": "J7F079OG00000",
"state": "paid"
},
{
"amount": 19.95,
"id": 3821,
"msg": "Rappel Factuur 101",
"ref": "KJEVMD5",
"state": "paid"
}
]
curl -X GET https://api.twikey.com/creditor/payment/link/feed?include=customer&include=meta \
-H 'authorization: **authorization**'\
-H 'x-reset: 2018-08-29T00:00:00.000Z'
[{
"id": 4613,
"ct": 0,
"amount": 15.0,
"msg": "Betaling Factuur 123",
"ref": "ABC123",
"state": "expired",
"customer": {
"email": "customer@mail.com",
"firstName": "John",
"lastName": "Doe",
"address": "streetname 100",
"city": "Brussel",
"zip": "1000",
"country": "BE",
"ref": "customer number",
"l": "nl",
"mobile": null
}
]
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
all | Include all non-paid updates too (by default only paid updates are returned) | No | boolean |
include | Include customer detail (include=customer) | No | String |
include | Include meta data (include=meta) | No | String |
Possible states
States | Description |
---|---|
Created | The payment link has been created but the customer did not do anything with it yet. |
Started | The customer has clicked on the payment link you transmitted him but did not complete the payment. In the Twikey dashboard the state will be shown as clicked. |
Pending | The customer started to pay, but did not complete the payment process. (only for iDeal, Paypal & Tikkie) |
Declined | The customer completed the payment process but the payment wasn't successful |
Paid | The customer paid the amount asked. |
Expired | The customer did not complete the payment before the expiration date you defined when creating the payment link. |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Refund paymentlink
Refund the full or partial amount of a payment link.
curl -x POST 'https://api.beta.twikey.com/creditor/payment/link/refund' \
-H 'authorization: **authorization**'\
-D 'id=123' \
-D 'message=refund' \
-D 'amount=25'
HTTP Request
POST /creditor/payment/link/refund
Supported PSP
Name | Supported |
---|---|
Mollie | Yes |
MultiSafePay | Yes |
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | Paymentlink ID | Yes | String |
message | Refund message | Yes | String |
amount | Full or partial amount (if not passed, full amount is used) | No | number |
HTTP response
{
"id": 123,
"amount": 25.0,
"msg": "refund"
}
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Error codes
Code | Description |
---|---|
err_contact_support | Error details in response "extra" |
err_fail_refund | Error details in response "extra" |
Remove paymentlink
Remove a payment link. Only paymentlinks with status 'created' can be removed, all other ones will be archived.
curl -X DELETE https://api.twikey.com/creditor/payment/link?id=123 \
-H 'authorization: **authorization**'
HTTP Request
DELETE /creditor/payment/link
Request Parameters
Name | Description | Required | Type |
---|---|---|---|
id | paymentlink ID | Yes) | string |
Meta data
Including meta data when you retrieve the status of one (or more) payment link(s) provides you with the following information:
- If the link was generated in a dunning step.
- If the link was generated in order to get an invoice paid
Request Response
HTTP response
{
"Links": [
{
"id": 77920,
"ct": 2223,
"amount": 6.0,
"msg": "123456789123",
"ref": "CF933-20200807073818839144-0",
"state": "created",
"meta": {
"sdd": "63884",
"tx" : "1234567"
}
},
{
"id": 77955,
"ct": 2223,
"amount": 10.0,
"msg": "124512454",
"ref": "CF933-202008070738447439143-0",
"state": "created",
"meta": {
"tx": "1234567"
},
{
"id": 76667,
"ct": 2223,
"amount": 100.0,
"msg": "123456789123",
"ref": null,
"state": "paid",
"meta": {
"invoice": "a48c77a7-349e-424b-bdfc-baa748ee9e55"
},
]
}
Meta parameters
Name | Description |
---|---|
tx | The transaction for which this link was generated |
sdd | The sdd transaction (state = failed) send to the bank for wich this link was generated |
invoice | The invoice uuid linked to the payment link |
While the tx can be returned if the link was generated on a transaction, the sdd will only be returned in the
context of dunning.
To retrieve related transaction, use the returned 'tx' id in the transaction status request.
Refunds (Credit Transfer)
Refunds can be used to completely or partially refund a transaction to a debtor. In exceptional cases, you may have to transfer funds from one account to another. This could be the case when you collected money that should be transferred to another person/company.
If the customer was not known, you may need to create a beneficiary account prior to making this call. In order to avoid extra costs on bank side an additional call to create the batch may be necessary or can be done automatically upon request.
Create/add a new credit transfer
Create or add a new credit transfer. This can only be done after the creation of the beneficary in case no signed SDD mandate exists. The customerNumber is strongly recommended since an account may be linked to multiple customers.
When no iban is specified in the call, if the customer has a signed sdd we use that iban for refunds.
HTTP Request
POST /creditor/transfer
curl https://api.twikey.com/creditor/transfer \
-H 'authorization: authorization' \
-d 'iban=BE68068897250734' \
-d 'customerNumber=123' \
-d 'message=test%20credit%20transfer' \
-d 'ref'='123' \
-d 'amount='0.00'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfer");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"iban=BE68068897250734"
."&customerNumber=123"
."&message=test credit transfer"
."&amount="50.00"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfer',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: {
"iban":"BE680688972.....",
"customerNumber":"123",
"message":"test credit transfer",
"amount":"50.00"
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody formBody = new FormBody.Builder()
.add("iban", "BE680688972.....")
.add("customerNumber","123")
.add("message","test credit transfer")
.add("amount", "50.00")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transfer")
.post(formBody)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/transfer");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded",
"iban=BE68068897250734" +
"&customerNumber=123" +
"&message=test credit transfer" +
"&amount=50.00"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"Entries": [
{
"id": "11DD32CA20180412220109485",
"iban": "BE12356798",
"bic": "BBRUBEBB",
"amount": 12,
"msg": "test",
"place": null,
"ref": "123",
"date": "2018-04-12"
}
]
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
customerNumber | The customer number | Yes | string |
iban | Iban of the beneficiary | Yes | string |
message | Message to the creditor (maximum length of 4x35 characters) | Yes | string |
ref | Reference of the transaction | No | String |
amount | Amount to be send | Yes | number |
date | Required execution date of the transaction (ReqdExctnDt) | No | string |
place | Optional place | No | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_invalid_iban | Invalid Iban |
403 | Account unregistered |
err_invalid_state | Mandate existed, but was not active |
err_invalid_date | Invalid date |
err_invalid_sepachars | Invalid message |
err_invalid_amount | Invalid amount |
Details of a credit transfer
Retrieve the details of a credit transfer by id. The id is the e2e id of the credit transfer upon creating the credit transfer. By hovering over the credit transfer in Twikey GUI, the E2E id appears.
HTTP Request
GET /creditor/transfer/detail
curl https://api.twikey.com/creditor/transfer/detail?id=609C16C920180919083905923 \
-H 'authorization: authorization'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfer/detail?id=609C16C920180919083905923");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfer/detail?id=609C16C920180919083905923',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
Request request = new Request.Builder()
.url(host + "/creditor/transfer/detail?id=609C16C920180919083905923")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/transfer/detail?id=609C16C920180919083905923");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
}
}
{
"Entries": [
{
"id": "609C16C920180919083905923",
"iban": "BE08001166979213",
"bic": "GEBABEBB",
"amount": 5,
"msg": "test",
"place": null,
"ref": "123",
"date": "2018-09-19",
"state": "PAID", // when paid
"bkdate": "2017-03-24" // when paid
}
]
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
id | id (e2e identifier) of the created refund | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_transaction | No such transaction |
Remove a credit transfer
Remove a single credit transfer.
HTTP Request
DELETE /creditor/transfer
curl -X DELETE https://api.twikey.com/creditor/transfer?id=123 \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfer?id=123");
curl_setopt($ch, CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transfer?id=123',
method: 'DELETE',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void removeTransaction(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transfer?id=123")
.delete(null)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void removeTransaction(){
RestClient client = new RestClient(host + "/creditor/transfer?id=123");
RestRequest request = new RestRequest(Method.DELETE);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
id | id of the created refund | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | User error if parameter is given but not valid (available in apierror header and response) |
Error codes
Code | Description |
---|---|
err_no_transaction | No such transaction |
Batch creation
Once the credit transfers are created, you need to create the batch with refunds to send to the bank. A batch can be created based upon the account from an existing contract template or new account. After the creation of the batch, the file needs to be processed in your bank environment. For some banks we can do the upload of the batch in your bank environment, for other banks you will need to download the batch from the Twikey dashboard via the menu Refunds. A refund must always be signed extra in your bank environment.
HTTP Request
POST /creditor/transfer/complete
curl https://api..twikey.com/creditor/transfer/complete \
-H 'authorization: authorization' \
-d 'ct=**ct_id**'
$host = "https://api.twikey.com";
$ct = "**ct_id**";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfer"/complete);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "ct=$ct");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
ct= "**ct_id**",
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfer/complete',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: {
"ct": ct
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String ct = "**ct_id**";
private String authorisation = null; //collected through logIn
public void completeCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody formBody = new FormBody.Builder()
.add("ct", ct)
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transfer/complete")
.post(formBody)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void completeCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/transfer/complete");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter(
"application/x-www-form-urlencoded",
"ct=" + ct,
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Template containing the originating account | Yes | string |
iban | Originating account, if different from ct account | No | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | Invalid request |
Batch details
Get all details from a specific batch
HTTP Request
GET /creditor/transfer/complete
curl https://api..twikey.com/creditor/transfer/complete \
-H 'authorization: authorization' \
-d 'id=**id**'
$host = "https://api.twikey.com";
$id = "**id**";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfer/complete?id=123");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
ct= "**ct_id**",
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfer/complete?id=123',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void completeCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
Request request = new Request.Builder()
.url(host + "/creditor/transfer/complete?id=123")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void completeCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/transfer/complete?id=123");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
id | Id of the batch previously submitted | No | string |
pmtinfid | PmtInfId of the batch previously submitted | No | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | Invalid request |
Error codes
Code | Description |
---|---|
err_invalid_params | No such batch available |
Get credit transfer feed
Retrieve list of credit transfers that have changes since the last call. If your system is out of sync or the full transaction database needs to be refreshed an optional "X-RESET" header can be passed. The format can be a timestamp like "2018-08-20T13:02:03Z". After that you will receive (all) transaction updates since that time again.
curl https://api.twikey.com/creditor/transfer \
-H 'authorization: **authorization**' \
-H 'x-reset: 2018-08-29T00:00:00.000Z'
$host = "https://api.twikey.com";
$authorization = null; // collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfer");
curl_setopt($ch, CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, // collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfer',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; // collected through login
public void getTransactions(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transfer")
.get()
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // collected through login
public void getTransactions(){
RestClient client = new RestClient(host + "/creditor/transfer");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
HTTP Request
GET /creditor/transfer
{
"Entries": [
{
"id": "IBWICD6E44Y1N3YRMCVB2U7BA",
"iban": "BE70361272935897",
"bic": "GDOENFY",
"amount": 1000,
"msg": "credit transfer message",
"place": null,
"ref": "123",
"date": "2017-01-20"
},
{
"id": "X52D04L9DNNPWKCRGBV7YPV2R",
"iban": "BE93261223700539",
"bic": "BRODBZL",
"amount": 12345,
"msg": "credit transfer message",
"place": "Brugge",
"ref": "456",
"date": "2018-01-23"
},
{
"id": "ZE31QPMT6GRMHEY7IPOOD219R",
"iban": "BE4447226747140",
"bic": "ORNSRAM",
"amount": 250099,
"msg": "",
"place": "Ghent",
"ref": "789",
"date": "2017-03-23",
"state": "PAID", // when paid
"bkdate": "2017-03-24"
},
"..."
]
}
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Get beneficiary accounts
Fetch a list of all customers' beneficiary accounts.
HTTP Request
GET /creditor/transfers/beneficiaries
curl https://api.twikey.com/creditor/transfers/beneficiaries?withAddress=true \
-H 'authorization: authorization'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfers/beneficiaries?withAddress=true");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfers/beneficiaries?withAddress=true',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
Request request = new Request.Builder()
.url(host + "/creditor/transfers/beneficiaries?withAddress=true")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/transfers/beneficiaries?withAddress=true");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
}
}
{
"beneficiaries": [
{
"name": "sdfsf",
"iban": "BE92221216720939",
"bic": "GEBABEBB",
"available": true,
"address": null
},
{
"name": "beneficiary2",
"iban": "BE16645348971174",
"bic": "JVBABE22",
"available": true,
"address": {
"street": "Veldstraat 11",
"city": "Gent",
"zip": "9000",
"country": "BE"
}
}
]
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
withAddress | include addresses in reponse | Yes | boolean |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
500 | System error |
Error codes
Code | Description |
---|---|
error_system | An error occured on the system |
Add a beneficiary account
In order to be able to do a refund, one needs to have a beneficiary account. The account can be either created explicitly via this call or implicitly via a signed SDD mandate. In the latter case, the account from the mandate is taken so you can immediately call the refund without this call.
Creating a beneficiary account can be done for an existing customer or a new one. This is done based on the customerNumber or in its absence the email address. If a customer is found, the address will also be updated if address, zip, city and country are passed on in the call.
For new customers and therefor new accounts, it is strongly advised to add the customerNumber as it allows you to reference them later for updates or creation of other objects such as contracts/mandate and/or paymentlinks. An address and name are mandatory, mobile and language are optional though recommended as it makes the customers journey better.
HTTP Request
POST /creditor/transfers/beneficiaries
curl -X POST https://api.twikey.com/creditor/transfers/beneficiaries \
-H 'authorization: authorization' \
-d 'customerNumber=123' \
-d 'email=support@twikey.com' \
-d 'name=Support Twikey' \
-d 'l=NL' \
-d 'mobile=32479123123' \
-d 'address=Derbystraat 43' \
-d 'zip="9051"' \
-d 'city=Sint Denijs Westrem' \
-d 'country=BE' \
-d 'iban=BE68068897250734' \
-d 'bic=JVBABE22'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfers/beneficiaries");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"&email=support%40twikey.com"
."&customerNumber=123"
."&name=Support Twikey"
."&l=NL"
."&address=Derbystraat%2043"
."&zip=9051"
."&city=Sint%20Denijs%20Westrem"
."&country=BE"
."iban=BE68068897250734"
."bic=JVBABE22"
);
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/transfers/beneficiaries',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: {
"customerNumber": "134",
"email": "support@twikey.com",
"name": "Support Twikey",
"l": "NL",
"address": "Derbystraat 43",
"zip": "9051",
"city": "Sint Denijs Westrem",
"country": "BE",
"iban": "BE68068897250734",
"bic": "JVBABE22"
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody formBody = new FormBody.Builder()
.add("customerNumber", "134")
.add("email", "support@twikey.com")
.add("name", "Support Twikey")
.add("l", "NL")
.add("address", "Derbystraat 43")
.add("zip", "9051")
.add("city", "Sint Denijs Westrem")
.add("country", "BE")
.add("iban","BE68068897250734")
.add("bic", "JVBABE22")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/transfers/beneficiaries")
.post(formBody)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/transfers/beneficiaries");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded",
"&customerNumber=123" +
"&email=support%40twikey.com" +
"&name=Support Twikey" +
"&l=NL" +
"&address=Derbystraat%2043" +
"&zip=9051" +
"&city=Sint%20Denijs%20Westrem" +
"&country=BE" +
"iban=BE68068897250734" +
"bic=JVBABE22"
, ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
{
"name": "Beneficiary Name",
"iban": "BE68068897250734",
"bic": "JVBABE22",
"available": true,
"address": {
"street": "Veldstraat 11",
"city": "Gent",
"zip": "9000",
"country": "BE"
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
customerNumber | The customer number | Yes | string |
name | Firstname & lastname of the debtor (required if debtor is not a company) | Yes | string |
Email of the debtor | No | string | |
l | language of the customer ISO format (2 letters) | No | string |
mobile | Mobile number required for sms (International format +32499123445) | No | string |
address | The street name and number/box | Yes | string |
city | City of debtor | Yes | string |
zip | Zipcode of debtor | Yes | string |
country | ISO format (2 letters) | Yes | string |
companyName | The company name (required if debtor is company) | Yes | string |
vatno | The enterprise number (if debtor is company) | No | string |
iban | IBAN of the beneficiary | Yes | string |
bic | BIC of the beneficiary | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
400 | Validation error due to wrong user input |
500 | System error |
Error codes
Code | Description |
---|---|
err_name_required | Invalid or missing name |
err_invalid_iban | Invalid IBAN number |
err_invalid_bic | Invalid BIC number |
error_system | An error occured on the system |
Disable a beneficiary account
Removal of a beneficiary can be done via an IBAN number, but it's strongly advisable to add the customerNumber in the call. This is optional for backwards compatible reasons, but strongly recommended as an account may be used on multiple customers. Note that the the beneficiary will be disabled and not deleted. Reactivating a beneficiary account can only be done using the interface.
HTTP Request
DELETE /creditor/transfers/beneficiaries/{IBAN}?customerNumber={customerNumber}
curl -X DELETE https://api.twikey.com/creditor/transfers/beneficiaries/BE16645348971174?customerNumber=123 \
-H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorization = null; /collected through logIn
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/transfers/beneficiaries/BE16645348971174?customerNumber=123");
curl_setopt($ch, CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, 'Authorization : $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through logIn
options = {
host: host,
port: '443',
path: '/creditor/transfers/beneficiaries/BE16645348971174?customerNumber=123',
method: 'DELETE',
headers: {
'Authorization': authorization
}
};
var req = https.request(options, function (res) {
console.log("result : ",result);
});
public class TwikeyAPI {
private String host = "https://api.twikey.com",
authorization = null; //collected through logIn
public void removeTransaction(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(host + "/creditor/transfers/beneficiaries/BE16645348971174?customerNumber=123")
.delete(null)
.addHeader("authorization", authorization)
.build();
Response response = client.newCall(request).execute();
};
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
authorization =null; // gathered through logIn
public void removeTransaction(){
RestClient client = new RestClient(host + "/creditor/transfers/beneficiaries/BE16645348971174?customerNumber=123");
RestRequest request = new RestRequest(Method.DELETE);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Authorization", authorization);
IRestResponse response = client.Execute(request);
}
}
HTTP Response
Code | Description |
---|---|
200 | the request has succeeded, no content |
400 | bad request, the IBAN provided is not valid |
404 | the entity was not found |
500 | system error |
Error codes
Code | Description |
---|---|
err_not_found | No such beneficary |
err_invalid_iban | No beneficary found for that IBAN |
err_fail_refund | Beneficiary account is disabled |
error_system | An error occured on the system |
Identification
Identification
Identification can be used to identify a customer using a third party (bank, government, ..).
When using this request, a url to their services is generated that can be used by the customer.
A template of type 'IDENT' is requested and a specific signing method.
Currently supported signing methods are Idin (Netherlands) and Itsme (Belgium).
It is possible to automatically create a signed mandate after identification, for this contact support@twikey.com
Fetch allowed banks
Return the banks that are currently connected to Idin
HTTP Request
GET /creditor/ident
curl https://api.twikey.com/creditor/ident \
-H 'authorization: authorization' \
-d 'ct=1234' \
-d 'method=idin'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/ident?ct=1234&method=idin");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/ident?ct=1234&method=idin',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
Request request = new Request.Builder()
.url(host + "/creditor/ident?ct=1234&method=idin")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/ident?ct=1234&method=idin");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Template number | Yes | number |
method | Method of identification | False | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Idin authentication url
Retrieve direct link from the bank
HTTP Request
POST /creditor/ident
curl https://api..twikey.com/creditor/ident \
-H 'authorization: authorization' \
-d 'ct=**ct_id**'
$host = "https://api.twikey.com";
$ct = "**ct_id**";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/ident");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "ct=$ct&bic=ABNANL2A");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
ct= "**ct_id**",
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/ident',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: {
"ct": ct,
"bic": 'ABNANL2A'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String ct = "**ct_id**";
private String authorisation = null; //collected through logIn
public void completeCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody formBody = new FormBody.Builder()
.add("ct", ct)
.add("bic","ABNANL2A")
.build();
Request request = new Request.Builder()
.url(host + "/creditor/ident")
.post(formBody)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void completeCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/ident");
RestRequest request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter(
"application/x-www-form-urlencoded",
"ct=" + ct,
"bic=ABNANL2A",
ParameterType.RequestBody
);
IRestResponse response = client.Execute(request);
}
}
Query parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Template containing the originating account | Yes | string |
bic | BIC Code of the bank to retrieve a url for | Yes | string |
HTTP Response
Code | Description |
---|---|
200 | The request has succeeded |
Itsme authentication url
Retrieve authentication url from Itsme
HTTP Request
POST /creditor/ident
Query parameters
Name | Description | Required | Type |
---|---|---|---|
ct | Identification template id | Yes | string |
method | Itsme | Yes | string |
l |
curl https://api.twikey.com/creditor/ident \
-H 'authorization: authorization' \
-d 'ct=1234' \
-d 'method=itsme'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$host/creditor/ident?ct=1234&method=itsme");
curl_setOpt($ch, CURLOPT_HTTPHEADER,"authorization: $authorization");
$server_output = curl_exec ($ch);
curl_close ($ch);
var https = require('https'),
querystring = require('querystring'),
host = "api.twikey.com",
authorization = null, //collected through login
options = {
host: host,
port: '443',
path: '/creditor/ident?ct=1234&method=itsme',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var req = https.request(options, function (res) {
console.log("response: " + res)
});
public class TwikeyApi{
private String host = "https://api.twikey.com";
private String authorisation = null; //collected through logIn
public void createCreditTransfer(){
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
Request request = new Request.Builder()
.url(host + "/creditor/ident?ct=1234&method=itsme")
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("authorization", authorisation)
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
}
}
public class TwikeyAPI {
private String host ="https://api.twikey.com",
ct = "**ct_id**",
authorisation = null; // collected through logIn
public void createCreditTransfer(){
RestClient client = new RestClient(host + "/creditor/ident?ct=1234&method=itsme");
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", authorisation);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
}
}
Webhooks
In order to reduce the number of polling requests, one can opt to implement a webhook endpoint and use this as a way to trigger polling requests. The endpoint is set in the API section of the settings screen and will convey information about various events in Twikey. The call is done via a simple GET with basic (non-sensitive) parameters eg. http://my.company.com/callback?type=contract&mandateNumber=MNDT123&state=signed...
In order to verify that the request is indeed coming from Twikey you can verify the 'X-Signature' header. This is a one-way encryption (HMAC256) of the url-decoded posted fields with your secret key (apiToken) converted into a hex encoded string.
You can test your implementation by using the 'Test' button in your environment (Api settings) which will send the sample payload 'msg=dummytest&type=event' as text.
note: URL encoded characters (E.g. %20, %2D, ..) have to be decoded to their original before calculating the X-Signature.
Retry mechanism
When a HTTP request is made, but we receive an error code (e.g. 3xx, 4xx, 5xx) the request is marked to be retried. All requests following this one will be suspended for a certain duration (currently 30min.)
We try up to 3 times after which the request will be archived and eventually removed. This allow us to resend the webhooks in case you have some issues on your end.
Note that the url to be given in the interface is without parameters since these are filled up depending on the type.
Types
type=contract
Triggered when something happens to the mandate. Activation events (when a mandate becomes suspended or gets resumed) will be included in the event=Update with the reason being either 'resumed" or 'suspended'
- mandateNumber : Mandatenumber
- contractNumber : Contract number
- state : New state of the mandate
- name : Name of the mandate
- event : Name of the event
- reason : Optional reason
curl -H "apiToken=MyToken" https://example.com/callback \
-d type=contract \
-d reason=resumed \
-d mandateNumber=CORE01 \
-d name=MyMandate \
-d contractNumber=454 \
-d state=SIGNED \
-d event=Update
type=plan
Triggered when a plan was executed
Extra parameters:
- name : Name of the plan that was executed
type=payment
Triggered when a batch of payments were received. Note that this is triggered for the batch and not per transaction as it could cause a flood of requests.
No parameters to avoid hammering your site when new transaction feedback is received
This is also triggered when a paymentlink was updated to either paid, rejected or expired. In that case you will receive the initial id, ref and status back.
type=dunning
Triggered when a dunning action was executed for a failed transaction
Extra parameters:
- mandateNumber : Mandatenumber
- txIds : Transaction ID
type=invoice
Currently not supported. You can use the payment type instead. This will give also give feedback when a payment for an invoice is received.
Exit Url
An alternative to a webhook can be the exit url or the page where the end-user is being redirected to after signing. This is a thank-you page or a redirect to an exit url defined on the template. This url can contain variables that are filled in depending on the outcome. The variables can either be positional of named.
- {0} / {{mandateNumber}} : mandate number
- {1} / {{status}} : status (ok = returned without error)
- {2} / {{account}} : iban/bic encrypted wih key privateKey+contract.getMandateNumber()
- {3} / {{s}} : signature over mandate and status separated by a slash (hex encoded)
- {4} / {{token}} : token (optional: if passed in the incoming url)
Some of the exceptional statusses can be (but not limited to):
- ok: document is signed
- cancel: cancel in the signing flow
- fail: signature / authentication failed
- pending: signature still pending (customer printed the document, extra signatures required)
In order to be sure that the return call is coming from Twikey, it's strongly recommended to verify the signature to the exit url. Calculation of the signature is done as described in Appendix E.
eg. an exit url with the following value
http:///website.com/{0}/{1}/{3}
or
http:///website.com/{{mandateNumber}}/{{status}}/{{s}}
would be expanded to if the end-customer returned without error
http:///website.com/MND123/ok/C9FB0D93...
Changes
January 2021
- 19/01 New request for transactions: refund a transaction
- 10/01 Allow paymentlinks to be retrieved via transaction (also in feed)
December 2020
- 17/12 Allow archiving of transaction
- 7/12 Ident response should also show mandate number
November 2020
23/11 Removed parameter 'form' in the invite request.
This parameter is not supported anymore. The form can be added in the companyName parameter instead.19/11 New invite or reminder request for invoices: action
Use the action request to send out the initial invitation or a reminder to the customer.
Can be done by email or sms.18/11 New parameter for credit transfers: ref
Add a reference to a credit transfer. Enables to create a reference of the transaction between our platform and your (booking) system.10/11 Move a mandate to another customer
Move a mandate to another customer using the mandate update request.09/11 Update or add a customer number
Update or add the customer number when updating mandate details.
July 2020
28/07 New request for invoices: Update invoice
Update title, date, due date and PDF on invoices.28/07 New parameter for payment links: invoice
Create a payment link to pay the total or partial amount of invoices.24/07 New parameter for beneficiary accounts: customerNumber
Ensure the beneficiary account is created on the correct customer.23/07 New parameter for payment links: sms
Send invites for payment links by sms.10/07 New identification method: Itsme
Itsme identification is now possible.
April 2020
29/04 New parameter for payment link feed 'include'
Added possibility of sideloading customers for paymentlinks29/4 Added ct parameter to payment link information
March 2020
23/03 Added parameters and return codes for invoices.
Improved documentation about states of invoices20/03 Renamed error from err_mandate_invalid_state to err_invalid_state
14/03 Improved webhook verification method added (X-Signature)
A newer verification method X-Signature was added to the header. The previous verification method can still be used, but will be dropped end of april
February 2020
- 17/02 Added HTTP request to add comments to a mandate
A new request was added to post a public or private comment on the audit trail of a mandate.
- 17/02 Added HTTP request to add comments to a mandate