๐Ÿ“ก What are the webhooks?

Webhooks are a powerful way to receive real-time notifications from our API about specific events. When certain events occur, such as a payment transaction, our system will send an HTTP POST request to a URL you've provided, allowing you to react to the event in your application. Let's dive into the webhook payload structure:

๐Ÿ“จ Request Headers

When setting up your webhook endpoint, make sure to handle incoming HTTP POSTrequests and consider including the following headers to handle the payload correctly:

  • Content-Type: application/json - Indicates that the request payload is in JSON format.

๐Ÿ“ Request Body Example

{
    "RRN": "3524703829728",
    "Type": "JustPay",
    "Payer": {
        "Phone": null,
        "FullName": null
    },
    "Token": "B91LLM0TEST64349UP1B0A670",
    "Amount": 51.5,
    "Refund": {
        "RefundId": 1234,
        "Status": "Processed",
        "Amount": null,
        "Revisions": [],
        "RejectReason": null,
        "RefundDate": 638123241242235100,
        "RefundDateIso": "2023-12-22T06:42:04.223587Z",
        "Refundable": true,
        "RequestedAmount": null
    },
    "Source": "Card",
    "Splits": [
        {
            "Iban": "GE65BG0000000000000000",
            "PayIn": 0,
            "Amount": 35,
            "Status": "Draft",
            "Description": "Split Funds (ID:99D4DDCC4TEST12BB260418C42A6912A); ",
            "CashOutOrder": []
        }
    ],
    "Sandbox": false,
    "CardMask": "415479xxxxxx4768",
    "Currency": "GEL",
    "Metadata": {
        "Order": {
            "OrderId": null,
            "AdvanceContactId": null,
            "OrderItems": null,
            "BillingAddress": {
                "City": null,
                "Line1": null,
                "Line2": null,
                "State": null,
                "Country": null,
                "LastName": null,
                "FirstName": null,
                "PostalCode": null,
                "PhoneNumber": null
            },
            "ShippingAddress": {
                "City": null,
                "Line1": null,
                "Line2": null,
                "State": null,
                "Country": null,
                "LastName": null,
                "FirstName": null,
                "PostalCode": null,
                "PhoneNumber": null
            },
            "UzRegulatoryOrderDetails": {
                "TaxiTin": null,
                "Latitude": null,
                "Longitude": null,
                "TaxiPinfl": null,
                "TaxiVehicleNumber": null
            }
        },
        "Channel": null,
        "ExtraAttributes": [
            {
                "Key": "API_VERSION",
                "Value": "V1",
                "Description": ""
            }
        ]
    },
    "BlockDate": 638381923066765000,
    "CardBrand": "Visa",
    "PaymentId": "2TEST21AF2DTESTDA14L2E05A",
    "CardHolder": null,
    "Commission": null,
    "CreateDate": 638381922898406900,
    "CaptureDate": null,
    "CardCountry": null,
    "FinalAmount": 51.5,
    "CanBeCaptured": true,
    "PaymentStatus": "Blocked",
    "Preauthorized": true,
    "ExpirationDate": "2706",
    "IdempotencyKey": null,
    "CardOrigination": "Off-Us",
    "RejectionReason": null,
    "CardOwnerEntityType": null
}

๐Ÿ” Parsing Payment Statuses

You can parse the PaymentStatus field to determine the status of the payment transaction. Here are the possible payment statuses:

Transaction StatusDescription
DraftWhen the transaction is created and waiting for card details for the next action.
BlockedThe funds have been successfully blocked on the card.
Usually, this means you have used preauthorize: True
Transactions with Blocked statuses need to be committed within 30 days, otherwise, they will be refunded automatically.
CapturedThe funds have been captured successfully from the cardholder.
RefundedThe transaction has been refunded fully.
PartiallyRefundedThe transaction amount has been refunded partially.
RejectedThe transaction was rejected, because of different reasons.

๐Ÿ’ป Example: Parsing Payment Statuses in Python

import json

# Sample JSON response
response_json = '{"data": {"PaymentStatus": "Draft", ...}, "status": {"message": null, "errors": null, "type": null}}'

response_dict = json.loads(response_json)
payment_status = response_dict['data']['PaymentStatus']

if payment_status == 'Draft':
    print("Transaction is in draft status, awaiting card details.")
elif payment_status == 'Blocked':
    print("Funds have been blocked on the card, ready for capture.")
# ... similar checks for other payment statuses


๐Ÿ”’ Webhook Security Enhancements (Optional)

For an additional layer of security, you can validate webhook requests using HMAC signatures.

๐Ÿšง

๐Ÿ‘‰ Note: To enable this security layer for your company, please contact us and request activation.

Follow the steps below:

Step 1: Retrieve the HMAC Signature from the Header

Extract the HMAC signature from the X-HMAC-Signature header of the incoming request.

string suppliedSignature = Request.Headers["X-HMAC-Signature"];

Step 2: Compute the HMAC Signature

Using the shared secret key and the request payload, compute the HMAC signature.

string secretKey = "Your Secret Key"; // Replace with your actual secret key
string payload = JsonConvert.SerializeObject(requestData); // `requestData` is the POST request body
string computedSignature = GenerateHmacSignature(payload, secretKey);

private string GenerateHmacSignature(string data, string secretKey)
{
    var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
    var dataBytes = Encoding.UTF8.GetBytes(data);

    using var hmac = new HMACSHA256(secretKeyBytes);
    var signatureBytes = hmac.ComputeHash(dataBytes);
    var signature = BitConverter.ToString(signatureBytes).Replace("-", string.Empty).ToLower();

    return signature;
}

Step 3: Compare Both Signatures

Validate the request by comparing the computed HMAC signature with the signature in the header.

if (suppliedSignature == computedSignature)
{
    // Request is verified and valid
}
else
{
    // Request is not valid
}

By following these guidelines, you can efficiently integrate and secure your webhook endpoints while handling events from our API.