Nav
bash php javascript java C#

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 enhanced security is setup, the private key allows the generation of a Time-based One-time password. View our sample code snippets on how to calculate this OTP in various languages.

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.

Find the API Key and security configuration in your Twikey Dashboard under Settings: Api

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

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

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 Email of the debtor No string (70 chars)
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
To update the address all address fields parameters 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
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 a mandate already exists, don't prepare a new one (based on email, customerNumber or mandatenumber and + template type(=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:

The first payment to sign this type of document is always a payment link.
Retrieve the mandate feed using a x-types header and/or the payment link feed to fetch details.

To add a plan in the invite request, an attribute named 'plan' and of type 'plan' need to be configured on the template*. To customize the plan attributes (amount, communication, ..) you can use the plan attributes. The plan is assigned when the end customer signs.

*: If a mandate is generated when signing a contract, the attribute 'plan' must be configured on the contract template.

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 :

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 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:

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). Recurring Credit Card is only fetched when passing the CREDITCARD x-types header.

In order too avoid polling, a webhooks 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.

curl https://api.twikey.com/creditor/mandate \
  -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");
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("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("authorization", authorisation);
        IRestResponse response = client.Execute(request);
    }
}
{
  "GrpHdr": {
    "CreDtTm": "2021-04-09T12:49:46Z"
  },
  "Messages": [
    {
      "Mndt": {
        "MndtId": "B2B38434",
        "LclInstrm": "B2B",
        "Ocrncs": {
          "SeqTp": "RCUR",
          "Frqcy": "ADHO",
          "Drtn": {
            "FrDt": "2021-04-09"
          }
        },
        "CdtrSchmeId": "BE81ZZZ1234567891",
        "Cdtr": {
          "Nm": "Merchant Company",
          "PstlAdr": {
            "AdrLine": "Companystreet 100",
            "PstCd": "1000",
            "TwnNm": "Brussel",
            "Ctry": "BE"
          },
          "Id": "BE0123456789",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "merchant.email@example.com"
          }
        },
        "Dbtr": {
          "Nm": "Twikey NV",
          "PstlAdr": {
            "AdrLine": "Derbystraat 43",
            "PstCd": "9051",
            "TwnNm": "Gent",
            "Ctry": "BE"
          },
          "Id": "BE0533800797",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "support@twikey.com",
            "Othr": "custNumber001"
          }
        },
        "DbtrAcct": "BE31798258915655",
        "DbtrAgt": {
          "FinInstnId": {
            "BICFI": "GKCCBEBB",
            "Nm": "BELFIUS BANK"
          }
        },
        "RfrdDoc": "Terms and Conditions",
        "SplmtryData": [
          {
            "Key": "SignerMethod#0",
            "Value": "maestro"
          },
          {
            "Key": "Signer#0",
            "Value": "Mock Maestro"
          },
          {
            "Key": "SignerPlace#0",
            "Value": "Ghent"
          },
          {
            "Key": "SignerDate#0",
            "Value": "2021-04-09T13:18:19Z"
          }
        ]
      },
      "EvtTime": "2021-04-09T13:19:19Z"
    },
    {
      "Mndt": {
        "MndtId": "NL-B2B60",
        "LclInstrm": "B2B",
        "Ocrncs": {
          "SeqTp": "RCUR",
          "Frqcy": "ADHO",
          "Drtn": {
            "FrDt": "2021-04-09"
          }
        },
        "MaxAmt": "1000",
        "CdtrSchmeId": "BE81ZZZ1234567891",
        "Cdtr": {
          "Nm": "Merchant Company",
          "PstlAdr": {
            "AdrLine": "Companystreet 100",
            "PstCd": "1000",
            "TwnNm": "Brussel",
            "Ctry": "BE"
          },
          "Id": "BE123456789",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "merchant.email@example.com"
          }
        },
        "Dbtr": {
          "Nm": "Twikey BV",
          "PstlAdr": {
            "AdrLine": "Bisschop de Vetplein 7",
            "PstCd": "5126CA",
            "TwnNm": "Gilze",
            "Ctry": "NL"
          },
          "Id": "65772989",
          "CtryOfRes": "NL",
          "CtctDtls": {
            "EmailAdr": "support@twikey.com",
            "Othr": "custNumber002"
          }
        },
        "DbtrAcct": "BE31798258923546",
        "DbtrAgt": {
          "FinInstnId": {
            "BICFI": "GKCCBEBB",
            "Nm": "BELFIUS BANK"
          }
        },
        "RfrdDoc": "General terms and conditions",
        "SplmtryData": [
          {
            "Key": "SignerMethod#0",
            "Value": "mock"
          },
          {
            "Key": "Signer#0",
            "Value": "Twikey Mock Signer"
          },
          {
            "Key": "SignerPlace#0",
            "Value": "Ghent"
          },
          {
            "Key": "SignerDate#0",
            "Value": "2021-04-09T12:49:42Z"
          }
        ]
      },
      "EvtTime": "2021-04-09T13:19:34Z"
    },
    {
      "AmdmntRsn": {
        "Orgtr": {
          "Nm": "Twikey NV",
          "PstlAdr": {
            "AdrLine": "Derbystraat 43",
            "PstCd": "9000",
            "TwnNm": "Gent",
            "Ctry": "BE"
          },
          "Id": "BE0533800797",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "support@twikey.com"
          }
        },
        "Rsn": "_T50"
      },
      "Mndt": {
        "MndtId": "CF2498",
        "LclInstrm": "CORE",
        "Ocrncs": {
          "SeqTp": "RCUR",
          "Frqcy": "ADHO",
          "Drtn": {
            "FrDt": "2021-04-09"
          }
        },
        "CdtrSchmeId": "BE81ZZZ1234567891",
        "Cdtr": {
          "Nm": "Merchant Company",
          "PstlAdr": {
            "AdrLine": "Companystreet 100",
            "PstCd": "1000",
            "TwnNm": "Brussel",
            "Ctry": "BE"
          },
          "Id": "BE123456789",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "merchant.email@example.com"
          }
        },
        "Dbtr": {
          "Nm": "Company NV",
          "PstlAdr": {
            "AdrLine": "streetname 100",
            "PstCd": "1000",
            "TwnNm": "Brussel",
            "Ctry": "BE"
          },
          "Id": "BE0154521254",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "customer.email@example.com",
            "Othr": "custNumber00125"
          }
        },
        "DbtrAcct": "BE12123356223353",
        "DbtrAgt": {
          "FinInstnId": {
            "BICFI": "GKCCBEBB",
            "Nm": "BELFIUS BANK"
          }
        },
        "RfrdDoc": "HvvGeWz627a",
        "SplmtryData": [
          {
            "Key": "SignerMethod#0",
            "Value": "print"
          },
          {
            "Key": "Signer#0",
            "Value": "customer.email@example.com"
          },
          {
            "Key": "SignerPlace#0",
            "Value": "(Imported)"
          },
          {
            "Key": "SignerDate#0",
            "Value": "2021-04-09T10:03:44Z"
          }
        ]
      },
      "OrgnlMndtId": "CF2498",
      "CdtrSchmeId": "BE81ZZZ1234567891",
      "EvtTime": "2021-04-09T13:26:53Z"
    },
    {
      "CxlRsn": {
        "Orgtr": {
          "Nm": "Twikey NV",
          "PstlAdr": {
            "AdrLine": "Derbystraat 43",
            "PstCd": "9000",
            "TwnNm": "Gent",
            "Ctry": "BE"
          },
          "Id": "BE0533800797",
          "CtryOfRes": "BE",
          "CtctDtls": {
            "EmailAdr": "support@twikey.com"
          }
        },
        "Rsn": "Custom cancel reason"
      },
      "OrgnlMndtId": "CF2506",
      "CdtrSchmeId": "BE81ZZZ1234567891",
      "EvtTime": "2021-04-09T13:30:51Z"
    }
  ]
}

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

