Skip to content
Skillv1.0.0

adobe-webhooks-events

Implement Adobe I/O Events webhook registration, RSA-SHA256 signature verification, challenge handshake, and event-driven architectures with Creative Cloud, Experience Platform, and Firefly Services e

by jeremylongshore(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from jeremylongshore/tons-of-skills-marketplace (plugins/saas-packs/adobe-pack/skills/adobe-webhooks-events/SKILL.md). Install upstream with npx skills add jeremylongshore/tons-of-skills-marketplace --skill adobe-webhooks-events. Copyright stays with the author (MIT).

Adobe Webhooks & Events

Overview

Implement Adobe I/O Events webhook endpoints with proper challenge-response handshake, RSA-SHA256 digital signature verification, and event routing for Creative Cloud Libraries, Experience Platform, and Firefly Services events.

Prerequisites

  • Adobe Developer Console project with Events API enabled
  • HTTPS endpoint accessible from the internet
  • @adobe/aio-lib-events installed (optional, for SDK approach)
  • Understanding of Adobe I/O Events architecture

Instructions

Step 1: Register Webhook via Adobe I/O Events API

// Register a webhook endpoint programmatically
import { getAccessToken } from '../adobe/client';

interface EventRegistration {
  name: string;
  description: string;
  webhookUrl: string;
  eventsOfInterest: Array<{
    provider_id: string;   // Event provider (e.g., Creative Cloud)
    event_code: string;    // Specific event type
  }>;
  deliveryType: 'webhook' | 'webhook_batch';
}

export async function registerWebhook(reg: EventRegistration): Promise<any> {
  const token = await getAccessToken();

  const response = await fetch(
    `https://api.adobe.io/events/${process.env.ADOBE_IMS_ORG_ID}/integrations/${process.env.ADOBE_INTEGRATION_ID}/registrations`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'x-api-key': process.env.ADOBE_CLIENT_ID!,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        client_id: process.env.ADOBE_CLIENT_ID,
        name: reg.name,
        description: reg.description,
        webhook_url: reg.webhookUrl,
        events_of_interest: reg.eventsOfInterest,
        delivery_type: reg.deliveryType || 'webhook',
      }),
    }
  );

  if (!response.ok) throw new Error(`Registration failed: ${await response.text()}`);
  return response.json();
}

// Example: Register for Creative Cloud Library events
await registerWebhook({
  name: 'CC Library Updates',
  description: 'Track Creative Cloud Library changes',
  webhookUrl: 'https://api.yourapp.com/webhooks/adobe',
  eventsOfInterest: [
    { provider_id: 'ccstorage', event_code: 'library_create' },
    { provider_id: 'ccstorage', event_code: 'library_update' },
    { provider_id: 'ccstorage', event_code: 'library_delete' },
  ],
  deliveryType: 'webhook',
});

Step 2: Implement Challenge-Response Handshake

When registering a webhook, Adobe sends a GET request with a challenge query parameter. Your endpoint must respond with the challenge value:

import express from 'express';
const app = express();

app.get('/webhooks/adobe', (req, res) => {
  // Adobe challenge verification during registration
  const challenge = req.query.challenge as string;
  if (challenge) {
    console.log('Adobe webhook challenge received');
    return res.status(200).json({ challenge });
  }
  res.status(400).json({ error: 'Missing challenge parameter' });
});

Step 3: Verify RSA-SHA256 Digital Signatures

Adobe I/O Events uses RSA-SHA256 (not HMAC). Public keys are served from static.adobeioevents.com:

import crypto from 'crypto';

const publicKeyCache = new Map<string, string>();

async function fetchPublicKey(keyPath: string): Promise<string> {
  if (publicKeyCache.has(keyPath)) return publicKeyCache.get(keyPath)!;
  const res = await fetch(`https://static.adobeioevents.com${keyPath}`);
  if (!res.ok) throw new Error(`Failed to fetch Adobe public key: ${res.status}`);
  const key = await res.text();
  publicKeyCache.set(keyPath, key);
  return key;
}

async function verifyAdobeSignature(rawBody: Buffer, headers: Record<string, string>): Promise<boolean> {
  for (const idx of ['1', '2']) {
    const sig = headers[`x-adobe-digital-signature-${idx}`];
    const keyPath = headers[`x-adobe-public-key${idx}-path`];
    if (!sig || !keyPath) continue;

    try {
      const publicKey = await fetchPublicKey(keyPath);
      const verifier = crypto.createVerify('RSA-SHA256');
      verifier.update(rawBody);
      if (verifier.verify(publicKey, sig, 'base64')) return true;
    } catch (err) {
      console.warn(`Adobe signature-${idx} verification error:`, err);
    }
  }
  return false;
}

Step 4: Event Handler with Routing

// POST handler for incoming events
app.post('/webhooks/adobe',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    // Verify signature
    if (!await verifyAdobeSignature(req.body, req.headers as any)) {
      console.error('Invalid Adobe webhook signature');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    const event = JSON.parse(req.body.toString());

    // Route by event type
    try {
      await routeAdobeEvent(event);
      res.status(200).json({ received: true });
    } catch (error: any) {
      console.error('Event processing failed:', error);
      res.status(500).json({ error: error.message });
    }
  }
);

