Integration Guide for Payment (Flex.API)

Introduction

Secupay's pay simple and safe system enables online processing of payment transactions in Internet shops and on Internet portals. This guide describes how to handle e-commerce payments with the Flex.API, version 2. There are other integration guides for the secuconnect API, or to integrate more sophisticated services for marketplaces, crowd investment platforms, and the like.

The integration guide begins with a Getting Started section, that explains the basic concepts and important key terms. In this section, you will learn how to create a first order and start the Payment Wizard. We recommend to study the Getting Started section thoroughly. The remaining sections, Reference and Troubleshooting can be accessed when needed. Should you require assistance with integration or further order processing, our support staff will be happy to help.

Getting Started

Introduction to Flex.API

The Flex.API uses HTTPS to create payment transactions or to perform other actions. (Unencrypted HTTP is not offered for security reasons. But we will use the term HTTP when we refer to request methods, headers, and the like.) The data can be represented in JSON or XML.

There are two possible workflows:

  • sale: The money is captured immediately. (Invoice payment needs an additional call to capture.)

  • authorization: The payment is only authorized. It needs a subsequent interface call to actually capture the money.

Every payment transaction is predetermined to a particular payment method.

Working Example

In our brief example we will create a payment transaction direct debit, using the sale flow. Then we will start the payment iframe. We will use JSON as data transfer format.

These are the steps we will do:

  1. We obtain the available payment methods. This is not necessary, but recommended, and easy to achieve.

  2. We create the payment transaction, and direct the customer to the Payment Wizard.

  3. We obtain the status of the transaction when the customer is returned. This is not necessary, but recommended, and easy to achieve.

Step 1: Obtain the Available Payment Methods

First we send a GET request to /payment/gettypes to obtain the available payment methods. This is our HTTP request, directed to our test system:

GET /payment/gettypes HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey":"6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace"
}
}

Note: The needed API key can be requested from our customer service.

This would be our response:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8;
...
 
{
"status": "ok",
"data": [
"prepay",
"debit",
"invoice",
"creditcard",
"sofort"
],
"errors": null
}

The returned payment methods correspond one-to-one with the field payment_type of the next step. As you see, a lot of different payment methods are active here.

Step 2: Create the Payment Transaction

Knowing direct debit would work, we offer it to our customer. Since our example uses the sale flow it must be offered at the end of your checkout process. The customer will close the contract with you together with the payment.

Here is our example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json;
Accept-Charset: utf-8
 
{
"data":{
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"demo": 1,
"payment_type": "debit",
"currency": "EUR",
"amount": "1995",
"purpose": "Test Order",
"url_success": "https://example.org/SUCCESS",
"url_failure": "https://example.org/FAILURE",
"url_push": "https://example.org/PUSH",
"language": "de_DE",
"title": "Herr",
"firstname": "Max",
"lastname": "Mustermann",
"street": "Musterstr.",
"housenumber": "112 a",
"zip": "09555",
"city": "Musterhausen",
"country": "DE",
"telephone": "+495555555555",
"dob_value": "01.02.1903",
"email": "max@example.org"
}
}

As you see, the request is an HTTP POST to https://api-testing.secupay-ag.de/payment/init. The payment is about €19,95. (We expect the smallest currency unit in the amount.)

You see also a demo flag. Although it has no extra effect on the testing server, it is good to know it. You can use it in the productive environment to create payment transactions that are not being captured.

This is the response of the server:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8;
...
 
{
"status": "ok",
"data": {
"hash": "tujevzgobryk3303",
"iframe_url": "https://api-testing.secupay-ag.de/payment/tujevzgobryk3303"
},
"errors": null
}

Everything worked. The payment transaction is created.

Note

To successfully carry out a demo transaction, your contract requires the appropriate conditions. Should the request be rejected with the error code 0007, please contact customer service for activation.

Please notice the two fields hash and iframe_url. The URL is given to the buyer in order to authorize the payment, and finally confirm the business transaction at the same time. If former API requests need to be performed, you should store the hash on your server. If the payment method was prepaid or invoice there would also be additional data that is explained in the Reference section.

This is what your customer sees, if they open the iframe_url in their browser:

images/download/attachments/76290586/image2020-3-13_13-57-17.png

The customer is prompted to confirm the payment, and sometimes for the needed data. When they use the buttons to submit or cancel, they are either directed to the success URL or the failure URL. In some cases the customer is not directed back to one of these URLs. They might simply stop here, and close the browser.

Step 3: Obtain the Status of the Transaction

We recommend that you also check the status of the transaction after the success URL was called.

This is an example request to obtain the status from our server:

POST /payment/status HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data":{
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"hash": "tujevzgobryk3303"
}
}

Example response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8;
...
 
{
"status": "ok",
"data": {
"hash": "tujevzgobryk3303",
"status": "accepted",
"created": "2018-07-01 12:54:56",
"demo": 1,
"trans_id": "23265478",
"amount": "1995",
"currency": "EUR",
"opt": {
"masked_payment_data": {
"purpose": "TA 23265478",
"data": "DE27 XXXX XXXX 9700"
}
}
},
"errors": null
}