Headers

Name Value Description
x-types CREDITCARD To retrieve the feed of recurring credit cards

Response

Code Description
200 The request has succeeded

Signed, Updated, Cancelled

Signed

A signed mandate will be returned in the feed including all the mandate, creditor, debtor details and the supplementary data.
Supplementary data returns several keys:
Each person that signed the document will be returned for each key using consecutive numbers #0, #1, .. .

This is returned in the "SplmtryData[key|value]" array.

Updated

When a document is updated, it is returned in the feed as amendment with initiator and reason:

The "Rsn" value informs you about the change, this can be information on the mandate that was updated or information about the mandate state.
Examples:

Cancelled

When a mandate was cancelled, this is returned as Cancelled reason with initiator and reason:

The "Rsn" value can be a custom reason the user, bank or debtor entered on cancellation.
This can also contain the reason of cancellation in case of automated dunning steps.
Examples:

Read the high level structure document for a more in depth explanation.

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("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
PRINT 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
Print 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. Note: Mobile number and email are always updated on both the mandate and customer.

curl POST 'https://api.twikey.com/creditor/mandate/update' \
--h 'Authorization: ....' \
--d 'mndtId=MDT123' \
--d'address=Derbystraat 43' \
--d 'zip=9000' \
--d 'city=Gent' \
--d 'country=BE' \
--d'iban=BE32 1234 1234 1234' \
--d 'bic=BRUBBEB'
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/mandate/update',
  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 => 'mndtId=MDT123&address=Derbystraat%2043&zip=9000&city=Gent&country=BE&iban=BE32%201234%201234%201234&bic=BRUBBEB',
  CURLOPT_HTTPHEADER => array(
    'Authorization: ....'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
var myHeaders = new Headers();
myHeaders.append("Authorization", "....");

var urlencoded = new URLSearchParams();
urlencoded.append("mndtId", "MDT123");
urlencoded.append("address", "Derbystraat 43");
urlencoded.append("zip", "9000");
urlencoded.append("city", "Gent");
urlencoded.append("country", "BE");
urlencoded.append("iban", "BE32 1234 1234 1234");
urlencoded.append("bic", "BRUBBEB");

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: urlencoded,
  redirect: 'follow'
};

fetch("https://api.twikey.com/creditor/mandate/update", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "mndtId=MDT123&address=Derbystraat 43&zip=9000&city=Gent&country=BE&iban=BE32 1234 1234 1234&bic=BRUBBEB");
Request request = new Request.Builder()
  .url("https://api.twikey.com/creditor/mandate/update")
  .method("POST", body)
  .addHeader("Authorization", "....")
  .build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/mandate/update");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "....");
request.AddParameter("mndtId", "MDT123");
request.AddParameter("address", "Derbystraat 43");
request.AddParameter("zip", "9000");
request.AddParameter("city", "Gent");
request.AddParameter("country", "BE");
request.AddParameter("iban", "BE32 1234 1234 1234");
request.AddParameter("bic", "BRUBBEB");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

HTTP Request

POST https://api.twikey.com/creditor/mandate/update

Query Parameters

B2B type mandate: iban cannot be updated once the document is signed.

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 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)
err_invalid_state mandate state is invalid: some query parameters are invalid or not allowed in the current state.

