PaperTiger.WebhookDelivery (PaperTiger v0.7.0)

View Source

Manages webhook event delivery to registered endpoints.

This GenServer delivers webhook events asynchronously with:

  • Stripe-compatible HMAC SHA256 signing of payloads
  • Exponential backoff retry logic (max 5 attempts)
  • Detailed delivery attempt tracking in Event object
  • Concurrent delivery to multiple endpoints

Architecture

  • Main delivery function: deliver_event/2 - Queues a delivery task
  • Signing: sign_payload/2 - Creates Stripe-compatible HMAC SHA256 signature
  • HTTP client: Uses Req library for reliable, timeout-aware requests
  • Retry strategy: Exponential backoff (1s, 2s, 4s, 8s, 16s)
  • Tracking: Stores delivery attempts in Event object via Store.Events

Stripe Signature Format

The Stripe-Signature header follows Stripe's format:

Stripe-Signature: t={timestamp},v1={signature}

Where:

  • t = Unix timestamp when webhook was created
  • v1 = HMAC SHA256 signature of "{timestamp}.{payload}" using webhook secret

Examples

# Deliver an event to all subscribed webhook endpoints
{:ok, _result} = PaperTiger.WebhookDelivery.deliver_event("evt_123", "we_456")

# Manually create a signature for testing
signature = PaperTiger.WebhookDelivery.sign_payload("body", "secret")

Summary

Functions

Returns a specification to start this module under a supervisor.

Delivers a webhook event to a specific endpoint.

Signs a payload using HMAC SHA256 (Stripe-compatible).

Starts the WebhookDelivery GenServer.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

deliver_event(event_id, webhook_endpoint_id)

@spec deliver_event(String.t(), String.t()) :: {:ok, reference()} | {:error, term()}

Delivers a webhook event to a specific endpoint.

This function queues the delivery asynchronously. Multiple calls with different webhook_endpoint_ids deliver to all endpoints.

Parameters

  • event_id - ID of the event to deliver (e.g., "evt_123")
  • webhook_endpoint_id - ID of the webhook endpoint (e.g., "we_456")

Returns

  • {:ok, reference} - Delivery queued successfully
  • {:error, reason} - Delivery could not be queued

Examples

{:ok, _ref} = PaperTiger.WebhookDelivery.deliver_event("evt_123", "we_456")

sign_payload(payload, secret)

@spec sign_payload(String.t(), String.t()) :: String.t()

Signs a payload using HMAC SHA256 (Stripe-compatible).

Creates the signature component for the Stripe-Signature header. The actual signature is computed on "{timestamp}.{payload}".

Parameters

  • payload - JSON string (or any string data) to sign
  • secret - Webhook secret from the webhook endpoint

Returns

String containing the hex-encoded HMAC SHA256 signature.

Examples

signature = PaperTiger.WebhookDelivery.sign_payload(payload, "whsec_...")
# Returns: "abcd1234..."

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts the WebhookDelivery GenServer.