SpareSpare Docs
GuidesAPI Reference

Webhooks

Event delivery, retries, and verifying webhook signatures.

Webhooks push real-time notifications when consents, payments, or mandates change state. Use them in production instead of polling, they reduce latency, API load, and missed edge cases.

In this guide

  • How outbound webhooks are delivered to your server
  • Which events are available today
  • Signature verification and idempotent handling
  • How webhooks fit with polling and Spare Link

Why webhooks matter

After payer authorization, settlement can take seconds or minutes. Polling in a tight loop wastes API quota and still misses events if your server restarts.

Webhooks let Spare notify you when:

  • Consent moves from Pending to Authorised or Rejected
  • Payment settlement completes or fails
  • Mandate transactions execute

Your handler should enqueue work and re-fetch the resource, webhook bodies are notifications, not the sole source of truth.

Delivery model

Transport

  • HTTPS POST to URLs you register in the Spare dashboard
  • JSON body with event type, resource IDs, and timestamps
  • HMAC signature header for verification (algorithm in your dashboard docs)

Retries

If your endpoint returns non-2xx or times out, Spare retries with exponential backoff. Design handlers to be idempotent, the same event may arrive more than once.

Event catalog

EventWhen fired
consent.createdConsent record created
consent.authorizedPayer approved at bank
consent.revokedConsent cancelled

More events such as consent.rejected and consent.expired may be added, so handle unknown event types gracefully.

Payment events

EventWhen fired
payment.createdPayment record created after execution starts

Settlement completion events may be published as the platform evolves, always confirm final state via GET /payments/{id}.

For Link-initiated payments, status updates may follow:

INITIATED β†’ EXECUTED β†’ SETTLED (or FAILED / REJECTED)

Wire these into the same handler pattern as standard payment events.

app.post("/webhooks/spare", async (req, res) => {
  // 1. Verify signature
  if (!verifySpareSignature(req)) {
    return res.status(401).send("invalid signature");
  }

  const event = req.body;

  // 2. Acknowledge quickly
  res.status(200).send("ok");

  // 3. Enqueue async processing
  await queue.add("spare-event", event);
});

async function processEvent(event: SpareEvent) {
  // 4. Re-fetch authoritative state
  const consent = await client.paymentConsents.get({
    consentId: event.data.consentId,
  });

  // 5. Idempotent business logic
  if (consent.data.status === "Authorised") {
    await fulfillOrder(event.data.paymentRequestId);
  }
}
from flask import Flask, request, abort
import json

app = Flask(__name__)

@app.route("/webhooks/spare", methods=["POST"])
def handle_webhook():
    # 1. Verify signature
    if not verify_spare_signature(request):
        abort(401, "invalid signature")

    event = request.get_json()
    event_type = event.get("type")

    if event_type == "payment.confirmed":
        # fulfill order
        pass
    elif event_type == "consent.authorised":
        # record authorization
        pass

    return "", 200

Rules of thumb

  1. Verify the signature before parsing untrusted payloads
  2. Respond 200 within a few seconds, do heavy work asynchronously
  3. Re-fetch resources via API before irreversible actions
  4. Deduplicate using event ID or (type, resourceId, timestamp) keys
  5. Log raw events for audit, redact PII in application logs

Webhooks vs polling

WebhooksPolling
LatencyLow (push)Depends on interval
API loadMinimalGrows with traffic
ComplexityEndpoint + verificationSimple loops
Best forProductionSandbox, debugging

Use polling as a fallback if a webhook is delayed, not as the primary production strategy.

Registering endpoints

Configure webhook URLs in your Spare merchant dashboard (sandbox and production separately). Requirements:

  • Public HTTPS URL
  • Valid TLS certificate
  • No authentication via query string secrets alone, use signature verification

Testing in sandbox

  1. Register a tunnel URL (e.g. ngrok) pointing to your local handler
  2. Complete a Quickstart payment
  3. Confirm consent.authorized arrives
  4. Verify your handler re-fetches consent before updating state

Key takeaways

  • Webhooks notify; the API GET confirms, never fulfill solely on webhook payload.
  • Respond fast, process async, verify signatures, deduplicate events.
  • Register separate sandbox and production endpoints.

On this page