Move a mandate

It is possible to move the mandate to another customer (owner).
Include the customer number of the target in the request.

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

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
refase2e The reference is used as E2E identifier for the first payment
Conform with the Rule Book of the EPC.
No boolean

[*1]: This is the message that both you and your customer will see on their bank statement. More info..

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. This endpoint allows to retrieve a list of 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".

The final flag is important as it indicates whether or not there are still automatic actions going on. 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 where no more automatic actions can be performed. Here an action will be required on your part. False means that we still have actions pending to debit the debtor's account. Note that paid can be reverted by the bank.

curl 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, '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);
    }
}
{
    "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
        },
        "..."
    ]
}

Include all parameters:

{
"Entries": [
{
    "id": 218914,
    "contractId": 1320345,
    "mndtId": "MNDT123",
    "contract": "CTR123",
    "amount": 5.63,
    "msg": "Delivery fee",
    "place": null,
    "ref": "DLVRY EXPRESS 001",
    "date": "2020-12-09T16:07:19Z",
    "final": true,
    "state": "ERROR",
    "bkerror": "AM04",
    "bkmsg": "Insufficient funds",
    "bkdate": "2020-12-09",
    "lastupdate": "2020-12-09T16:07:24Z",
    "bkamount": 0,
    "collection": 9314,
    "reqcolldt": "2020-12-11",
    "actions": [
    {
        "type": "FAIL_SOFT",
        "reason": "AM04",
        "action": "again",
        "at": "2020-12-09T16:07:24Z"
    },
    {
        "type": "FAIL_SOFT",
        "reason": "AM04",
        "action": "backup",
        "at": "2020-12-10T03:30:09Z"
    }
       ]
     }
   ]
}