If the payment method was prepaid or invoice additional details would be available.

Summary

We have obtained the available payment methods with a first interface call. After this we created a payment transaction for direct debit payment to be captured immediately. We found the iframe URL in it, and acted as customer in our tests. We have entered the bank details, and confirmed the payment. Afterwards, we were led back to the shop's success URL. We have also found the transaction's hash and used it for a second API call to obtain the transaction status.

Furthermore you can:

  • use the authorization flow;

  • use other payment methods (credit card, advance payment, invoice payment, Sofort);

  • define return URLs to direct the customer back to your website;

  • show a detailed basket;

  • show project or payment details;

  • define stakeholder shares;

  • defer the capture for a condition (accrual);

  • work with recurring payments for subscriptions;

  • customize the button text or the primary design colour;

  • use informal speech, or change the language;

  • use the XML data format.

Everything you need as a merchant is found in the following reference section. Furthermore you will find details of the communication protocol, the test environment and the demo flag.

Reference

Basic Workflow For Immediate Payment

The general workflows for sale (immediate payment) is this:

  1. The merchant obtains the available payment methods, and offers them to the customer.

  2. The merchant creates a payment transaction, and directs the customer to the payment iframe. The customer is prompted for final closure here.

  3. The merchant receives the customer back at the success URL, and checks the payment status.

If the payment status is accepted everything is ready for delivery. But it is also possible you need to wait for the payment.

If it is invoice payment, the merchant adds every delivery, and asks for capture together with the final delivery.

If something went wrong, the customer is directed to the failure URL. It is also possible, the customer is neither directed to the success URL nor to the failure URL.

Basic Workflow For Authorization

The general workflows for authorization is this:

  1. The merchant obtains the available payment methods, and offers them to the customer.

  2. The merchant creates a payment transaction, and directs the customer to the payment iframe. The customer only authorizes the payment here.

  3. The merchant receives the customer back at the success URL.

  4. The merchant prompts the customer for final closure, and then asks for capture, except for invoice payment.

If the payment status is accepted everything is ready for delivery. But it is also possible you need to wait for the payment.

If it is invoice payment, the merchant adds every delivery, and asks for capture together with the final delivery.

If something went wrong, the customer is directed to the failure URL. It is also possible, the customer is neither directed to the success URL nor to the failure URL.

Test or Production Environment

The secupay Flex.API has a productive and a testing environment. The base URLs are:

  • testing: https://api-testing.secupay-ag.de/

  • productive: https://api.secupay.ag/

In the testing environment you can try out all Flex.API calls without affecting your live contract. No real transactions are processed and there are no request costs.

Content Negotiation Headers

The data format is determined by the HTTP request headers Content-Type, Accept, Accept-Charset, and Accept-Language.

These are the headers to send and receive JSON:

Content-Type: application/json; charset=utf-8;
Accept: application/json;
Accept-Charset: utf-8
Accept-Language: de_DE

And these are needed for XML:

Content-Type: text/xml; charset=utf-8;
Accept: text/xml;
Accept-Charset: utf-8
Accept-Language: de_DE

The Content-Type header is only needed in POST or PUT requests, since the body is not evaluated in a GET request.

The request is expected in UTF-8, and also the response uses this encoding. The charset header is optional.

The Accept-Language does not influence the payment window but the API response, for instance error messages. It can be set to de_DE or en_US. The language header is optional, German is the default.

Request Body

All incoming and outgoing data are structured uniformly, regardless of the API endpoint. All requests with HTTP body encapsulate the transmitted user data in a field data.

Example request JSON:

{
"data":{
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"demo": 1,
"payment_type": "debit",
...
}

Or in XML:

<?xml version="1.0" encoding="utf-8"?>
<request>
<data>
<apikey>6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace</apikey>
<demo>1</demo>
<payment_type>debit</payment_type>
...
</data>
</request>

Response Body

All responses by the Flex.API have three top-level elements, status, data, and errors.

Example response of a successful query in JSON:

{
"status": "ok",
"data": {
"hash": "...",
"iframe_url": "..."
},
"errors": null
}

Or in XML:

<?xml version="1.0" encoding="utf-8"?>
<response version="1.0">
<status>ok</status>
<data>
<hash>bnpdcobygifw4287426</hash>
<iframe_url>https://api-testing.secupay-ag.de/payment/bnpdcobygifw4287426</iframe_url>
</data>
<errors />
</response>

The response status indicates whether the request was processed or not. There are three different options:

Status

Description

ok

The request to the flex.API was successful and the desired action was performed. The field data contains the details.

error

The requested action could not be performed, due to a technical error. Such errors indicate defects of the Flex.API or the client. The attention of a developer is required. You find details in the field error.

failed

The desired action could not be performed. These are mostly validation errors, so the user should check the error messages. Again you find details in the field error.

The structure of the data field depends on the particular API endpoint.

Example response of a failed query:

{
"status": "failed",
"data": null,
"errors": [
{
"code": "0001",
"message": "Invalid apikey"
}
]
}

If present, the errors field is an array with pairs of code and message.

Attribute

Type

Description

code

string

Machine-readable error code. See section Error Codes.

message

string

Human-readable error message. It is translated according to the Accept-Language setting in the request. See the section Content Negotiation Headers for more details.

Usually there is only one error reported. But your application should be prepared to process multiple messages.

Demo Transactions

You can mark a request and transaction as demo using the parameter demo. If marked so, the payment is not actually processed. There are also no transaction costs, shipments, nor statement positions.

Example request:

{
"data":{
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"demo": 1,
...
}

If the parameter is transmitted with the value 1 or true, it is a demo transaction. If the parameter is omitted, or transmitted with 0 or false, it is a real transaction.

Obtain Available Payment Methods

A GET request to /payment/gettypes returns all available payment methods. We recommended you to run this query prior to offering a payment method, so that you do not get unwanted error messages if the particular payment method is not available.

Example request:

GET /payment/gettypes HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
 
{
"data": {
"apikey":"6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace"
}
}

Example response:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8;
...
 
{
"status": "ok",
"data": [
"prepay",
"debit",
"invoice",
"creditcard",
"transfer",
"payout",
"sofort"
],
"errors": null
}

The returned payment methods correspond one-to-one with the field payment_type that is passed when you create a new transaction.

Create Payment Transaction

This is the by far most important API request. In order to create a new payment transaction you send a POST request to /payment/init.

These parameters are needed:

  • apikey

  • payment_type

  • amount

  • url_success

  • url_failure

  • url_push

  • firstname

  • lastname

  • company (if applicable)

  • email

  • street

  • housenumber

  • zip

  • city

  • country

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
"payment_action": "sale",
"url_success": "https://example.org/SUCCESS",
"url_failure": "https://example.org/FAILURE",
"url_push": "https://example.org/PUSH",
"apiversion": "2.11",
"language": "de_DE",
"title": "Herr",
"firstname": "Max",
"lastname": "Mustermann",
"street": "Musterstr.",
"housenumber": "112 a",
"zip": "09555",
"city": "Musterhausen",
"country": "DE",
"telephone": "+4912342134123",
"dob_value": "01.02.1903",
"email": "max@example.org",
"ip": "172.31.6.49",
"currency": "EUR",
"amount": "199",
"purpose": "Test order 1"
}
}

Example response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8;
...
 
{
"status": "ok",
"data": {
"hash": "tujevzgobryk3303",
"iframe_url": "https://api.secupay.ag/payment/tujevzgobryk3303"
},
"errors": null
}

As you remember from the Getting Started section, the hash is needed for subsequent API calls, and the iframe URL displays our payment window.

Parameter overview:

Attribute

Type

Description

apikey

string

Your individual API key. It identifies the merchant, determines the contract, and grants access to the API. 40 alphanumeric digits like 6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace.

payment_type

string

Determines the payment method:

  • prepay (advance payment)

  • debit (SEPA direct debit)

  • invoice

  • creditcard

  • sofort

You can only use the contracted methods. The same method might be active in demo mode or not. Please ask our customer service for more payment methods.

demo

boolean|number|string

Optional demo flag:

  • 0 or false (real transaction)

  • 1 or true (demo transaction)

If ommitted, it defaults to false. Then it is a real transaction.

Note: Please be careful with the flag and make sure to remove the demo parameter for transaction in productive environment.

payment_action

string

Optional. Determines the workflow:

  • sale

  • authorization

In the sale flow the buyer completes the payment process with a pay now button. This is the final closure, and the money is captured immediately.

Having the authorization flow, the payment is only authorized. It needs a subsequent interface call to capture the money. You would use this flow if the final closure is done at your site after the customer returned to it.

If omitted, the payment action defaults to sale.

language

string

Optional, the language of the payment window:

  • de_DE for German

  • en_US for English

If omitted, it defaults to de_DE.

title

string

Optional "Mr" or "Mrs".

firstname

string

First name(s), like "Max-Johann", or "John M."

lastname

string

Last name(s), like "Mustermann", "Mustermann-Müller", or "van Mustermann".

company

string

Optional company name, like "Musterfirma GmbH & Co. KG". It is mandatory, if the customer is a company.

street

string

Street without house number, like "Musterallee", or "Dr.-Max-Mustermann-Platz".

housenumber

string

Full house number (including additions for split or joined properties; for example, "101-103", or "21 b").

zip

string

Postal code, like "09555".

city

string

Official town name.

country

string

Country as ISO-3166 Alpha-2 code; for example "DE" for Germany, or "CH" for Switzerland. See language for the translation of the payment window.

telephone

string

Phone number (international format), like "+493515555555".

dob

string

Date of birth (format example 31.01.2020); needed for scoring when you offer invoice.

email

string

E-mail address.

ip

string

IP address of the buyer as string.

amount

string|int

Amount to pay in the smallest unit; for example 1995 with EUR means 1995 Euro Cents, or €19.95.

currency

string

Optional currency as ISO-4217 Alpha-3 code; for example EUR, GBP, or CHF. Special contract options are required in order to receive payments in currencies other than EUR.

If omitted, the currency defaults to Euro (EUR).

purpose

string

Optional purpose line. It is displayed for each position (a) at the bank statement of the payer, and (b) at our detailed advice note for the merchant. For example "order 5002012345 from 2020/01/31" or "hotel room, 1 p., b&b" .

