← The Logbook
Jun 29, 2026

How to Use Webhooks: Build Shopify Affiliate Programs 2026

Learn how to use webhooks for a reliable Shopify app affiliate program. Master receiving, verifying, & handling events with PartnerDock.

How to Use Webhooks: Build Shopify Affiliate Programs 2026

You're probably here because the basic version already “works.” You pasted a webhook URL into a dashboard, saw a test payload arrive, and checked the box.

That isn't enough for affiliate payouts.

When money, partner trust, and reconciliation sit downstream from a webhook, the primary task isn't receiving JSON. Instead, the focus is making sure every event is authentic, processed once, traceable later, and mapped cleanly into your accounting workflow. That's the gap most webhook tutorials skip, and it's exactly where production systems break.

Table of Contents

Why Webhooks Are Essential for Your Affiliate Program

A payout system falls apart when attribution arrives late or out of order. An affiliate drives sales, your app records conversions, but your reconciliation job only checks for updates on a schedule. By the time the dashboard refreshes, finance is already asking why a commission doesn't match the underlying order record.

That's why learning how to use webhooks matters in affiliate infrastructure. Webhooks push an event the moment something happens. Polling asks over and over whether something happened yet. In a financial workflow, that difference changes how much cleanup your team does later.

A comparison infographic showing how webhooks provide real-time affiliate tracking versus traditional delayed polling methods.

Polling breaks at the worst moment

Polling looks simple at first. It also creates the exact failure mode payout teams hate most: delayed visibility with ambiguous state.

A scheduled sync can hit while an upstream system is mid-update. It can miss an event window. It can pull partial data and make your database look complete when it isn't. Then someone exports commissions, sees a mismatch, and starts a manual investigation.

Webhook-based delivery avoids the waste too. Svix's State of Webhooks report says webhook adoption among software organizations increased from 83% to 85% between 2023 and 2024, which reflects the broader move toward event-driven architectures. That number matters because it shows this isn't an edge pattern anymore. It's the default operating model for systems that need timely synchronization.

Practical rule: If a missed event can change who gets paid, polling is the fallback, not the primary design.

Why event-driven delivery fits payout systems

In affiliate programs, the source system should speak when an event occurs. It shouldn't wait for your next scheduled job. That gives you cleaner sequencing for commission creation, review workflows, payout state changes, and audit trails.

This is also why major platforms rely on webhooks for system-to-system coordination, and why affiliate operators increasingly expect them as part of any serious integration stack. Real-time delivery means zero traffic when nothing changes, and immediate delivery when something does. That pattern is a much better fit for financial events than repeated fetch loops.

If you're evaluating affiliate infrastructure, the product details that matter most usually sit inside the operational model, not the marketing copy. A platform built for Shopify app partner operations should support accurate event handling, clean reconciliation, and predictable cost structure. That's the context behind tools like PartnerDock's affiliate platform features.

Creating Your First Webhook Receiver Endpoint

The first version of your receiver should be boring. That's a good sign.

Don't start by mixing verification, payout logic, retries, and partner balance updates into one controller. Start with a public endpoint whose only job is to accept a POST request and let you inspect what the sender is delivering.

A hand drawing a pencil line connecting incoming email icons to an API endpoint server gateway illustration.

Start with a single-purpose route

A webhook receiver is just an HTTP endpoint you control. In practice, that means:

  • Publicly reachable URL that the provider can call over HTTPS
  • POST handler for incoming event payloads
  • Raw body access if you'll later verify signatures
  • Basic logging so you can inspect headers and structure before adding business logic

Keep the route isolated from your normal app API. Don't reuse a customer-facing controller. A dedicated path makes it easier to apply tighter middleware, custom rate controls, and better logs.

A minimal Node and Express receiver

Here's a clean starting point in Node.js with Express:

const express = require('express');

const app = express();

// For the first pass, JSON parsing is enough.
// Later, switch to raw body handling for signature verification.
app.use(express.json());

