Skip to main content

GitHub Issue: Implement Creative Approval Webhook System

Repository: activation-api Labels: enhancement, webhooks, creative-sync, integration

Title

Implement bidirectional webhook system for creative approval notifications

Problem Statement

When syncing creatives to sales agents (e.g., Wonderstruck), the approval process is asynchronous and potentially manual. Currently, we successfully sync creatives with status: "pending", but we have no automated way to know when they’re approved or rejected. Current flow:
  1. ✅ Sync creative to sales agent → returns status: "pending"
  2. ❌ Wait for manual review (could take minutes, hours, or days)
  3. ❌ No notification when status changes
  4. ❌ Must manually poll to check status
This results in delayed response to rejections and inefficient status checking.

Proposed Solution

Implement a bidirectional webhook system:

1. Inbound Webhooks (Sales Agent → Us)

Sales agents POST status updates to our endpoint when creatives are approved/rejected.

2. Outbound Webhooks (Us → Customer)

We forward these notifications to customer-configured webhook endpoints.

3. Polling Fallback

For sales agents that don’t support webhooks, implement periodic polling.

Architecture Overview

┌─────────────┐         ┌──────────────┐         ┌─────────────┐         ┌──────────────┐
│   Sales     │         │  Activation  │         │   Sales     │         │   Customer   │
│   Agent     │────1───>│     API      │────2───>│   Agent     │────3───>│   Webhook    │
│(Wonderstruck│         │              │         │(Wonderstruck│         │   Endpoint   │
└─────────────┘         └──────────────┘         └─────────────┘         └──────────────┘
     Manual                    |                                                 ▲
     Review                    |                                                 │
       ↓                       └──────────────4──────────────────────────────────┘
   Approve/
   Reject
Flow:
  1. We sync creative to sales agent, register webhook callback
  2. Sales agent reviews creative (manual process)
  3. Sales agent POSTs status to our webhook endpoint
  4. We create internal notification
  5. We POST notification to customer’s webhook URL

Implementation Tasks

Phase 1: Inbound Webhook Receiver (High Priority)

Goal: Accept status updates from sales agents
  • Create Express route: POST /webhooks/creative-status/:customerId/:creativeId
  • Implement HMAC signature verification for security
  • Update creative_sync_status table on status changes
  • Create internal Notification records with types:
    • CREATIVE_APPROVED
    • CREATIVE_REJECTED
    • CREATIVE_CHANGES_REQUESTED
  • Add rate limiting and IP validation
  • Add audit logging to webhook_deliveries table
  • Write unit tests for webhook receiver
  • Write integration tests with mock sales agent callbacks
Files to create:
  • src/routes/webhooks/creative-status.ts - Express route handler
  • src/services/webhook-receiver-service.ts - Business logic
  • src/__tests__/routes/webhooks/creative-status.test.ts - Tests

Phase 2: Webhook Subscription with Sales Agents

Goal: Register our callback URL when syncing creatives
  • Update ADCPCreativeSyncService to register webhook during sync
  • Add webhook_url parameter to sync requests (if ADCP supports it)
  • Store webhook registration details in creative_sync_status table
  • Add fields: webhook_registered, webhook_url, webhook_secret
  • Generate unique webhook secrets per sales agent
  • Handle webhook registration failures gracefully
Files to modify:
  • src/services/adcp-creative-sync-service.ts - Add webhook registration
  • src/types/creative.ts - Add webhook fields to sync status

Phase 3: Customer Webhook Delivery

Goal: Forward notifications to customer endpoints
  • Implement webhook delivery service with retries
  • Add HMAC signature generation for customer webhooks
  • Implement retry policy with exponential backoff
  • Auto-pause webhooks after consecutive failures
  • Add webhook health tracking
  • Create webhook delivery audit log
  • Write tests for delivery service
Files to create:
  • src/services/webhook-delivery-service.ts - Delivery logic
  • src/__tests__/services/webhook-delivery-service.test.ts - Tests

Phase 4: Polling Fallback

Goal: Support sales agents without webhook capability
  • Implement periodic polling job (cron every 5 minutes)
  • Add get_creative_status or equivalent tool call
  • Track which sales agents support webhooks vs polling
  • Update status and create notifications on detected changes
  • Add configuration to enable/disable per sales agent
Files to create:
  • src/jobs/creative-status-poller.ts - Polling job
  • src/services/creative-status-polling-service.ts - Polling logic

Phase 5: Monitoring & Reliability

Goal: Production-ready webhook system
  • Add webhook delivery metrics (success rate, latency)
  • Implement auto-pause for repeatedly failing webhooks
  • Add customer notification preferences (email fallback)
  • Create admin dashboard for webhook health
  • Add alerting for webhook delivery failures
  • Document webhook setup for customers

Database Schema Updates

Extend creative_sync_status table

ALTER TABLE creative_sync_status ADD COLUMN IF NOT EXISTS
  -- Webhook tracking
  webhook_registered BOOL DEFAULT FALSE,
  webhook_url STRING,
  webhook_secret STRING,  -- Encrypted
  webhook_last_attempt TIMESTAMP,
  webhook_failure_count INT64 DEFAULT 0;

Create webhook_deliveries table (if not exists)

CREATE TABLE IF NOT EXISTS webhook_deliveries (
  id STRING NOT NULL,
  subscription_id STRING NOT NULL,
  event_id STRING NOT NULL,

  -- Delivery details
  url STRING NOT NULL,
  event_type STRING NOT NULL,
  payload STRING NOT NULL,  -- JSON

  -- Result
  success BOOL NOT NULL,
  status_code INT64,
  response_body STRING,
  error_message STRING,
  retry_attempt INT64 DEFAULT 0,

  -- Timing
  delivered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
  duration_ms INT64,

  PRIMARY KEY (id)
);

API Design

Inbound Webhook Endpoint

POST /webhooks/creative-status/:customerId/:creativeId
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...

{
  "creative_id": "wonderstruck_creative_456",
  "activation_creative_id": "creative_k0i02ddq5b",
  "status": "approved",  // approved | rejected | changes_requested
  "message": "Creative approved for display inventory",
  "reviewer": "john@wonderstruck.com",
  "reviewed_at": "2025-10-01T15:30:00Z",
  "platform_notes": "Looks great, approved for all formats"
}

Outbound Webhook to Customer

POST https://customer-system.com/scope3/webhooks
Authorization: Bearer customer-api-key
X-Scope3-Signature: sha256=...
X-Scope3-Event-Type: creative.approved
X-Scope3-Event-ID: evt_abc123

{
  "event_id": "evt_abc123",
  "event_type": "creative.approved",
  "timestamp": "2025-10-01T15:30:00Z",
  "data": {
    "creative_id": "creative_k0i02ddq5b",
    "creative_name": "Wonderstruck Mushroom 300x250",
    "brand_agent_id": "48",
    "sales_agent_id": "principal_8ac9e391",
    "sales_agent_name": "Wonderstruck",
    "approval_message": "Creative approved for display inventory",
    "approved_at": "2025-10-01T15:30:00Z",
    "platform_creative_id": "wonderstruck_creative_456"
  }
}

Security Considerations

Inbound (Sales Agent → Us)

  1. HMAC Signature Verification
    const computedSignature = crypto
      .createHmac("sha256", webhookSecret)
      .update(JSON.stringify(req.body))
      .digest("hex");
    
    if (
      !crypto.timingSafeEqual(
        Buffer.from(computedSignature),
        Buffer.from(receivedSignature),
      )
    ) {
      return res.status(401).json({ error: "Invalid signature" });
    }
    
  2. Rate Limiting: Max 100 requests per minute per IP
  3. IP Allowlisting: Optionally restrict to known sales agent IPs
  4. Audit Logging: Log all webhook deliveries for forensics

Outbound (Us → Customer)

  1. HMAC Signature Generation
  2. Encrypted Credentials: Store customer auth tokens encrypted in BigQuery
  3. Secret Rotation: Provide endpoint for customers to rotate secrets
  4. Retry Limits: Auto-pause after 3 consecutive failures

Testing Strategy

Unit Tests

  • HMAC signature verification
  • Webhook payload validation
  • Retry logic
  • Status update handling

Integration Tests

  • End-to-end creative sync → approval → notification flow
  • Webhook delivery with retries and failures
  • Polling fallback behavior

Manual Testing

  1. Sync creative to Wonderstruck
  2. Manually trigger webhook callback (simulate approval)
  3. Verify notification created
  4. Verify customer webhook called
  5. Test failure scenarios (invalid signature, network errors)

Success Metrics

  • Latency: Time from approval → customer notification < 5 seconds
  • Reliability: Webhook delivery success rate > 99%
  • Adoption: 80% of customers using webhooks within 3 months
  • Cost: Reduced polling API calls by 90%

Documentation Needed

  • Customer-facing webhook setup guide
  • Webhook event types reference
  • Troubleshooting guide for webhook failures
  • Security best practices
  • Example webhook handlers (Node.js, Python, Ruby)
  • Detailed architecture: docs/creative-approval-webhooks.md
  • Notification types: src/types/notifications.ts
  • Existing webhook types: src/types/webhooks.ts

Dependencies

  • ✅ Creative sync working with auth (@adcp/client 0.2.4)
  • ✅ Real GCS asset hosting
  • ✅ Wonderstruck MCP integration
  • ⏳ ADCP webhook specification (need to verify if sync_creatives supports webhook_url param)

Open Questions

  1. Does ADCP spec support webhook registration in sync_creatives?
    • Need to check if we can pass webhook_url parameter
    • Alternative: Separate subscribe_creative_updates tool call
  2. What’s Wonderstruck’s webhook format?
    • Need to coordinate with Wonderstruck team on payload format
    • Need webhook secret sharing mechanism
  3. Polling frequency?
    • Start with 5 minutes, optimize based on actual approval times
    • Consider exponential backoff for long-pending creatives

Implementation Timeline

  • Week 1: Phase 1 (Inbound webhook receiver)
  • Week 2: Phase 2 (Sales agent subscription) + Phase 3 (Customer delivery)
  • Week 3: Phase 4 (Polling fallback) + Testing
  • Week 4: Phase 5 (Monitoring) + Documentation + Beta rollout

Risk Mitigation

  • Sales agent compatibility: Start with polling fallback, add webhooks incrementally
  • Customer adoption: Provide both webhooks and polling/list endpoints
  • Scaling: Rate limit inbound webhooks, queue outbound deliveries
  • Reliability: Comprehensive retry logic and auto-pause on failures

Instructions for GitHub

  1. Copy this to a new GitHub issue in the activation-api repository
  2. Add labels: enhancement, webhooks, creative-sync, integration, good-first-issue (for Phase 1 tasks)
  3. Link to related issues/PRs:
    • PR that fixed @adcp/client auth (if separate repo)
    • Any existing webhook implementation PRs
  4. Assign to appropriate milestone
  5. Tag relevant team members for review