apiversion

string

Optional API version, for example "2.11"

url_success

string

URL to return in case of success. See section Return Customer To Merchant Page.

url_failure

string

URL to return in any case of failure. See section Return Customer To Merchant Page.

url_push

string

URL to receive push messages on status changes. See section Receive Status Notifications (Push API).

Pass Delivery Address

You can pass a delivery address during the creation of the transaction. The delivery address must be passed, if it differs from the customer address.

The correct transmission of the delivery address helps secupay to give transaction support and assess the risk of an order.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
...
"title": "Herr",
"firstname": "Max",
"lastname": "Mustermann",
"street": "Musterstr.",
"housenumber": "112 a",
"zip": "09555",
"city": "Musterhausen",
"country": "DE",
"telephone": "+4912342134123",
"dob_value": "01.02.1903",
"email": "max@example.org",
...
"delivery_address": {
"firstname": "Max",
"lastname": "Mustermann",
"street": "Gartenstr.",
"housenumber": "22",
"zip": "90555",
"city": "Musterdorf",
"country": "DE"
}
}
}

You can also pass a company name. The format is basically the same as that of the customer, but it can be extended if necessary.

übrig: s. Optional delivery address. If there see definition Flex 2.0 API Payment Schnittstelle#Lieferadresse

Pass Merchant Information

You can optionally pass merchant-induced information during creation of the transaction. You can pass:

  • a customer ID;

  • an order ID;

  • up to three user fields for individual notes.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
...
"merchant_customer_id": "1234",
"order_id": "100203",
"userfield_1": "Hotel room, 1 person, bed and breakfast",
"userfield_2": "person is walking disabled; arrival at about 9 p. m.",
"userfield_3": "2020/01/28 through 2020/01/30"
}
}

Pass Detailed Basket

You can optionally pass a detailed basket during the creation of the transaction. If you want to display the basket instead of the total amount, you need our customer service to activate a contract option for you.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
...
"currency": "EUR",
"amount": "14485",
"basket": [
{
"item_type": "article",
"article_number": "4124",
"quantity": "2",
"name": "Book shelf Peter, 201 x 59 x 28",
"ean": "4123412341243",
"tax": "19",
"total": "11990",
"price": "5995"
},
{
"item_type":"article",
"article_number":"4123",
"quantity":"1",
"name":"Desk lamp Eric, white",
"ean":"4123412341236",
"tax":"19",
"total":"2495",
"price":"2495"
}
]
}
}

Detailed description of the objects for the basket items:

Attribute

Type

Description

item_type

string

Must be article for regular basket items.

id

number

The item ID as integer. It is necessary as handle for further changes.

quantity

number

The amount as integer.

articleNumber

string

Optional. Your internal article number, or storage keeping unit (SKU). Currently we accept only numeric digits here.

ean

string

Optional. The official EAN or GTIN of this product.

Note: If your product has no EAN or GTIN, please omit this attribute. It might conflict with real GTINs that need to be evaluated by use. We need to evaluate EANs when you start a loyalty card programme to detect loyalty cards, or articles with special tax handling. We also need to evaluate EANs when you start to sell e-goods, phone credit for example.

name

string

The article name.

price

number

The gross unit price in the smallest currency unit.

If you pass a value of 1595 for a order in Euros, this means 1595 Euro Cents, or €15,95.

tax

number

The value-added tax (VAT) rate in percent.

If you pass a value of 19, this means a VAT rate of 19%.

If there is a basket, the field amount must be equal to the sum of gross item totals. It is calculated (quantity1 × price1) + (quantity2 × price2) + … + (quantityn × pricen). If present, also the shipping fee needs to be included. (See more in the next section.)

If the basket display is active for the contract, it would look so:

images/download/attachments/76290586/image2020-3-18_16-24-4.png

When the basket is displayed, you can also change its headline. Read more in the section about display options.

Pass Shipping Fee

You can pass a shipping fee in the basket during the creation of the transaction.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
...
"currency": "EUR",
"amount": "12485",
"basket": [
{
"item_type": "article",
"article_number": "4124",
"quantity": "2",
"name": "Book shelf Peter, 201 x 59 x 28",
"ean": "4123412341243",
"tax": "19",
"total": "11990",
"price": "5995"
},
{
"item_type": "shipping",
"name": "standard delivery",
"tax": "19",
"total": "495"
}
]
}
}

Detailed description of the objects for the basket items:

Attribute

Type

Description

item_type

string

Must be shipping for the shipping fee.

name

string

The name as listed among the article names.

tax

number

The value-added tax (VAT) rate in percent.

If you pass a value of 19, this means a VAT rate of 19%.

total

number

The gross total fee in the smallest currency unit.

If you pass a value of 495 for a order in Euros, this means 495 Euro Cents, or €4,95.

If a shipping fee is present, the field amount must contain it. It is calculated (quantity1 × price1) + (quantity2 × price2) + … + (quantityn × pricen) + (totalshipping).

If the basket display is active for the contract, it would look so:

images/download/attachments/76290586/image2020-3-18_16-26-20.png

Show Payment Hint

