Overview

A webhook is an event-driven communication system that allows one system to send real-time data to another system via HTTP when a specific event occurs.

When a transaction happens on your system, be it card, USSD or payout. Your system will not be aware of this. However, when you set up a webhook, we will notify you of the type of event and the status.

How It works

  1. Set up a URL: First, you create a special URL on your server so that Cepta can send a POST request of transaction status.
  2. Payment Event Trigger: When a payment event happens, Cepta will automatically “call” your URL to notify your system of the event.
  3. Your System Responds: Your server receives the webhook, processes the information , and sends back a simple acknowledgment like a 200 OK to let us know that the data was received successfully.

It’s important that you query transaction status before you give value to your customer.

Set up a URL

To set a webhook URL, head over to your Cepta dashboard > Settings > API Credentials. Add your URL and click Set URLs.

Set webhook URL

Validate Event Source

To ensure the webhook events are coming from us, we will send a signature hash as part of the header, this hash will be a SHA512 calculated encryption with header key hash-key you will have to validate it before making use of the response data. To calculate this key, you will need to generate a SHA512 hash by concatenating your secret key and merchant ID. This hash is then compared with the “hash-key” found in the response header to verify the integrity of the request before processing it.

Always validate the signature hash before proceeding with business logic.

For example, using the secret key test_scrk_5gtnuq9buqeic7c3edu8yjrsqnzhhnur and the merchant ID TW201325608238020, the concatenated string would be:

"test_scrk_5gtnuq9buqeic7c3edu8yjrsqnzhhnur" | "TW201325608238020"

Then, you generate the SHA512 hash of that string and compare it with the hash-key from the response header.

Javascript code sample:

const crypto = require('crypto');

const secretKey = "test_scrk_5gtnuq9buqeic7c3edu8yjrsqnzhhnur";
const merchantId = "TW201325608238020";

const concatenatedString = secretKey + "|" + merchantId;

// Generate SHA512 hash
const hashValue = crypto.createHash('sha512').update(concatenatedString).digest('hex');

const responseHeaderHash = "b78e7c3b8b501ff84d3c96f98e3f7b97869b98958bce15b5cd14b9e7a03e5852";

// Compare the calculated hash with the header hash
if (hashValue === responseHeaderHash) {
    console.log("Hash verified successfully! Proceeding with processing.");
} else {
    console.log("Hash mismatch! Do not process the request.");
}

Payment Event Trigger

When a transaction happens, we will send information regarding this transaction to your system via a dedicated URL that you have created. Below is a list of event types that we supported.

Supported Webhook Event Types

Event TypesDescription
card.collection.statusEvent triggered when a card transaction occurred
bank.transfer.collection.statusEvent triggered when a bank transfer transaction occurred
payout.transaction.statusEvent triggered when a payout transaction occurred
wallet.transaction.statusEvent triggered when a wallet transaction occurred

Event types structure

The data we send across to you for all event type are of similar structure, only the eventType and the data object will varies based on what type of event information we send.

    {
        "data": {
            "merchantId": "TW201325608238020",
            "transactionAmount": 1000.0000,
            "cardExpirationDate": "",
            "cardholderName": "testing lee",
            "currency": "NGN",
            "destinationCountry": "Nigeria",
            "feeDeductionAmount": 5.0000,
            "maskedPan": "23409857****3353",
            "netAmount": 995.0000,
            "payerEmail": "[email protected]",
            "payerFirstName": "John",
            "paymentDescription": "Payment tests",
            "status": "SUCCESSFUL",
            "sourceCountry": "Nigeria",
            "transactionDate": "2025-01-17T01:09:00",
            "transactionReference": "bdknnnndfbbbvvbbnnndgdgvgoedgd",
            "ipAddress": "10.110.0.1"
        },
        "eventType": "card.collection.status",
        "sentAt": "2025-01-17T03:10:06.5031934"
    }     

Best Practices

1.Ensure Secure URLs: Use HTTPS for your webhook URL to ensure the communication between systems is encrypted and secure.

2.Validate Webhook Signatures: Always validate the signature hash from the request header to confirm that the webhook is genuinely coming from Cepta and not from a malicious third party.

3.Check Event Data Before Processing: Before using the event data in your business logic, verify that the status is successful to avoid processing failed transactions.

4.Avoid Re-Processing: If your system has already processed a webhook event, ensure you don’t reprocess the same event. This can be done by checking the transaction reference or using idempotency keys.

5.Handle Failures Gracefully: If your server doesn’t respond with 200 OK, Cepta will retry the webhook a few times. Make sure your server handles these retries gracefully.

6.Monitor Webhook Deliveries: Set up logging to monitor the incoming webhook requests and responses. This helps to identify and debug issues quickly.

7.Respond Quickly: Send a response as soon as possible (ideally within a few milliseconds) to acknowledge receipt of the webhook. If processing the data takes longer, do it asynchronously.

8.Ensure Idempotency: Your webhook endpoint should handle duplicate notifications without adverse effects. This is especially important in case of retries.

9.Test Webhooks: Before going live, use sandbox or test environments to verify that your webhook integration is correctly processing the events.