HTTP Request

GET /creditor/transaction

Query Parameters

Name Description Required Type
chunkSize Amount of transactions to return per call (max 100) No long

include parameter

This parameter can be added multiple times with different values

Name Value Description
include collection returns the batch id
include lastupdate returns the last update in datetime format and 'bkdate' as date.
include action returns the dunning steps taken for a transaction

Dunning steps (actions)

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 No more actions are pending. Manual action is required if the state is in error
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": [
        {
            "id": 1234,
            "amount": 10.0,
            "contract": "Algemene voorwaarden",
            "contractId": 325638,
            "date": "2017-09-16T14:32:05Z",
            "mndtId": "MNDT123",
            "msg": "Monthly payment",
            "place": null,
            "ref": null,
            "state": "OPEN",
            "reqcolldt": "2021-01-11"
        }
    ]
}

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

include parameter

This parameter can be added multiple times with different values

Name Value Description
include collection returns the batch id
include lastupdate returns the last update in datetime format and 'bkdate' as date.

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

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 on 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, backup*, archive

*backup: alternative payment method is sent to the customer by email. This can include a payment link or bank transfer details depending on your configuration.

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
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

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

This endpoint allows to retrieve an SDD batch. 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.

The final flag is important as it indicates whether or not there are still automatic actions going on. 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 where no more automatic actions can be performed. Here an action will be required on your part. False means that we still have actions pending to debit the debtor's account. Note that paid can be reverted by the bank.

HTTP Request

GET /creditor/collect

curl https://api.twikey.com/creditor/collect \
  -H 'authorization: **authorization**'
$host = "https://api.twikey.com";
$authorisation = null; //collected through login

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "$host/creditor/collect");
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/collect',
        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 authorization = null; //collected through logIn

    public void statusCollection(){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
          .url(host + "/creditor/collect")
          .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",
        authorisation = null; // collected through logIn

    public void statusCollection(){
        RestClient client = new RestClient(host + "/creditor/collect");
        RestRequest request = new RestRequest(Method.GET);
        request.AddHeader("authorization", authorisation);
        IRestResponse response = client.Execute(request);
    }
}
{
    "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 continue dunning)
                    "state": "error", // Transaction was paid but customer requested a refund
                    "bkamount": 30.0,
                    "bkdate": "2015-07-27",
                    "bkerror": "MD06" // Actual error code (refund request)
                },
                {
                    "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"
                }
            ]
        }
    ]
}

Query parameters

Name Description Required Type
id Specific SDD reference No number
pmtinfid Specific Payment identifier No string

HTTP Response

Code Description
200 The request has succeeded

Import Collection

Import a direct debit batch for collection. When the batch is imported and valid, it is directly sent to the bank for processing. Accepted format: Pain 008.001.02 (ISO 20022)

HTTP Request

POST /creditor/collect/import The Direct Debit message can be imported as file or as XML in the body of the request.

curl --location --request POST 'https://api.twikey.com/creditor/collect/import' \
-h 'authorization: **authorization**' \
-h 'Content-Type: application/xml' \
-d '@path/to/batch.xml'
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/collect/import',
  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 => "<file contents here>",
  CURLOPT_HTTPHEADER => array(
    'Authorization: $authorization',
    'Content-Type: application/xml'
  ),
));

$response = curl_exec($curl);
$result = json_decode($response);

curl_close($curl);
var data = "<file contents here>",
    authorization = null; //collected through login

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://api.twikey.com/creditor/collect/import");
xhr.setRequestHeader("Authorization", authorization);
xhr.setRequestHeader("Content-Type", "application/xml");

xhr.send(data);
public class TwikeyApi{
    private String host = "https://api.twikey.com";
    private String authorization = null; //collected through logIn

    public void importCollection(){
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/xml");
RequestBody body = RequestBody.create(mediaType, "<file contents here>");
Request request = new Request.Builder()
  .url(host + "/creditor/collect/import")
  .method("POST", body)
  .addHeader("Authorization", authorization)
  .addHeader("Content-Type", "application/xml")
  .build();
Response response = client.newCall(request).execute();
    }
}
public class TwikeyAPI {
    private  String host ="https://api.twikey.com",
                    authorization = null; // collected through logIn