You can pass a hint to explain the payment. It consists of lines with text pairs, each aligned to the left and to the right, like on a cash receipt. You can also modify the headline above it.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
...
"currency": "EUR",
"amount": "45000",
"purpose": "Restzahlung 500016251 Mustermann Warnemünde 5.-10.9.2020",
"order_id": "500016251",
"language": "de_DE",
"payment_hint": [
{
"item": "Verwendungszweck:",
"hint": "Restzahlung Ferienwohnung"
},
{
"item": "Bestellnumer:",
"hint": "500016251"
},
{
"item": "Zeitraum:",
"hint": "5.-10.9.2020"
},
{
"item": "Ferienwohung",
"hint": "Warnemünde, Appartment \"Meerblick\", bis 5 P."
}
],
"labels": {
"de_DE": {
"payment_hint_title": "Details zu Ihrem Auftrag"
}
}
}
}

Here an example of the outcome:

images/download/attachments/76290586/image2020-3-19_13-35-17.png

Miscellaneous Display Options

There are a number of further display options. These are the most common:

  • You can change the primary design colour to your needs. In order to achieve this, you need our customer service to set the option in your particular contract.

  • You can customize the button texts for a single transaction.

  • You can customize the headlines of the basket, and of the payment hint, for a single transaction.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"payment_action": "sale",
"demo": 1,
...
"language": "en_US",
"labels": {
"en_US": {
"basket_title": "Your Furniture",
"submit_button_title": "Pay now, and buy furniture!",
"cancel_button_title": "Back to ACME shop"
}
}
...
}
}

Here a screenshot for this example:

images/download/attachments/76290586/image2020-3-19_8-23-50.png

In order to change the payment hint title you would use the attribute payment_hint_title. You find an example in the section about the payment hint.

Return Customer To Merchant Page

In most cases you would like to return your customer back to your web page. You can pass two URLs for this, one for the case of success, and one for the case of failure. The case of failure includes user abort, failed authorization, and technical problems. The URLs can be generic, but may also be specific for the particular transaction.

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
"url_success": "http://shop.example.com/success.php",
"url_failure": "http://shop.example.com/failure.php",
...
}

The parameter url_success is the URL to direct the customer back after successful authorization, or payment. When the transaction uses the sale flow, it is common to confirm the order thankfully. When in authorization flow, it is most likely you will show a summary, and prompt the customer for final confirmation.

The parameter url_failure is the URL to send the customer back after failed authorization, if they aborted the payment or in case of a technical problem. Usually, you would guide the customer back to your checkout process, for instance to the payment method selection.

Pass Shop and Module Information

For debugging one can pass:

  • the shop name and version

  • the shop module version

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
...
"shop": "APITest Shop",
"shopversion": "1.0",
"moduleversion": "1.0",
...
}

Improve Customer Rating

You can improve the customer rating in three ways:

  • pass your customer ID to us;

  • share your customer experience with us.

The first helps us to recognize the customer correctly, for instance after marriage or relocation. So we can apply our experience to him, including credibility above average. The second helps us to trust your regular customers better, or to involve your poor experiences with a particular customer in our rating. Overall, this helps avoid rejection of good customers, but also to reduce risk.

Note: In order to pass the payment experience, you need a contract option to be set by our customer service.

You can pass the needed data during the creation of a transaction:

Example request:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data":{
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
"currency": "EUR",
"amount": "15900",
"purpose": "Test order 1",
...
"merchant_customer_id": "1234",
"experience": {
"positive": "1",
"negative": "0"
}
}
}

The experience values in detail:

Parameter

Meaning

positive

How often has the customer paid in time:

  • 0: no positive experiences with the customer so far

  • 1: one transaction paid in time

  • 2: multiple transactions paid in time

negative

Tell us, if a customer has negative traits

  • 0: no negative experience with the customer so far

  • 1: customer currently has overdue open items

  • 2: customer has caused charge backs or paid only after repeated reminders in the past

Obtain Transaction Status and Details

You can obtain the status of a Payment Transaction making a GET request to /payment/status. You need to pass the API key and transaction hash.

Example request:

POST /payment/status HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"hash": "tujevzgobryk3303"
}
}

The response contains some meta information about the transaction.

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8;
...
 
{
"status": "ok",
"data": {
"hash": "tujevzgobryk3303",
"status": "accepted",
"created": "2013-06-10 10:27:42",
"demo": 0,
"trans_id": "1831201",
"amount": "100",
"opt": {
}
},
"errors": null
}

The status contained in the data part of the response must be "accepted" after forwarding to url_success. Exception: for advance payment and pre-authorized transactions the status can be "proceed". It is recommended, after forwarding to url_success, to verify the status "accepted" or "proceed" by a status query. Read more details about the status in the following section Payment Status.

If the payment method is invoice or prepaid, then the subordinate object "opt" contains additional details.

Example response body of a prepaid transaction (advance payment):