app.post('/webhooks/affiliate', (req, res) => {
  console.log('Headers:', req.headers);
  console.log('Payload:', req.body);

res.status(200).json({ received: true });
});

app.listen(3000, () => {
  console.log('Webhook receiver listening on port 3000');
});

That endpoint gives you a front door. It doesn't make trust decisions yet. It doesn't mutate financial records. It just confirms the provider can reach you and shows you the shape of incoming data.

A few details matter even in this early version:

  1. Return a success response deliberately. If you leave requests hanging, the sender may retry.
  2. Log enough to inspect structure. Event name, request headers, and payload shape are useful. Full payload logging can wait until you've reviewed sensitivity and retention rules.
  3. Resist transforming data early. New developers often remap fields before they've seen enough real payloads. Keep the first pass raw.

A webhook receiver isn't your business workflow. It's your intake layer.

When you test locally, use a tunnel such as Ngrok so the provider can reach your machine. For one-off payload inspection, tools like webhook.site are handy because they show you exactly what arrived without any application code in the way.

Once the payload reaches your route consistently, you can make a better architectural decision: what should be trusted immediately, what should be queued, and what should be rejected. That's where most “how to use webhooks” guides finally start to become useful.

Securing Your Endpoint with Signature Verification

If your webhook endpoint can create or alter payout records, it's part of your financial perimeter. Treat it that way.

The most important control is HMAC signature verification. A provider signs the payload with a shared secret and SHA-256, sends the signature in a header, and your service recomputes the signature locally before processing. If the values don't match, you reject the request.

A diagram illustrating the five-step process for securing webhooks using digital signature verification and data integrity.

Why shared-secret signing matters

Static API keys are the wrong mental model for incoming webhooks. They identify a client. They don't prove that a specific payload was sent intact.

That difference matters because the receiver must validate both origin and integrity. According to Stytch's webhook security guidance, 78% of webhook-related breaches stem from unverified or weakly authenticated requests. If you process financial events without signature verification, you're trusting any caller that can reach the route.

In affiliate systems, that risk isn't theoretical. A forged commission event or payout status update can corrupt balances, trigger fraud reviews, or push finance into manual cleanup.

A practical HMAC verification example

To verify correctly, you need the raw request body, not a re-serialized JSON object. Even harmless formatting differences can change the signature.

Here's an Express example using raw body handling:

const express = require('express');
const crypto = require('crypto');

const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// Use raw body so the exact payload bytes are available
app.use('/webhooks/affiliate', express.raw({ type: 'application/json' }));

app.post('/webhooks/affiliate', (req, res) => {
  const signatureHeader = req.get('X-Provider-Signature');
  const rawBody = req.body;

const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(rawBody)
    .digest('hex');

if (!signatureHeader) {
    return res.status(401).json({ error: 'Missing signature' });
  }

const provided = Buffer.from(signatureHeader, 'hex');
  const expected = Buffer.from(expectedSignature, 'hex');

if (
    provided.length !== expected.length ||
    !crypto.timingSafeEqual(provided, expected)
  ) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

const payload = JSON.parse(rawBody.toString('utf8'));

console.log('Verified event:', payload.event);

return res.status(200).json({ received: true });
});

app.listen(3000);

A few implementation notes separate reliable code from fragile code:

  • Compare with a timing-safe function. Don't use plain string equality for secrets.
  • Verify before parsing or executing logic. Reject bad requests as early as possible.
  • Store secrets outside code. Environment variables or a secret manager are better than constants in source files.

Verify first. Parse second. Persist third.

Security controls that belong around verification

Signature verification is the gatekeeper, but it shouldn't stand alone.

Use these additional controls:

  • Restrict trusted senders: Accept webhook traffic only from expected source ranges when the provider supports that model.
  • Rotate secrets: Shared secrets shouldn't live forever. Rotation lowers the blast radius if a secret leaks.
  • Validate and sanitize payloads: A valid signature doesn't mean the payload matches your expected schema.
  • Check replay defenses: If the provider includes timestamps or unique delivery IDs, use them to reject stale or repeated requests.