    public void importCollection(){
var client = new RestClient(host + "/creditor/collect/import");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", authorization);
request.AddHeader("Content-Type", "application/xml");
request.AddParameter("application/xml", "<file contents here>", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
  }
}

HTTP Response

Code Description
200 The request has succeeded
400 Bad request

Error codes

Code Description
invalid_file Invalid format or file already uploaded*

*Collection with the same value of 'PmtInfId' and 'EndToEndId' was already uploaded.

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 collections. Both can be polled periodically or triggered by a callback.

Account reporting

Get account reporting, this endpoint allows you to retrieve a stream of items listed on your account as soon as they're made available from the bank.

Returns all reporting since the last call.

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);
    }
}
{
    "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"
        }
    ]
}

HTTP Response

Code Description
200 The request has succeeded

Error codes

Code Description

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 template, different payment options are provided to the customer.

HTTP Request

POST /creditor/invoice

curl -X POST https://api.twikey.com/creditor/invoice \
  -H 'authorization: **authorization**' \
  -H "Content-Type: application/json" \
  -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://app.twikey.com/<company_id>/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" \
  -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://app.twikey.com/<company_id>/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://app.twikey.com/<company_id>/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://app.twikey.com/<company_id>/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://app.twikey.com/<company_id>/fec44175-b4fe-414c-92aa-9d0a7dd0dbf2"
      }'

Header X-Purpose:

Use X-Purpose to alter the url for specific use cases

Value Description
qr (default) Returns a url that can be used in different bank apps.
redirect Returns a branded-url for generic use cases (faster)
merchant Returns a url that can be used over the counter

Request Parameters

Invoice Object

Name Description Required Type
id UUID of the invoice (optional) No string (36)
number Invoice number [*1] Yes string
title Message to the debtor [*2] Yes string (140)
remittance Payment message, if empty then title will be used [*3] 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
customer Customer Yes object
customerByDocument Customer by document reference No string
pdf Base64 encoded document No string

Customer Object

Name Description Required Type
customerNumber The customer number to link this invoice too (strongly advised) Yes* string
email 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

[1]: If an invoice with this number already exist, it will return the invoice details instead.
[2]: This is the message that your customer will see on their bank statement. More info..
[3]: 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
err_debtor_id_missing A customer number or email address is missing in the customer object

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
pdf 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.

curl https://api.twikey.com/creditor/invoice \
  -H 'authorization: **authorization**' 
$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
GET /creditor/invoice/{{invoice_id}} (to retrieve a specific invoice)

Request Parameters

The parameter 'include' can be reused in the url several times with a different value.
'include=lastpayment' replaces the prior parameter 'include=paymentdetail' offering more details.

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
include lastpayment List details about the method and state of executed payments No string
{
    "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://app.twikey.com/<company_id>/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
email Send invitation by email
sms Send invitation by sms
reminder 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

Reconciliation files can be generated in CAMT053 or CODA.
Direct debit files are available 3 days after sending the transactions to the bank.
Payment link files are available every day for payments done the prior day(s).

When using Mollie for your settlements the frequency can vary. Please contact Mollie for more information about settlements.

HTTP Request

POST /creditor/files

curl POST 'https://api.twikey.com/creditor/files' \
--h 'Authorization: .....' \
--d 'sdd=false' \
--d 'format=coda' \
--d 'paylink=true'

$ch = curl_init();
$authorization = null; // collected through logIn

curl_setopt_array($ch, array(
  CURLOPT_URL => "https://api.twikey.com/creditor/files",
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "sdd=true&paylink=true&format=coda",
  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/files',
        method: 'POST',
        headers: {
            'Authorization': authorization
        },
        body :{
            'sdd:' 'true',
            'paylink:' 'true',
            'format:' : 'coda'
        }
    };

var req = https.request(options, function (res) {
    console.log("result : ",result);
});
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "sdd=false&format=coda&paylink=true");
Request request = new Request.Builder()
  .url("https://api.twikey.com/creditor/files")
  .method("POST", body)
  .addHeader("Content-Type", "application/x-www-form-urlencoded")
  .addHeader("Authorization", "....")
  .build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/files");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "....");
request.AddParameter("sdd", "false");
request.AddParameter("format", "coda");
request.AddParameter("paylink", "true");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

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). Default is camt 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)
X-FILES-CREATED included in the header when files are generated, returns the number of files generated