{
"status": "ok",
"data": {
"hash": "tujevzgobryk3303",
"status": "proceed",
...
"opt": {
"recipient_legal": "secupay AG, Goethestraße 6, 01896 Pulsnitz",
"payment_link": "https://api.secupay.ag/payment/tujevzgobryk3303",
"payment_qr_image_url": "https://api.secupay.ag/qr?d=http%3A%2F%2F....",
"transfer_payment_data": {
"purpose": "TA 123456",
"accountowner": "secupay AG",
"iban": "DE37 8999 9999 5555 5555 55",
"bic": "TESBDEZZXXX",
"bankname": "Testbank AG"
}
}
},
"errors": null
}

All these fields are always present, when the payment method is invoice or prepaid. They have these meanings:

  • recipient_legal: full name and address of the payee (secupay as holder of the escrow account);

  • payment_link: URL to help the buyer to pay immediately;

  • payment_qr_image_url: URL to get an QR code for the above URL (helps to overcome media disruption from a printed invoice to online payment);

  • transfer_payment_data: bank details to pay by your own.

You need to print the details on your invoice, at least the bank details. It is a good practice to include the payment_url in online media, and the QR code at printed media. You should also remind the buyer that their invoice was assigned to secupay AG in Pulsnitz (recipient_legal) as payment service provider.

If your transaction is paid on invoice, and you have already marked it as shipped, the status response will also contain this message:

{
"status": "ok",
"data": {
"hash": "tujevzgobryk3303",
"status": "proceed",
...
"opt": {
"recipient_legal": "secupay AG, Goethestraße 6, 01896 Pulsnitz",
"payment_link": "https://api.secupay.ag/payment/tujevzgobryk3303",
"payment_qr_image_url": "https://api.secupay.ag/qr?d=http%3A%2F%2F....",
"transfer_payment_data": {
"purpose": "TA 123456",
"accountowner": "secupay AG",
"iban": "DE37 8999 9999 5555 5555 55",
"bic": "TESBDEZZXXX",
"bankname": "Testbank AG"
},
"invoice_number": "90001234555",
"shipping_date": "2018-11-12 08:50:40",
"shipped": true
}
},
"errors": null
}

Payment Status

The payment status is returned by the former payment status request. It is also passed to your servers from our push service described below.

The normal flow can have has these statusses, depending on the payment method:

Status

Meaning

proceed

Initial status of every transaction. The payment is not authorized, nor wanted to capture.

authorized

The payment is authorized, but was not requested to capture yet.

pending

The payment was requested to capture, but you must wait with delivery for status accepted. This status is always set when we wait for the advance payment. It is also used with other payment methods to perform an additional risk check.

accepted

The request for capture or for invoice payment was accepted. You can deliver now. (Recall: When you use invoice payment, you need to add the partial deliveries, and to request the capture along with your final delivery.)

paid

We have received the invoice payment.

There are also these exceptional statusses:

Status

Meaning

denied

The payment was rejected for some reason.

issue

A problem occured after the payment was accepted. For instance, the payer wanted a credit card charge back.

issue_resolved

The problem is resolved. For instance, the charge back could be objected.

refund

The payment is flagged for refund. It will be processed with our next bank cycle.

void

The payment was cancelled, or refunded.

Capture Authorized Payment

When you use the "sale" flow, the payment is executed automatically after the customer confirmed. In some cases you still need to wait with delivery. But the contract is closed, and we care for the payment.

When you use the "authorization" flow, the contract is not closed yet. The payment is only authorized and you need to tell us, that we shall capture the payment now.

You can either use the API solution with POST, or the browser solution with GET. The API endpoint to capture the payment is /payment/<hash>/capture. You need no parameters in addition to your API key.

For invoice transactions you must not call /capture before the full delivery! Please study the next two sections for this case.

Example of API solution with POST:

POST /payment/tujevzgobryk3303/capture HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace"
}
}

The browser solution is very similar, but you need to append the API key to the URL. To capture the above transaction your URL is https://api-testing.secupay-ag.de/payment/tujevzgobryk3303/capture/6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace. This will open a transaction overview, and you can capture the payment with a click on a button.

Be aware that the browser might store the API key in the browser history. It must not be revealed to other persons.

Add Shipment Note For Partial Delivery

When you offer invoice payment to your customers, you need to inform us for every delivery of such a transaction. We need this information in the communication with you, the merchant, and with your customer.

If you inform us about an intermediate delivery, you need to call POST /payment/adddata.

Example request:

POST /payment/adddata HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
   "hash": "oxaijkeaucbl2041",
  "tracking": {
    "provider": "DHL",
     "number": "TC123456789"
  },
"invoice_number": "90001234555",
  "shipping_date": "2018-11-12 08:50:40"
}
}

Note: You still need to call /capture for the final delivery. Otherwise we do not expect the full payment nor can we manage the payout.

All fields except hash and apikey are optional. Here the meanings:

Attribute

Type

Meaning

tracking.provider

string

Optional. The shipping provider like "DHL", "DPD", etc.

tracking.number

string

Optional. The tracking code received from the shipping provider.

invoice_number

string

Optional. Your invoice number.

shipping_date

string

Optional. The actual shipping date formatted like "2018-01-31 08:50:40", up to three days in the past. Defaults to to the current time.

Capture Invoice Payment On Full Delivery

