Skip to main content
Add webhook_url when creating an enhancement to receive status events. Webhooks are recommended for production catalog imports because they reduce polling and let you update each product as soon as its image is ready. Webhook URLs must be public HTTPS URLs. Localhost, private networks, internal DNS, unsupported protocols, and redirects to private networks are rejected.

Configure a webhook

{
  "preset": "marketplace_clean_catalog",
  "webhook_url": "https://client.example/webhooks/aigenstudio",
  "images": [
    {
      "external_id": "catalog-product-001",
      "source_url": "https://client.example/images/product-001.jpg"
    }
  ]
}

Delivery headers

Each webhook request includes:
X-Aigen-Signature
X-Aigen-Timestamp
X-Aigen-Event-Id
Signature format:
X-Aigen-Signature: v1=<hex_hmac_sha256>

Verify signatures

Verification parameters:
ParameterValue
AlgorithmHMAC SHA-256
Signed payloadtimestamp.event_id.raw_body
Signing secretsha256(<your full API key>)
Use the exact raw request body bytes. Do not verify against a parsed and re-serialized JSON object. Example in Node.js:
import { createHash, createHmac, timingSafeEqual } from "node:crypto";

const timestamp = req.headers["x-aigen-timestamp"];
const eventId = req.headers["x-aigen-event-id"];
const signature = req.headers["x-aigen-signature"]; // v1=<hex>
const rawBody = requestBodyAsReceived;

if (!process.env.AIGENSTUDIO_API_KEY) {
  throw new Error("Missing AIGENSTUDIO_API_KEY");
}

const signingSecret = createHash("sha256")
  .update(process.env.AIGENSTUDIO_API_KEY)
  .digest("hex");

const expected = `v1=${createHmac("sha256", signingSecret)
  .update(`${timestamp}.${eventId}.${rawBody}`)
  .digest("hex")}`;

const signatureBuffer = Buffer.from(signature ?? "", "utf8");
const expectedBuffer = Buffer.from(expected, "utf8");

const valid =
  typeof signature === "string" &&
  signatureBuffer.length === expectedBuffer.length &&
  timingSafeEqual(signatureBuffer, expectedBuffer);
Reject events when:
  • the signature is missing or invalid;
  • the timestamp is outside your allowed clock skew window;
  • the event id has already been processed.

Event types

product_image_enhancement.item.completed
product_image_enhancement.item.failed
product_image_enhancement.completed
product_image_enhancement.failed
product_image_enhancement.partially_completed
Item events are best for updating individual products. Enhancement events are best for marking a catalog batch as finished.

Example item event

{
  "id": "9ffbd85e-7560-42d4-8e64-8bb8d12d24da",
  "type": "product_image_enhancement.item.completed",
  "created_at": "2026-06-22T00:00:00.000Z",
  "data": {
    "enhancement": {
      "id": "f693e677-51e0-4ebe-80a0-ad06acbc4443",
      "status": "processing",
      "total_items": 1,
      "completed_items": 1,
      "failed_items": 0,
      "credits_reserved": 5,
      "credits_used": 5,
      "sandbox": false
    },
    "item": {
      "id": "b8e766bf-38e6-4384-9f7e-1c4ff76670be",
      "external_id": "catalog-product-001",
      "status": "completed",
      "result_url": "https://.../image.png",
      "thumbnail_url": "https://.../thumbnail.png",
      "error_code": null,
      "error_message": null
    }
  }
}
Webhook payloads do not include API keys or secrets.

Retry schedule

AI Gen Studio retries failed webhook deliveries on this schedule:
1 minute
5 minutes
15 minutes
1 hour
6 hours
AI Gen Studio stops retrying after any HTTP 2xx response. Any non-2xx response or timeout schedules another attempt until the retry limit is reached.

Receiver requirements

  • Respond with 2xx only after the event is safely accepted.
  • Process events idempotently by X-Aigen-Event-Id.
  • Do not depend on event order.
  • Poll the enhancement status endpoint if you need the final source of truth.
  • Store external_id so results can be mapped back to your products.