Error codes

Code Description
err_invalid_params Parameters are invalid

List Files

Return a list of reconciliation files.
The list returned include the files generated since this request was lasted performed.
To retrieve files older then this you can add a X-RESET header to reset the feed to an earlier time.
The value of the header is in UTC (standard ISO) format.

HTTP Request

GET /creditor/files

curl GET 'https://api.twikey.com/creditor/files' \
--h 'Authorization: ...'

response:

{
    "Files": [
        {
            "name": "sdd_twikey_BE81ZZZ0000000000--201222090211-2223.cod",
            "created": "2021-03-16T17:28:38Z"
        },
        {
            "name": "sdd_twikey_BE81ZZZ0000000000--201222090212-2223.cod",
            "created": "2021-03-16T17:28:38Z"
        }
      ]
  }
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/files',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'Authorization: ...'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
var myHeaders = new Headers();
myHeaders.append("Authorization", "...");

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  redirect: 'follow'
};

fetch("https://api.twikey.com/creditor/files", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
Request request = new Request.Builder()
  .url("https://api.twikey.com/creditor/files")
  .method("GET", null)
  .addHeader("Authorization", "...")
  .build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/files");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "...");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

HTTP Response

Code Description
200 The request has succeeded

Download File

Download reconciliation files.

HTTP Request

GET /creditor/files/filename

curl GET 'https://api.twikey.com/creditor/files/sdd_twikey_BE81ZZZ0000000000--201222090211-2223.cod' \
--h 'Authorization: .....'
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/files/sdd_twikey_BE81ZZZ0000000000-201222090211-2223.cod',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'Authorization: ....'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
var myHeaders = new Headers();
myHeaders.append("Authorization", "....");

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  redirect: 'follow'
};

fetch("https://api.twikey.com/creditor/files/sdd_twikey_BE81ZZZ0000000000--201222090211-2223.cod", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
Request request = new Request.Builder()
  .url("https://api.twikey.com/creditor/files/sdd_twikey_BE81ZZZ0000000000--201222090211-2223.cod")
  .method("GET", null)
  .addHeader("Authorization", "....")
  .build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/files/sdd_twikey_BE81ZZZ0000000000--201222090211-2223.cod");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "....");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Query parameters

Name Description Required Type
filename the filename Yes String

HTTP Response

Code Description
200 The request has succeeded

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 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 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 (200)
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:

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",     // title of the paymentlink
   "ref": "My Ref",   // remittance of the paymentlink
   "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
include Include customer detail (include=customer) No string
include Include meta data (include=meta) No string
include Include time data (include=time) 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

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**'
$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&include=time \
  -H 'authorization: **authorization**'
{
        "links": [
            {
                "id": 228192,
                "ct": 2223,
                "amount": 12.19,
                "msg": "Order-id 10058",
                "ref": "R10058",
                "state": "paid",
                      "customer": {
                          "id": 1010238,
                          "email": "email@example.com",
                          "firstname": "Smith,",
                          "lastname": " Douglas",
                          "address": "Derbystraat  43",
                          "city": "Gent",
                          "zip": "9000",
                          "country": "BE",
                          "customerNumber": "de8f0be99b1b2521c7a74a5067b5d85f",
                          "l": "nl",
                          "mobile": null
                                   },
                      "meta": {
                            "active": false,
                            "sdd": "130542",
                            "tx": "255733"
                               },
                     "time": {
                          "creation": "2021-05-03T07:42:40Z",
                          "expiration": "2021-05-17T07:42:40Z",
                          "lastupdate": "2021-05-03T07:44:00Z"
                             }
                          },
            {
                "id": 244041,
                "ct": 2223,
                "amount": 449.87,
                "msg": "Invoice February",
                "ref": "invoice-2021-02",
                "state": "paid",
                      "customer": {
                            "id": 1200553,
                            "email": "email@example.com",
                            "firstname": "John",
                            "lastname": "Smith",
                            "address": "Derbystraat 43",
                            "city": "Gent",
                            "zip": "9000",
                            "country": "BE",
                            "customerNumber": "5921071",
                            "l": "nl",
                            "mobile": "+3283838383"
                                  },
                      "meta": {
                            "active": false,
                            "method": "bancontact",
                            "invoice": "d133b08b-fe06-445b-81ff-6846a568d71f"
                               },
                      "time": {
                            "creation": "2021-05-06T15:16:52Z",
                            "lastupdate": "2021-05-06T15:16:55Z"
                              }

          } 
}

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
include Include time data (include=time) 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.

Response Parameters

meta

Payment links used to pay invoices or direct debit transactions (in case of dunning for example) will include additional meta data.
Dependant the case, different response parameters are returned.

Parameter Description
active the payment link url is still valid (true, false)
sdd internal sdd identifier (Twikey)
tx transaction id returned when linked to a transaction
method the method of payment. Not returned when linked to a direct debit
invoice invoice unique identifier returned when linked to an invoice

time

Parameter Description
creation creation of the payment link
expiration expiry of the payment link. Not returned when there is none
lastupdate last time the payment link was updated

A payment link can have a state 'active': false when the expiration date is not set or not yet reached.
The link is then already invalidated in a different way (paid, archived,..).

HTTP Response

Code Description
200 The request has succeeded

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 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:

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 Yes string (140)
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.

curl https://api.twikey.com/creditor/transfer \
  -H 'authorization: **authorization**' 
$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 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);
    }
}