As said before, when you offer invoice payment to your customers, you need to inform us for every delivery of such a transaction. You also need to inform us about the final delivery, since we need this for the payout, and sometimes to send a reminder notice. You can also store more details that help you and us to trace back the transaction later.

No matter if you use the sale or authorization flow, when the payment method is invoice, you must tell us, that we can execute the payment process now. This is done with a POST request to the /capture endpoint.

Note: If the payment method is invoice you must call this endpoint in order to receive the payout. But you must not call this endpoint before you have delivered fully.

Example POST request:

POST /payment/tujevzgobryk3303/capture HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"tracking": {
"provider": "DHL",
"number": "TC123456789"
},
"invoice_number": "90001234555",
"shipping_date": "2018-11-12 08:50:40"
}
}

You find a description of these parameters in the previous section. It is the same format.

Cancel Payment

You can cancel an authorized transaction as long as it is not captured yet. You can also cancel a transaction you have already captured, if the capture has not been executed yet. Direct debit transactions are usually executed the next morning at about 6 a. m.

It is also a good practice to cancel authorized transactions if these shall not be captured anymore.

You can either use the API solution with POST, or the browser solution with GET. The API endpoint to capture the payment is /payment/<hash>/cancel. You need no parameters in addition to your API key.

Example of API solution with POST:

POST /payment/tujevzgobryk3303/cancel HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace"
}
}

Response:

{
"status":"ok",
"data":{
"hash":"tujevzgobryk3303",
"demo":0,
"trans_id":"1831201"
},
"errors":null
}

There is also a browser solution. It is very similar, but you need to call GET and to append the API key to the URL. To cancel the above transaction your URL is https://api-testing.secupay-ag.de/payment/tujevzgobryk3303/cancel/6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace.

Be aware that the browser might store the API key in the browser history. It must not be revealed to other persons.

Receive Status Notifications (Push API)

Sometimes it is needed to synchronize the status of your system with ours. It is much better to respond to our push notification instead of polling the status endpoint repeatedly. You receive the notification much quicker and it saves both of us a lot of resources.

Basically, it functions this way: You pass a push URL when you create the transaction. This push URL might can be generic, since we transmit the transaction hash with our push notification. But it can also be a specific URL, containing your own ID. When there is this URL, you will receive push notifications for every change of the payment status.

Example request to create a transaction with push URL:

POST /payment/init HTTP/1.1
Host: api-testing.secupay-ag.de
Content-Type: application/json; charset=utf-8;
Accept: application/json
Accept-Charset: utf-8
 
