Webhooks
Receive real-time HTTP notifications when events occur on your GAdsfy account. Webhooks allow you to automate workflows such as order fulfillment, email notifications, and analytics tracking.
How It Works
When an event occurs (e.g., a payment is approved), GAdsfy sends a POST request to your configured endpoint with a JSON payload describing the event.
Configure
Add your webhook URL in Dashboard → Settings → Webhooks.
Receive
GAdsfy sends a POST request with the event payload to your URL.
Verify & Process
Validate the signature, then process the event in your backend.
Requirements
- •Your endpoint must be publicly accessible over HTTPS.
- •Return a
2xxstatus within 30 seconds to acknowledge receipt. - •Failed deliveries are retried up to 5 times with exponential backoff.
Signature Verification
Every webhook request includes a cryptographic signature in the x-gadsfy-signature header. You must verify this signature to ensure the request originated from GAdsfy and was not tampered with.
Security Critical
Always verify the webhook signature before processing the payload. Skipping verification exposes your application to spoofing attacks where an attacker could forge fake payment events.
How Signatures Work
- 1GAdsfy computes an HMAC-SHA256 hash of the raw request body using your Webhook Secret.
- 2The resulting hex digest is sent in the
x-gadsfy-signatureheader. - 3On your end, compute the same HMAC-SHA256 and compare it using a timing-safe equality check.
Your Webhook Secret (found in Dashboard → Settings → Webhooks):
whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxVerification Examples
import crypto from "crypto";
function verifyWebhookSignature(rawBody, signatureHeader, secret) {
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
// Use timing-safe comparison to prevent timing attacks
const expected = Buffer.from(expectedSignature, "hex");
const received = Buffer.from(signatureHeader, "hex");
if (expected.length !== received.length) return false;
return crypto.timingSafeEqual(expected, received);
}
// Express.js example
app.post("/webhooks/gadsfy", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-gadsfy-signature"];
const isValid = verifyWebhookSignature(req.body, signature, process.env.GADSFY_WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.body);
// Process the event...
res.status(200).json({ received: true });
});import hmac
import hashlib
def verify_webhook_signature(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)
# Flask example
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/webhooks/gadsfy", methods=["POST"])
def handle_webhook():
signature = request.headers.get("x-gadsfy-signature", "")
is_valid = verify_webhook_signature(
request.data,
signature,
os.environ["GADSFY_WEBHOOK_SECRET"],
)
if not is_valid:
return jsonify({"error": "Invalid signature"}), 401
event = request.get_json()
# Process the event...
return jsonify({"received": True}), 200Event Types
Below are all the webhook events GAdsfy can send to your endpoint.
| Event | Description |
|---|---|
transaction.approved | A payment was successfully processed and approved. |
transaction.declined | A payment attempt was declined by the payment provider. |
transaction.refunded | A previously approved transaction was refunded. |
transaction.disputed | A chargeback or dispute was opened for a transaction. |
checkout.completed | A checkout session was completed (payment captured). |
checkout.expired | A checkout session expired before the customer completed payment. |
payout.processed | A merchant payout was sent to the connected account. |
payout.failed | A merchant payout failed to process. |
Payload Example
Here is a full example of the JSON payload your endpoint receives when a transaction is approved.
{
"id": "evt_Lm4pKqRsT8nW",
"object": "event",
"type": "transaction.approved",
"created_at": "2026-04-05T14:22:33Z",
"data": {
"id": "txn_rS8qYm3jN",
"object": "transaction",
"status": "approved",
"amount": 4900,
"currency": "USD",
"product": {
"id": "prod_abc123",
"name": "Digital Marketing Masterclass"
},
"customer": {
"email": "buyer@example.com",
"name": "John Doe",
"country": "ZA"
},
"payment_method": "card",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2028
},
"checkout_session_id": "cs_xK7mNpQ2wL9r",
"metadata": {
"order_ref": "ORD-9281"
},
"created_at": "2026-04-05T14:22:30Z"
}
}Headers Sent
| Header | Value |
|---|---|
Content-Type | application/json |
x-gadsfy-signature | HMAC-SHA256 hex digest |
x-gadsfy-event | Event type (e.g. transaction.approved) |
x-gadsfy-delivery-id | Unique delivery ID for idempotency |
Best Practices
- ✓Respond quickly. Return a 2xx within 30 seconds. Process heavy logic asynchronously after acknowledging.
- ✓Handle duplicates. Use the
x-gadsfy-delivery-idheader for idempotency. The same event may be delivered more than once. - ✓Always verify signatures. Never process a webhook without validating the
x-gadsfy-signatureheader. - ✓Use HTTPS only. Webhook endpoints must use TLS encryption. HTTP endpoints are rejected.
- ✓Log everything. Store the raw payload and headers for debugging. You can also view recent deliveries in the Dashboard.
