UpPromote Public API
  1. Webhook Event Payload
UpPromote Public API
  • API overview
  • Affiliate
    • Get affiliates
      GET
    • Get affiliate by ID
      GET
    • Create an affiliate
      POST
    • Approve/Deny affiliate
      POST
    • Set upline for an affiliate
      POST
    • Move an affiliate to a program
      POST
    • Connect a customer to an affiliate
      POST
  • Coupon
    • Get coupons
      GET
    • Assign a coupon to an affiliate
      POST
  • Payment
    • Get unpaid payments
      GET
    • Get paid payments (History)
      GET
    • Count total paid payments
      GET
    • Get a payment by ID
      GET
    • Mark as paid a manual payment
      POST
  • Referral
    • Get list referrals
      GET
    • Get a referral by ID
      GET
    • Create a referral
      POST
    • Add referral adjustment
      POST
  • Webhook
    • Get webhook subscriptions
    • Subscribe a webhook event
    • Update a webhook subscription
    • Delete a webhook subscription
  • Webhook Event Payload
    • Webhook overview
    • Referral new
      POST
    • Referral approved
      POST
    • Referral denied
      POST
    • Referral status changed
      POST
    • Affiliate new
      POST
    • Affiliate approved
      POST
    • Affiliate inactive
      POST
    • Affiliate status changed
      POST
    • Payment paid
      POST
  1. Webhook Event Payload

Webhook overview

Verifying Webhook Signatures#

To ensure that webhook requests are coming from our servers and have not been tampered with, you need to verify the webhook signature included in the request headers.
Each webhook request includes a header:
X-UpPromote-Signature: <signature>
The signature is generated using the HMAC-SHA256 algorithm with your subscription’s secret key and the raw request body.
Your application should:
1.
Retrieve the raw request body.
2.
Get the X-UpPromote-Signature header value.
3.
Compute an HMAC-SHA256 hash using the secret key and the raw body.
4.
Compare the calculated hash with the received signature using a time-safe comparison.
If they match, the webhook is valid. Otherwise, reject the request.

Example Implementations#

PHP (Laravel Middleware)#

public function handle(Request $request, Closure $next): mixed
{
    $secret = 'your-subscription-secret'; // Replace with your secret
    $payload = $request->getContent(); // Raw request body
    $receivedSignature = $request->header('X-UpPromote-Signature');

    $calculatedSignature = hash_hmac('sha256', $payload, $secret);

    if (hash_equals($receivedSignature, $calculatedSignature)) {
        logger('Webhook valid');
        return $next($request);
    } else {
        logger('Webhook invalid. Received: ' . $receivedSignature . ', Calculated: ' . $calculatedSignature);
        return response()->json(['error' => 'Invalid signature'], 401);
    }
}

Node.js (Express)#

Python (Flask)#

import hmac
import hashlib
from flask import request, abort

def verify_webhook():
    secret = b'your-subscription-secret'  # Replace with your secret
    payload = request.get_data()  # Raw request body
    received_signature = request.headers.get('X-UpPromote-Signature')

    calculated_signature = hmac.new(secret, payload, hashlib.sha256).hexdigest()

    if hmac.compare_digest(received_signature, calculated_signature):
        print("Webhook valid")
        return True
    else:
        print("Webhook invalid")
        abort(401, "Invalid signature")

Ruby (Sinatra)#

require 'openssl'

before '/webhook' do
  secret = 'your-subscription-secret' # Replace with your secret
  payload = request.body.read
  received_signature = request.env['HTTP_X_SIGNATURE']

  calculated_signature = OpenSSL::HMAC.hexdigest("SHA256", secret, payload)

  halt 401, "Invalid signature" unless Rack::Utils.secure_compare(received_signature, calculated_signature)
end

Key Notes#

Always use the raw request body (before JSON parsing).
Use HMAC-SHA256 with your subscription secret.
Compare signatures using a time-safe comparison function (e.g., hash_equals in PHP, hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js).
Reject requests with mismatched signatures.

Best Practices#

To keep your webhook integration secure and reliable, consider the following best practices:

1. Always use HTTPS#

Ensure that your webhook endpoint is only accessible via HTTPS with a valid SSL certificate to prevent man-in-the-middle attacks.
Do not accept webhook requests over plain HTTP.
Your webhook endpoint must:
Accept requests using the POST method only.
Return a 200 OK HTTP status code to acknowledge successful receipt of the webhook.
Be served over HTTPS with a valid SSL certificate — otherwise, the webhook subscription will fail.

2. Use the raw request body#

Signature verification must be done against the exact raw body of the request, before JSON parsing or other transformations.

3. Time-safe comparison#

Always use a constant-time comparison function (hash_equals, hmac.compare_digest, crypto.timingSafeEqual, etc.) to prevent timing attacks.

4. Validate headers#

Check that the X-UpPromote-Signature header exists before attempting validation.
Optionally, reject requests missing required headers.

5. Respond quickly#

The webhook sender will wait up to 6 seconds for a response from your server.
Your endpoint should return a 200 status code within that time window.
Do not perform long-running or heavy operations during the webhook request. Instead, push the event to a queue or background job worker for further processing.

6. Retry on failure#

If the delivery fails (due to timeout, network error, or non-2xx response), the webhook will be retried up to 3 times.
Each retry attempt will be delayed by 5 minutes.
If all retries fail, the webhook is considered undeliverable and no further attempts will be made.

7. Log failures securely#

Log invalid signatures and errors, but avoid logging sensitive data like the raw secret or full payload.
Include enough metadata (timestamp, request ID) to debug issues.

8. Rotate secrets when needed#

If you suspect that a secret key has been exposed, rotate it immediately.
Implement a process that allows for key rotation with minimal downtime.

9. Restrict IPs (optional)#

If possible, only accept webhook traffic from known IP ranges.
This adds an extra layer of defense but should not replace signature validation.

10. Idempotency handling#

Webhooks may be sent multiple times (retries). Ensure your processing logic is idempotent (safe to run more than once).

11. Versioning#

If multiple webhook versions exist, verify and handle them consistently.
Keep backward compatibility when updating your validation logic.
Modified at 2025-10-06 07:11:20
Previous
Delete a webhook subscription
Next
Referral new
Built with