The key idea

What is a webhook? It is a message that one system sends to a URL on your server the moment something happens, so your code does not have to keep asking. In payments, it tells your server that a customer paid, even if the customer closed the browser. Verify the message before you deliver anything.

Webhook meaning in simple words

A webhook is a message that one system sends to a URL on your server the moment something happens. It is a normal HTTP request, almost always a POST, with a few details about the event in its body.

The key idea is the direction. Usually your code asks another system and waits. With a webhook, the other system contacts you: you give it an address once, and it uses that address each time the event happens.

Developers in Egypt usually meet webhooks first in payments. A customer pays, and the payment service tells the seller's server right away.

Polling or webhooks: an example from daily life in Egypt

You order lunch by phone from a restaurant in Giza, then you call the shop every ten minutes: has my order left yet? Most of the time the answer is not yet. That is polling: asking again and again.

Normally you give your phone number once, and the delivery rider calls you when he arrives. That is a webhook: the other side contacts you when there is news.

PointPollingWebhook
Who starts the contactYour server, again and againThe other system, once per event
When you learn the newsAt your next check, often lateClose to the moment it happens

Polling still works when your code cannot receive requests. But when events are rare and time matters, as with payments, a webhook fits better.

The five parts of a webhook

Every webhook has the same five parts:

  1. Your URL. An address on your server that accepts a POST, often called an endpoint, for example https://yoursite.com/webhook.php. You register it once with the sender.
  2. The event. What happened, as a short name such as payment.success.
  3. The payload. The body of the request, usually JSON, with the details.
  4. The headers. Extra lines sent with the request, often about the delivery itself.
  5. Your reply. An HTTP status code. Any code that starts with 2, written 2xx, means: I received it. Anything else, or no answer in time, means the delivery failed.

Many senders try again after a failed delivery. This is called a retry.

API call, callback page or webhook: what is the difference?

These three terms differ in who starts and where the information arrives.

QuestionAPI callCallback pageWebhook
Who starts it?Your codeThe browser of the customerThe other system
Where does it arrive?At the other systemOn a page of your site, in that browserAt a URL on your server
What if the customer closes the tab?No effectThe page never opensIt still arrives

The callback page is the page of your site that the customer returns to after paying, with the result in its address. Both it and the webhook are only signals, because anyone can type a URL or send a POST. The proof is an API call that your own code makes to an address you trust.

A real example: the payment webhook from Gammal Tech

Gammal Tech is an Egyptian platform that gives a website ready backend services, including payments. Webhooks are optional: you set a Webhook URL in the project settings. After every successful payment, including each subscription renewal, Gammal Tech sends a POST to that URL with this JSON body:

{"event": "payment.success", "timestamp": 1748524800, "payment_token": "eyJ…"}

The token is shortened here: it is a signed JSON Web Token (see what is JWT). The timestamp counts seconds since the start of 1970. Two headers come with the request, X-Gammal-Event and X-Gammal-Attempt. Your server then does four things:

  1. Reads payment_token from the body.
  2. Sends it in a POST to the verify endpoint https://api.gammal.tech/sdk/pay/link/verify.php with the JSON body {"payment_token": "…"}.
  3. Reads status in the answer: 1 means a real payment, verified for the first time. 2 means a real payment that was verified before, for example by your callback page. 0 means invalid.
  4. Answers with an HTTP 2xx status, quickly.

Status 1 and status 2 both prove that the payment is real. Which one your server sees depends on who asked first: if the browser of the customer already verified the token on your callback page, your server gets 2. So a server should not wait for 1. It should look up the transaction in its own records and deliver only if it has not delivered before.

Imagine a teacher in Cairo who sells an online course. A student pays by card on his phone and closes the browser before it returns to her thank you page. Without a webhook, her site never hears about the payment, and the paid lessons stay locked. With a webhook, her server gets the message anyway, verifies the token and marks the order as paid.

A short webhook handler in PHP

This handler does the four steps in PHP. deliver_once is your own function: it looks up the transaction ID in your records, gives the customer what they bought only if that transaction was not delivered before, and saves it as delivered. Read the live guide for the full description of the verify answer.

<?php
// webhook.php: called by Gammal Tech
$body = json_decode(file_get_contents('php://input'), true);
$token = $body['payment_token'] ?? '';

// Never trust the body: verify it
$url = 'https://api.gammal.tech/sdk/pay/link/verify.php';
$context = stream_context_create(['http' => [
    'method' => 'POST',
    'header' => 'Content-Type: application/json',
    'content' => json_encode(['payment_token' => $token]),
    'ignore_errors' => true,
]]);
$reply = @file_get_contents($url, false, $context);
$answer = json_decode((string) $reply, true);
if (!is_array($answer)) { http_response_code(500); exit; } // retry later

