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:

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_push": "https://push.example.org/push_client.php",
...
}

The push URL may have up to 2000 characters.

After you have set the push URL 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:

Request
POST /push_client.php HTTP/1.1
Host: push.example.org
Content-Type: application/x-www-form-urlencoded
Accept: */*
 
hash=tujevzgobryk3303&status_id=6&status_description=abgeschlossen&changed=1365444092&payment_status=accepted&apikey=6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace

Example positive response:

Response (Success)
HTTP/1.1 200 OK
Content-Type: application/x-www-form-urlencoded
 
ack=Approved&hash=bogushashval1524&status_id=6&status_description=abgeschlossen&changed=1365444092&payment_status=accepted&apikey=6801fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7ace

Example negative response:

Reponse (Failure)
HTTP/1.1 200 OK
Content-Type: application/x-www-form-urlencoded
 
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:

Request Handler
// 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));
}