Blacklist

When there is (suspected) abuse or another valid reason, you can add bank accounts to a blacklist.
Bank accounts listed can't be used to register new mandates, existing mandates registered with this iban can be suspended or cancelled.
The option to notify the customer will trigger the standard email informing the customer that their mandate was suspended, reactivated or cancelled.

Blacklisting is available in the Enterprise subscription.

Add accounts

When adding a bank account to the blacklist a parameter can be passed to change the state of all the mandates registered with this iban.
"passive": The mandate is suspended.
"cancel": The mandate is cancelled.

curl -X POST 'https://api.twikey.com/creditor/ibanblacklist' \
--h 'Authorization: {{authorization}}' \
--d' rsn=IBAN blacklisted' \
--d 'iban=BE123456789123456' \
--d 'notify=false' \
--d 'state=passive' \

response

 "iban": "BE123456789123456",
    "rsn": "IBAN blacklisted",
    "state": "passive",
    "updatedMandates": [
        {
            "mndtId": "MNDT123"
        }
                        ]
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/ibanblacklist',
  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 => 'rsn=IBAN%20blacklisted&iban=BE123456789123456&notify=false&state=passive',
  CURLOPT_HTTPHEADER => array(
    'Authorization: $authorization'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

HTTP Request

POST https://api.twikey.com/creditor/ibanblacklist

Query Parameters

Name Description Required Type
iban bank account to add to the blacklist Yes string
rsn reason Yes string
state update all mandates state registered with this iban (passive, cancel) No string
notify notify the customer by email No boolean

HTTP Response

Code Description
200 Request succeeded
400 Invalid or missing parameter(s)

Error codes

Code Description
err_provide_reason Reason is missing
err_invalid_params invalid or missing parameter

List accounts

Retrieve a list of all the bank accounts currently blacklisted.

curl GET 'https://api.twikey.com/creditor/ibanblacklist' \
--h 'Authorization: {{authorization}}' \

response

[
    {
        "iban": "BE123456789123456",
        "rsn": "IBAN blacklisted"
        },
    {
        "iban": "BE33445566889988",
        "rsn": "Suspected abuse"
    }
]
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/ibanblacklist',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'Authorization: $authorization'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
var myHeaders = new Headers();
var authorization = '.......';

myHeaders.append("Authorization", authorization);

var urlencoded = new URLSearchParams();

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  body: urlencoded,
  redirect: 'follow'
};