That last point is worth stressing. Some teams verify the signature and stop there. That still leaves room for replayed valid requests if the payload can be resent later. In payout workflows, replay prevention is a security feature and an accounting safeguard.

Building a Resilient Handler for Idempotency and Retries

Production webhook delivery is messy by design. Networks time out. Upstream systems retry. Your database stalls for a moment. The sender doesn't know whether you completed the work, so it sends the event again.

That isn't a bug. It's normal distributed-system behavior.

A hand-drawn illustration showing arrows hitting a shield protected server to represent secure webhook processing.

Why duplicate delivery is normal

The handler that mutates financial data must be idempotent. That means processing the same event multiple times produces the same final result as processing it once.

This is one of the core reliability practices in Apideck's webhook overview. Engineers need to build idempotent handlers that survive retries and duplicates, return 2xx responses quickly, and process asynchronously. That guidance matters even more in affiliate systems because one duplicated webhook can create a bad payout record and force reconciliation work that should never have existed.

A durable idempotency pattern

The usual pattern is straightforward:

  1. Receive the verified event.
  2. Extract a stable event identifier from the payload or delivery headers.
  3. Attempt to write that identifier into a table with a uniqueness constraint.
  4. If the insert succeeds, enqueue downstream processing.
  5. If the identifier already exists, treat the event as already handled and return success.

A simple schema might include:

Field Purpose
event_id Unique key from the provider
event_type Helps with filtering and debugging
received_at Audit timestamp
processing_status queued, completed, failed
payload_hash Useful for later inspection

What matters is where the uniqueness lives. Put it in durable storage, not process memory. An in-memory cache works until the app restarts or traffic spans multiple instances.

If the consequence of duplication is double payment, deduplication belongs in the database layer, not just in application code.

Ack fast and process later

A common mistake is doing all business logic inside the request-response cycle. That slows down the sender, increases timeouts, and encourages more retries.

A better flow looks like this:

  • Request thread: verify signature, check idempotency key, persist receipt, enqueue job, return 2xx
  • Worker process: load payload, apply business rules, update balances, create audit entries, mark job complete

Here's a trimmed example:

app.post('/webhooks/affiliate', async (req, res) => {
  const payload = req.verifiedPayload;
  const eventId = payload.id;

const inserted = await saveWebhookReceiptIfNew({
    eventId,
    eventType: payload.event,
    rawPayload: payload
  });

if (!inserted) {
    return res.status(200).json({ duplicate: true });
  }

await enqueueWebhookJob({ eventId });

return res.status(200).json({ received: true });
});

That split gives you two benefits. First, the sender gets a timely acknowledgment. Second, your real processing can use retries, backoff, dead-letter handling, and richer error classification without holding open an HTTP request.

The result is calmer operations. When failures happen, they become visible work items instead of silent payout corruption.

Translating Webhook Events into Payout Workflows

Once the receiver is secure and resilient, the next challenge is mapping raw events into accounting actions. At this point, many integrations become awkward. Developers think in event names. Finance thinks in balances, approvals, holds, and payout batches.

Your code has to translate between those worlds.

From event payload to accounting record

Say a commission event arrives. The receiver shouldn't immediately “pay the affiliate.” It should create a sequence of controlled internal actions.

A practical flow often looks like this:

  • Parse the event type and delivery metadata.
  • Extract the partner identifier, related order or conversion reference, and commission details from the payload.
  • Match the event to your internal partner record.
  • Write a commission ledger entry with a clear source reference.
  • Apply business rules such as review status, hold period, or exception flags.
  • Queue any downstream payout eligibility updates.

That structure keeps event intake separate from money movement. It also makes investigation easier later because you can answer two different questions: “Did we receive the event?” and “What financial state change did we derive from it?”

