GAdsfy
Infrastructure

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.

1

Configure

Add your webhook URL in Dashboard → Settings → Webhooks.

2

Receive

GAdsfy sends a POST request with the event payload to your URL.

3

Verify & Process

Validate the signature, then process the event in your backend.

Requirements

  • Your endpoint must be publicly accessible over HTTPS.
  • Return a 2xx status 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

  1. 1GAdsfy computes an HMAC-SHA256 hash of the raw request body using your Webhook Secret.
  2. 2The resulting hex digest is sent in the x-gadsfy-signature header.
  3. 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_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Verification Examples

Verify signaturejavascript
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 });
});
Verify signaturepython
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}), 200

Event Types

Below are all the webhook events GAdsfy can send to your endpoint.

EventDescription
transaction.approvedA payment was successfully processed and approved.
transaction.declinedA payment attempt was declined by the payment provider.
transaction.refundedA previously approved transaction was refunded.
transaction.disputedA chargeback or dispute was opened for a transaction.
checkout.completedA checkout session was completed (payment captured).
checkout.expiredA checkout session expired before the customer completed payment.
payout.processedA merchant payout was sent to the connected account.
payout.failedA merchant payout failed to process.

Payload Example

Here is a full example of the JSON payload your endpoint receives when a transaction is approved.

transaction.approved webhook payloadjson
{
  "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

HeaderValue
Content-Typeapplication/json
x-gadsfy-signatureHMAC-SHA256 hex digest
x-gadsfy-eventEvent type (e.g. transaction.approved)
x-gadsfy-delivery-idUnique 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-id header for idempotency. The same event may be delivered more than once.
  • Always verify signatures. Never process a webhook without validating the x-gadsfy-signature header.
  • 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.