Skip to content
Инвойсбокс

Default notification

If automatic status notifications are enabled in the merchant settings, Invoicebox calls a dedicated URL from those settings as soon as an order is paid.

The call is a POST with Content-Type: application/json; the body holds an OrderNotification object.

OrderNotification

Repeats the structure of OrderResponse. The main fields:

PropertyRequiredTypeDescription
idyesstring(36)Order identifier in Invoicebox, for example 01771534-1a57-f184-dee3-ebeb91dded75
statusyesstring(50) enumOrder status, for example completed, canceled
merchantIdyesstring(36)Merchant identifier, for example 01771534-1a57-f184-dee3-ebeb91dded76
merchantOrderIdyesstring(36)Order identifier in the merchant's own system, for example O-12345
merchantOrderIdVisiblenostring(100)Order number shown on the payment page; falls back to merchantOrderId, for example 111TN22-33
amountyesfloatOrder total, for example 19658.45
customeryesCustomerBuyer details
currencyIdyesstring(3) enumOrder currency, for example RUB, USD, EUR, GBP
createdAtyesdatetimeWhen the order was created, for example 2026-09-14T00:00:00+00:00

An order counts as paid when its status is completed. Checking the signature is not enough: compare the amount in the notification with the amount in your own system, and compare the status with the state the order is already in. If either disagrees, refuse the request and answer with an error — otherwise a replayed old notification or a tampered amount passes for a payment.

Response format

On success the merchant's web service returns a NotificationSuccess object; on a deliberate processing error — wrong amount, unknown order, bad signature and so on — a NotificationError.

Important

Both answers are returned with HTTP 200. HTTP 200 alone does not mean success: success is the pair HTTP 200 + {"status":"success"} in the body. The pair HTTP 200 + {"status":"error", "code": ...} is an expected answer too — it reports a deliberate processing error (see NotificationErrorCode).

Any answer with a status code other than 200 — and any answer without valid JSON in the body — is read by Invoicebox not as the code in the body but as the merchant's web service being unavailable, that is, the same as out_of_service, no matter what code says. Such requests are retried up to 10 more times within 24 hours.

In other words, code only means something when the status code is 200. If your service answers HTTP 400 or 401, the body is not parsed at all and the request is retried as out_of_service, even when the body says signature_error.

NotificationSuccess

PropertyRequiredTypeDescription
statusyesstring(50)On success only one value is allowed — success

Example:

{
  "status": "success"
}

NotificationError

PropertyRequiredTypeDescription
statusyesstring(50) enumOn a processing error only one value is allowed — error
codenostring(100) enumError code from NotificationErrorCode; defaults to out_of_service
messagenostring(500)Free-text description of the error

Example:

{
  "status": "error",
  "code": "order_wrong_amount",
  "message": "Order amount does not match the payment amount"
}

NotificationErrorCode

Error codeDescription
out_of_serviceA technical failure in the merchant's web service. Invoicebox retries the request 10 more times over the next 24 hours
order_wrong_amountThe order amount in the merchant's system differs from the amount in the notification
order_already_paidThe order has already been paid with another payment instrument :warning:
order_not_foundThe order is unknown to the merchant's system
shipping_unavailableThe service cannot be rendered or the goods cannot be delivered
full_refund_requiredThe same as shipping_unavailable, with a refund or payment cancellation created automatically
signature_errorThe request signature did not verify

Important

If a notification with the same id has already been processed successfully on your side, answer status = success again — repeated delivery is normal.

If the order was paid earlier by a notification with a different id or by another payment instrument, answer status = error with code = order_already_paid.

Request timeout

Invoicebox waits 20 seconds for the merchant's web service to answer. Anything slower counts as a failure.

Request signature

Verify the integrity of every notification: compute the signature of the incoming body and compare it with the X-Signature header. If they differ, answer with NotificationError and NotificationErrorCode signature_errorwith HTTP 200, like any other NotificationError (see Response format). Answering 400, 401 or 403 instead means Invoicebox never parses code from the body and treats the call as the technical failure out_of_service rather than signature_error.

The signature is a cryptographic transformation of the request body using the key and algorithm chosen in the notification settings. Merchants connected today start with the hash_hmac method and sha256 — use that on a new integration. Merchants configured earlier keep the algorithm chosen back then, usually sha1; it still works, but switch to sha256 when you can. The algorithm and the key are both in the merchant integration settings in your Invoicebox account.

Signature check in PHP
<?php

$xSignature = false;
foreach (getallheaders() as $header => $value) {
    if (strtolower($header) == "x-signature") {
        $xSignature = $value;
        break;
    }
}

if (!$xSignature) {
    // No signature in the request.
    // The status code is not set explicitly, so the default 200 applies — which is
    // required here, otherwise Invoicebox will not read the code from the body.
    header("Content-Type: application/json");
    die('{"status":"error","code":"out_of_service"}');
}

$payload = file_get_contents("php://input");
$apiKey = ""; // The signing key from the merchant integration settings
// Use the algorithm set in the notification settings: sha256 for new merchants,
// usually sha1 for merchants configured earlier
$calcSignature = hash_hmac("sha256", $payload, $apiKey);

if ($xSignature != $calcSignature) {
    // The signature does not match.
    // Again HTTP 200 by default, not 400 or 401.
    header("Content-Type: application/json");
    die('{"status":"error","code":"signature_error"}');
}
Signature check in Python
import hashlib
import hmac
import json

# Adjust the path and the method in @app.route() to your own application.
@app.route("/invoicebox_callback", methods=['POST'])

async def invoicebox_callback():
    x_signature = request.headers.get('x-signature')
    if not x_signature:
        # No signature in the request. The status code has to be 200, otherwise
        # Invoicebox ignores the code in the body and counts the answer as a
        # technical failure (out_of_service).
        response = jsonify({'status': 'error', 'code': 'out_of_service'})
        response.headers["Content-Type"] = "application/json"
        return response, 200

    # The signing key from the merchant integration settings
    api_key = ""
    payload = request.data
    # Use the algorithm set in the notification settings: sha256 for new merchants,
    # usually sha1 for merchants configured earlier
    calc_signature = hmac.new(api_key.encode(), payload, hashlib.sha256).hexdigest()

    if x_signature != calc_signature:
        # The signature does not match. HTTP 200, not 400 or 401 — see "Response format".
        response = jsonify({'status': 'error', 'code': 'signature_error'})
        response.headers["Content-Type"] = "application/json"
        return response, 200

See also the PHP SDK

Monitoring and automatic integration testing

Invoicebox monitoring tests integrations on its own.

To check that yours works, the system may send a test notification: the merchant order identifier is empty and the Invoicebox order identifier is ffffffff-ffff-ffff-ffff-ffffffffffff.

On such a request the merchant's system should verify the signature, compare the merchant identifier with its settings and answer according to the result of those checks.


Read next »

Was this page helpful?