This separation matters because affiliate reconciliation systems are attractive targets for abuse. The Hookdeck tutorial page notes that 68% of webhook failures in 2025 stemmed from unauthenticated or replayed payloads, particularly in affiliate reconciliation systems. Even after verification, your business logic should still be conservative. A valid event can still be incomplete, duplicated upstream, or inconsistent with your current account state.

For teams evaluating end-to-end partner operations, it helps to look at the full workflow, not just event delivery. How PartnerDock works is a useful example of the broader lifecycle from tracking through reconciliation and payout operations.

How PartnerDock handles attribution data

This is an important distinction: PartnerDock does not use an outbound webhook system for founders.

Instead, PartnerDock uses a pull-based Partner API model. Founders query the API to fetch referral and attribution data when they need it, rather than subscribing to pushed events. In practice, that means your integration logic should treat PartnerDock as a source you read from on demand, not a sender that posts commission.created or payout.processed events to your endpoint.

That distinction matters architecturally. If you're building around PartnerDock, your job is to decide when to request data, how to reconcile what changed, and where to store internal state once the API returns the latest attribution records. The system is still event-aware from a business standpoint, but the delivery model is API retrieval rather than webhook subscription.

A practical pattern is to:

  • Query the Partner API for referral and attribution data on a schedule or during internal sync jobs
  • Match returned records to your internal partner, order, or commission entities
  • Write deterministic ledger or reconciliation updates in your own system
  • Preserve source references so finance can trace each balance change back to the API data you fetched

PartnerDock's attribution sync runs internally on its own schedule, so founders are not receiving pushed notifications when those updates occur. If you're evaluating fit, the relevant product details are the API access model and attribution workflow described in PartnerDock's features and how PartnerDock works.

The broader lesson still applies beyond PartnerDock: whether data arrives by webhook or by API pull, you want the same operational discipline around reconciliation, auditability, and controlled financial state changes.

Monitoring and Troubleshooting Your Webhook Integration

A webhook integration isn't done when the first event succeeds. It's done when failures are visible, diagnosable, and recoverable.

This part is often underestimated because the happy path is easy to demo. The painful path starts later, when a sender changes payload shape, a background job fails halfway through processing, or a replayed request slips into a weak intake pipeline. Existing content often treats webhook setup like a static checklist, but the bigger operational gap is real-time payload validation and debugging strategy, which Snipcart's webhook article highlights as a common source of silent data loss in complex integrations.

Logs need business context

Structured logging is the difference between “something failed” and “this exact commission event was received, verified, queued, retried, and finally rejected by a downstream rule.”

Include fields like:

  • Delivery identifier for correlation across services
  • Event type so you can group failure patterns
  • Verification result to separate bad requests from business exceptions
  • Processing status such as received, queued, completed, failed
  • Internal record references like partner ID or commission ID where appropriate

Don't rely on free-form application logs alone. Financial operations need an audit trail that developers, operations, and finance can all follow.

Use live inspection before you blame the sender

When something looks wrong, inspect the raw delivery before changing code. webhook.site is useful for looking at the exact headers and body. Ngrok helps when you need a provider to hit your local receiver during development. Both are practical because they remove guesswork.

The payload you think you're handling and the payload that actually arrived are often not the same thing.

It also helps to keep a dead-letter path for events that fail after acceptance. That lets you reprocess them deliberately instead of losing them during a transient outage.

If you're migrating from an older partner stack, observability matters even more. Data drift often appears during cutover, when two systems briefly disagree about attribution or payout state. Teams planning that move should pay close attention to migration workflow and exception handling, which is why PartnerDock's migration guidance for teams leaving PartnerJam is relevant operational reading.


If you're building or migrating a Shopify app affiliate program, PartnerDock is designed for the hard parts that matter in production: accurate tracking, reconciliation, payout workflows, predictable costs, and hands-on migration support for teams leaving legacy affiliate tools.