// Event type definitions
type AdobeEventType =
  | 'library_create'
  | 'library_update'
  | 'library_delete'
  | 'asset_created'
  | 'asset_updated';

interface AdobeEvent {
  event_id: string;
  event: {
    type: AdobeEventType;
    activitystreams?: any;
    xdmEntity?: any;
  };
  recipient_client_id: string;
}

const eventHandlers: Partial<Record<AdobeEventType, (event: AdobeEvent) => Promise<void>>> = {
  library_create: async (event) => {
    console.log('New CC Library created:', event.event_id);
    // Sync library metadata to your database
  },
  library_update: async (event) => {
    console.log('CC Library updated:', event.event_id);
    // Refresh cached library data
  },
  library_delete: async (event) => {
    console.log('CC Library deleted:', event.event_id);
    // Remove from local cache/database
  },
};

async function routeAdobeEvent(event: AdobeEvent): Promise<void> {
  const handler = eventHandlers[event.event.type];
  if (handler) {
    await handler(event);
  } else {
    console.log(`Unhandled Adobe event type: ${event.event.type}`);
  }
}

Step 5: Idempotency (Prevent Duplicate Processing)

import { Redis } from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);

async function processEventIdempotently(event: AdobeEvent): Promise<boolean> {
  const key = `adobe:event:${event.event_id}`;
  // SET NX with 7-day TTL — returns null if key already exists
  const result = await redis.set(key, '1', 'EX', 86400 * 7, 'NX');

  if (!result) {
    console.log(`Duplicate Adobe event skipped: ${event.event_id}`);
    return false; // Already processed
  }

  await routeAdobeEvent(event);
  return true;
}

Output

  • Webhook registered with Adobe I/O Events
  • Challenge-response handshake handler for registration
  • RSA-SHA256 signature verification with key caching
  • Event routing by type with handler pattern
  • Idempotency via Redis to prevent duplicate processing

Error Handling

Issue Cause Solution
Challenge response 400 Missing JSON content-type Return { challenge } as JSON
Signature always invalid Not using raw body Use express.raw() before parsing
Events not arriving Registration failed Check I/O Events dashboard for status
Duplicate events No idempotency Track event_id in Redis/DB
Public key fetch fails Network/firewall Whitelist static.adobeioevents.com

Examples

Start with the smallest applicable command or code example already provided in this guide, using a non-production Adobe environment and credentials. Confirm the documented response or validation result before applying the pattern to production.

Resources

Next Steps

For performance optimization, see adobe-performance-tuning.

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/jeremylongshore-tons-of-skills-marketplace-adobe-webhook-041f33/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

jeremylongshore-tons-of-skills-marketplace-adobe-webhook-041f33.ocm.jsonjson
{
  "ocm": "1",
  "id": "jeremylongshore-tons-of-skills-marketplace-adobe-webhook-041f33",
  "kind": "skill",
  "name": "adobe-webhooks-events",
  "description": "Implement Adobe I/O Events webhook registration, RSA-SHA256 signature verification, challenge handshake, and event-driven architectures with Creative Cloud, Experience Platform, and Firefly Services events. Trigger with phrases like \"adobe webhook\", \"adobe events\", \"adobe I/O events\", \"adobe event registration\", \"adobe notifications\".",
  "publisher": "jeremylongshore",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "creative"
    ],
    "tags": [
      "skill-md",
      "saas",
      "design",
      "adobe",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Implement Adobe I/O Events webhook registration, RSA-SHA256 signature verification, challenge handshake, and event-driven architectures with Creative Cloud, Experience Platform, and Firefly Services events. Trigger with phrases like \"adobe webhook\", \"adobe events\", \"adobe I/O events\", \"adobe event registration\", \"adobe notifications\"."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/jeremylongshore/tons-of-skills-marketplace",
      "path": "plugins/saas-packs/adobe-pack/skills/adobe-webhooks-events/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/jeremylongshore/tons-of-skills-marketplace/blob/HEAD/plugins/saas-packs/adobe-pack/skills/adobe-webhooks-events/SKILL.md",
      "key": "jeremylongshore/tons-of-skills-marketplace/plugins/saas-packs/adobe-pack/skills/adobe-webhooks-events/SKILL.md"
    },
    "compatibility": "Designed for Claude Code",
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit,",
      "Bash(curl:*)"
    ],
    "license": "MIT"
  },
  "instructions": "# Adobe Webhooks & Events\n\n## Overview\n\nImplement Adobe I/O Events webhook endpoints with proper challenge-response handshake, RSA-SHA256 digital signature verification, and event routing for Creative Cloud Libraries, Experience Platform, and Firefly Services events.\n\n## Prerequisites\n\n- Adobe Developer Console project with Events API enabled\n- HTTPS endpoint accessible from the internet\n- `@adobe/aio-lib-events` installed (optional, for SDK approach)\n- Understanding of Adobe I/O Events architecture\n\n## Instructions\n\n### Step 1: Register Webhook via Adobe I/O Events API\n\n```typescript\n// Regis",
  "cost": {
    "context_tokens": 2025
  }
}

Fetch it by URL: GET /api/v1/registry/jeremylongshore-tons-of-skills-marketplace-adobe-webhook-041f33/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.

adobe-webhooks-events - Skill - OpenSmartRoute