{
"data": {
"apikey": "6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace",
"payment_type": "debit",
"demo": 1,
"url_push": "https://push.example.org/push_client.php",
...
}

After this we will call the above push URL with a POST request with these fields:

Field

Description

hash

our transaction hash

status_id

detailed status ID (usually not processed)

status_description

detailed status text (often wanted to display)

changed

UTC timestamp of the status change

apikey

API key used to create the particular transaction (used for validation)

payment_status

payment status (explained in section Payment Status)

The body has the MIME type application/x-www-form-urlencoded. This means it looks like the query string of an HTTP request.

Push notifications need to be acknowledged by your server. As long as the notification is not acknowledged, our server will try it again every 5 minutes for the next 24 hours.

For an acknowledgement return us the original body, and add ack=Approved at any place. If you cannot process the call, for instance for a hash mismatch, return ack=Disapproved. If you want to tell us a reason, you can also add a parameter error.

Example request to your server:

POST /push_client.php HTTP/1.1
Host: push.example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 157
Referrer: https://api-testing.secupay-ag.de
Accept: */*
Connection: close
...
 
hash=tujevzgobryk3303&status_id=6&status_description=abgeschlossen&changed=1365444092&payment_status=accepted&apikey=6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace

Example positive response:

HTTP/1.1 200 OK
...
 
ack=Approved&hash=bogushashval1524&status_id=6&status_description=abgeschlossen&changed=1365444092&payment_status=accepted&apikey=6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace

Example negative response:

HTTP/1.1 200 OK
...
 
ack=Disapproved&error=no+matching+order+found+for+hash&hash=jtnjpfgrbrqk3300&status_id=6&status_description=abgeschlossen&changed=1365444092&payment_status=accepted&apikey=6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace

Example implementation PHP:

// This is our main mathod, called to handle the request
function handleRequest()
{
// Correct method?
    if ($_SERVER['REQUEST_METHOD'] != 'POST') {
respondError('bad request method ' . $_SERVER['REQUEST_METHOD']);
return;
    }
 
// Something missing?
    static $keys = [
'hash',
'apikey',
'payment_status',
'status_description'
]; // We ignore `status_id´ and `changed´ in our example ...
    $missing = [];
    foreach ($keys as $k) {
        if (!array_key_exists($k, $_POST)) {
            $missing []= $k;
        }
    }
    if (!empty($missing)) {
respondError('missing param(s) ' . implode(', ', $missing));
return;
    }
 
// Process status push
    try {
 
// You would modify something in the DB, for instance
        setStatusFromPush(
$POST['hash'],
$POST['apikey'],
$POST['payment_status'],
$POST['status_description']
);
} catch (MyException $e) {
 
// In our example we add a support ID to find the log entry
error_log($e->getSupportId() . ': ' . $e->getMessage());
respondError('support ID ' . $e->getSupportId());
return;
    } catch (Exception $e) {
 
// Should also be handled safely
        error_log($e->getMessage());
respondError();
return;
    }
respondOk();
}
 
// Sends a simple response for the good case
function respondOk()
{
    return respond('200 OK', [ 'ack' => 'Approved' ]);
}
 
// Sends a response for the error case
function respondError($msg = null)
{
    $additionalFields = [ 'ack' => 'Disapproved' ];
    if ($msg != null) {
        $additionalFields['error'] = $msg;
    }
    return respond('500 Server Error', $additionalFields);
}
 
// Not called directly, but by the previous two methods
function respond($status, $additionalFields)
{
    header('HTTP/1.1 ' . $status);
    header('Content-Type: application/x-www-form-urlencoded');
    echo http_build_query(array_merge($_POST, $additionalFields));
}

Troubleshooting

When you see no regular response:

Error Situation

Explanation

I receive an HTTP error code.

This is very unlikely. Please check your URL. Do you use the correct server address?

I expect HTML, JSON or XML, but receive something different.

Please check (1) the request headers you send, and (2) the request method.

The server will respond with an HTML page, if you use GET. Please refer to the section for capture, or that for adding deliveries, and you will understand why.

If you use POST, then the Accept header determines the response format. Please check the header whether it is sent properly.

I receive JSON or XML, but the status is not ok.

Please check the error codes.

When the response indicates a certain error:

Error Code

Explanation

0001

Invalid API key.

(1) The API key is invalid or missing.

Is it that one you have received from us? Is anything missing or too much? Maybe you cut off the first or last characters, or there are additional spaces or quotes.

Former keys differed between test and production. If this is the case, please check if it is the right key. If your think your former key for the test environment became invalid in over time, please get in touch with us.

(2) A malformed request body is processed in some cases, but sometimes it is indicated by error code 0001.

0002

Invalid hash.

(1) The transaction hash is invalid or missing.

(2) A malformed URL is processed in some cases, but is indicated by error 0002.

0003

Cannot capture unauthorized payment.

0004

Cannot cancel/void unaccepted payment.

0005

Invalid amount.

0006

Cannot refund unaccepted payment.

0007

No payment type available.

0008

Hash has already been processed.

0009

Scoring invalid.

0010

Payment currently not available.

0011

Payment could not be finalized.

0012

Selected payment type is not available.

0013

API key mismatch.

0014

Cannot capture specified payment.

0015

Cannot cancel/void specified payment.

0016

Cannot refund specified payment.

0017

Invalid payment data.

0018

Missing parameter.

0019

Could not create the user.

0020

Username/email unavailable.

0021

Username or password invalid..

0022

Userauth token invalid.

0023

Could not connect the card to the user.

0024

Invalid value for parameter.

0025

Cannot process specified payment.

0026

Cannot create payment information.

0027

Invalid data.

0028

Payment Provider declined the payment.

0029

No transaction available for this terminal.

0030

Cannot create transaction.

0031

Unknown parking zone.

0032

The password you entered is too short.

0033

The passwords are not equal.

0034

The data provided is not sufficient.

0035

There was an error creating the API key.

0036

The license plate is not valid.

0037

Payment data missing.

0038

Cannot find any active ticket for this zone and car.

0039

There is already valid ticket for this car in this zone.

0040

There is not any tariff valid for your parking time.

0041

Password recovery failed.

0042

Your password has been recovered.

0043

Error recovering the password.

0044

Failed to save your payment data.

0045

Your payment data has been saved.

0046

Referenced payment is not accepted.

0047

Cannot set accrual.

0048

Cannot reverse accrual.

0049

Failed to add data.

0050

Your bank does not support SEPA direct debit.

0051

You are not approved for Subsequent.

0052

Subsequent posting already Available.

0053

The is already a subsequent posting.

0054

Amount too high.

0055

You are not approved for Refund.

0056

Missing or Invalid Parameter.

0057

Transaction not found.

0058

Refund amount higher than transaction amount.

0059

Invalid transaction status for refund.

0060

Payment type does not support refund.

0061

Refund amount higher than remaining transaction amount.

0062

Refund creation failed.

0063

Refund not implemented for payment type.

0064

You are not approved for getSubscription.

0065

Accrual not set for transaction.

0066

Selected currency is not available.

0067

This currency is not available for you.

0068

You have transferred disallowed characters.

0069

Refund amount does not match the available transaction amount.

0070

Total amount does not match the basket amount.

0071

Basket field name is not valid.

0072

Payment type of transaction_payout transaction does not support Payout.

0073

Invalid transaction status of transaction_payout transaction.

0074

Access denied to transaction_payout transaction.

0075

Basket has too many items.

0076

PIN wrong.

0077

The PIN was entered incorrectly too often.

0078

You have entered an incorrect telephone number (allowed characters are "+" and 0-9).

0079

Operation not approved for this project API key.

0080

You are not approved for this operation.

0081

Due to significant risk of fraud this user is rejected.

0082

The payment is already completed.