fetch("https://api.twikey.com/creditor/ibanblacklist", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
Request request = new Request.Builder()
  .url("https://api.twikey.com/creditor/ibanblacklist")
  .method("GET", null)
  .addHeader("Authorization", ".......")
  .build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/ibanblacklist");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "........");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

HTTP Request

GET https://api.twikey.com/creditor/ibanblacklist

HTTP Response

Code Description
200 Request succeeded

Remove accounts

Remove prior added accounts from the blacklist.
Suspended mandates can be reactivated using this request.

curl -X DELETE 'https://api.twikey.com/creditor/ibanblacklist' \
--h 'Authorization: {{authorization}}' \
--d 'iban=BE123456789123456' \
--d 'state=active' \
--d 'notify=false' \


response

 "iban": "BE123456789123456",
    "state": "active",
    "updatedMandates": [
        {
            "mndtId": "MNDT123"
        }
                        ]
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.twikey.com/creditor/ibanblacklist?iban=BE123456789123456&state=active&notify=false',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_HTTPHEADER => array(
    'Authorization: $authorization'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
var myHeaders = new Headers();
myHeaders.append("Authorization", "......");

var urlencoded = new URLSearchParams();

var requestOptions = {
  method: 'DELETE',
  headers: myHeaders,
  body: urlencoded,
  redirect: 'follow'
};

fetch("https://api.twikey.com/creditor/ibanblacklist?iban=BE123456789123456&state=active&notify=false", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
  .url("https://api.twikey.com/creditor/ibanblacklist?iban=BE123456789123456&state=active&notify=false")
  .method("DELETE", body)
  .addHeader("Authorization", "......")
  .build();
Response response = client.newCall(request).execute();
var client = new RestClient("https://api.twikey.com/creditor/ibanblacklist?iban=BE123456789123456&state=active&notify=false");
client.Timeout = -1;
var request = new RestRequest(Method.DELETE);
request.AddHeader("Authorization", "......");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

HTTP Request

DELETE https://api.twikey.com/creditor/ibanblacklist

Query Parameters

Name Description Required Type
iban bank account to remove from the blacklist Yes string
state reactivate all suspended mandates using this iban (active) No string
notify notify the customer by email No boolean

HTTP Response

Code Description
200 Request succeeded
400 Invalid or missing parameter(s)

Error codes

Code Description
err_invalid_params invalid or missing parameter

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.

Setup the different webhooks in your Twikey Dashboard under 'Settings: Api'.
Activate up to four differen categories (documents, payments, customer updates and other events).

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.

$apiKey = "**API_KEY**";
$message= urldecode($_SERVER['QUERY_STRING']);
$xsignature= hash_hmac('sha256', $message, $apiKey);

$provided_signature= $_SERVER['HTTP_X_SIGNATURE']; // To verify that both signatures match

echo $xsignature;

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

curl -H "apiToken=MyToken" https://example.com/callback \
    -d type=contract \
    -d reason=resumed \
    -d mandateNumber=CORE01 \
    -d name=<empty> \
    -d contractNumber=General terms and conditions \
    -d state=SIGNED \
    -d event=Update

Triggered when something happens to the mandate. Activation events will be
included in the event=Update with the reason being either 'resumed' or 'suspended'.
Update events can also contain a specific _Txx code.

Specific codes:
  • _T50 Account changed
  • _T51 Address changed
  • _T52 MandateNumber changed
  • _T53 Name changed
  • _T54 Email changed
  • _T57 Owner Mandate changed

type=plan

Triggered when a plan was executed

Extra parameters:

type=customer

Triggered on customer updates.

Eg. When two customers are merged, you receive a webhook for both customers.
If a customer has documents, you'll recieve a webhook with type=contract for every document.

type=payment (batch)

type=payment (batch)

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

type=payment (payment links)
amount 45.42
ct      2223
id      186229
ref     123456
status  paid
type    payment

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=payment (invoices)

type=payment (invoices)
amount  168.05 
ct      2223 
id      186402 
ref     813124990774 
status  paid 
type    payment

Currently we do not provide a dedicated webhook for invoices.
The type=payment can be used instead when the invoice is paid by direct payment.
You will receive the linked paymentlink id and ref (remittance of the invoice).

type=dunning

type=dunning
mandateNumber    MNDT123
txIds            [258802]
type             dunning

Triggered when a dunning action was executed for a failed transaction.
Option to notify 'webhook' must be activated in the dunning actions.

Extra parameters:

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 or named.

Some of the exceptional statusses can be (but not limited to):

Exit url's can be defined for mandates and invoices as described in How to define an exit URL.

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. View our sample code snippets to find examples in various languages on how to calculate the signature.

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