$status = (int) ($answer['status'] ?? 0);
if ($status === 1 || $status === 2) {      // a real payment
    deliver_once($answer['txn'], $answer); // your own function
}
http_response_code(200);

The handler replies 500, not 2xx, only when it gets no usable answer from the verify endpoint, so the delivery is tried again later. The @ stops PHP from printing a warning into the reply. Keep slow work, such as sending emails, out of the handler.

Why the handler must be safe to run twice

If your server does not answer 2xx quickly, Gammal Tech retries the delivery a few times, so the same payment can reach your handler more than once. Code that gives the same final result no matter how many times it runs is called idempotent. Here the transaction ID does the work: txn is the same on every repeat, so deliver_once finds it in your records and does nothing the second time.

A page with no server behind it has no records to check, so there you deliver only on status 1 and never on 2. On a server, your own records are the judge. A useful habit: put your order number in the desc of the payment link. The verify answer returns it as description, so your server knows which order was paid.

Security basics for any webhook

A webhook URL is a public door into your server: anyone who learns the address can send a POST to it. Three habits keep it safe:

  • Use HTTPS, so nobody on the network can read or change the message.
  • Never trust the body alone. A message that says a payment succeeded is not a payment.
  • Verify first, act second. Many services sign each message so that you can check it. Gammal Tech puts a token in the body, and a fake token gets 0 from the verify endpoint.

How to test a webhook when there is no test mode

Gammal Tech has no test mode: every payment is real money. Fees and refunds differ by payment method, and the current rules are in the live guide. Read them, then test in three steps:

  1. A fake request. Send a POST to your handler with an invented token. No payment is needed. The verify endpoint answers 0, so nothing should be delivered, and your handler should still reply 2xx. A 500 reply means your server could not get an answer from the verify endpoint.
  2. The cancelled path. Open your payment link and cancel. The callback page gets ?status=cancelled and no token, and no order should be delivered.
  3. One small real payment. Pay a small amount yourself. Check that the webhook arrived and that the order was delivered exactly once. Then send the same body again: nothing should be delivered a second time.

Log each request in a private file while you test, and remember that step three is a real payment with the normal fees.

When you do not need a webhook at all

Many small sites need no webhook. After a card payment, the customer returns to your callback page with ?status=success and a payment_token in the address. The page sends the token to the same verify endpoint and delivers on status 1. The token is short lived, so verify it at once.

That is enough for one time payments where a missed return can be fixed with one message. Add a webhook when a missed message costs you: subscriptions, where each renewal happens with no customer in front of a browser, or a shop with many orders.

Common questions about webhooks

Is a webhook the same as an API?

No. With an API call, your code asks another system and waits. A webhook goes the other way: the other system calls your URL. They often work together: the webhook brings the news, and an API call confirms it.

Do I need a server to receive webhooks?

Yes. You need a public URL that accepts a POST and runs code, such as a PHP file on your hosting. A site made only of HTML files cannot receive one, so it should use the callback page with verification.

What happens if my server is down?

Gammal Tech retries the delivery a few times. Do not depend on retries alone: keep the verification on your callback page too. A payment token that you hold can still be checked at the verify endpoint while it is valid.

Are webhooks secure?

As secure as the code that receives them. Use HTTPS, verify the token before you act, and make the handler safe to run twice. Then a fake request does no harm.

Start with a focused project on Gammal Tech

If your account is already approved, start at step 2. Follow these actions inside your own account:

  1. Open the registration page, create your account once and complete the identity checks shown there. The standard document is a National ID from a country whose citizenship you hold; read the document requirements and limited Egyptian exceptions. Wait for approval before integration; approval can take up to 10 days.
  2. Sign in to your account, then open Developer Mode. You will see your project list.
  3. Select an existing project, or click Create Project for a new one. Open its page and record the project ID, pid. This is public configuration, not a secret key.
  4. In project settings, add the HTTPS domain that will run your website. Register the www hostname and the hostname without it separately if visitors use both.
  5. Follow this guide’s integration example or exercise on the registered website. Check one complete task from start to finish and record what happens before adding more features.

The Webhook URL is an optional field in the project settings, the same place where you enable payments.

Source and service details

Integration and pricing details are based on the Gammal Tech guide. Check the documentation before publishing or changing your project configuration.

Articles & Guides