Shopify product video AI API with products/create webhooks

Answer Shopify's products/create webhook within five seconds, run a Sume Format from a queue, then upload the MP4 to Shopify with a staged upload.

6 min readSume
All posts

To make an AI video for each new Shopify product, subscribe to the products/create webhook, verify it and answer 200 within Shopify's five seconds, then start a Sume Format run from a queue with the product photos as attachments. When Sume's signed webhook returns primary_output_url, upload that MP4 to Shopify with stagedUploadsCreate and fileCreate, then attach the file to the product once it is READY.

Sume has no Shopify app; this is your own app server talking to Shopify's Admin API and to Sume over HTTPS. The Sume facts come from Create a run and Runs and results, and the Shopify facts from shopify.dev, all read on 2026-09-27. Which catalog Formats suit product video is covered in Ready-made Formats for product video.

How fast must my app answer Shopify's webhook?

Shopify allows a one-second connection timeout and five seconds for the whole request, and any response outside the 200 range, 3XX included, is an error. After 8 consecutive failures it deletes a subscription configured through the Admin API. Shopify's own advice for staying inside five seconds is a queue, so the receiver does three short things:

  • Verify X-Shopify-Hmac-SHA256, a base64 HMAC-SHA256 of the raw body keyed with your app's client secret.
  • Skip any X-Shopify-Webhook-Id you have already stored, because Shopify may deliver the same webhook more than once.
  • Enqueue the product and answer 200. Call Sume from the queue: a Format run's create fetches and copies every attachment before it answers.

How do I start the Sume run for a new product?

The worker calls a catalog Format at sume/{slug} with a formats:write key. Put product text such as the title in input, not instruction; Sume's docs name input as the place for product copy. Store data.id next to the product id, because a value you send cannot come back in output unless the run repeats it.

  • attachments takes up to 30 images, 30 MB each and 500 MB per run, as JPEG, PNG, WebP, GIF, or AVIF. Sume fetches them at create time, so each URL must be reachable without auth; an unreachable one fails the create with 502 attachment_fetch_failed and details.index.
  • Derive Idempotency-Key from the product id and a version you bump for a deliberate re-render. The same key and body returns 200 with the original receipt and idempotency_hit: true, with no second charge.
  • generation_spend_cap_usd caps one product's run at up to $500; 0 is rejected.
  • Shopify's sample products/create payload has an empty images array. A product with no photos has nothing to attach yet.
// Queue worker. product = { id, title, imageUrls } from your queue.
async function startProductVideo(product) {
  const res = await fetch("https://api.sume.com/v1/formats/sume/sume-product-commercial/runs", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + process.env.SUME_API_KEY,
      "Content-Type": "application/json",
      "Idempotency-Key": "shopify-product-" + product.id + "-v1",
    },
    body: JSON.stringify({
      instruction: "Make a product video from the attached photos.",
      input: { product_title: product.title },
      attachments: product.imageUrls.slice(0, 30).map((url) => ({ type: "input_image", image_url: url })),
      generation_spend_cap_usd: 20,
      communication: { webhook_url: "https://app.example.com/hooks/sume" },
    }),
  });
  const body = await res.json();
  if (!res.ok) throw new Error(body.error.code); // e.g. attachment_fetch_failed
  await saveRun(body.data.id, product.id);
}

How do Shopify's webhook and Sume's webhook differ?

Your app receives two signed webhooks with two schemes and two secrets, so give each its own route and verifier. During a secret rotation, Sume's header carries two comma-separated sume-v1= entries for 24 hours; accept either, as verifyWebhook in @sume-com/sdk does.

From Shopify's "Verify webhook deliveries" page and Sume's Run webhooks page, read 2026-09-27.
PropertyShopify `products/create`Sume `format.run.terminal`
Signature headerX-Shopify-Hmac-SHA256, base64x-sume-webhook-signature: sume-v1=<hex>
Signed bytesThe raw body<timestamp>.<raw_body>
SecretApp client secretWorkspace webhook signing secret
Answer within1 s to connect, 5 s in total10 s per attempt
Retries8 times over 4 hoursUp to 10 attempts
Dedupe onX-Shopify-Webhook-Idrequest_id
A 3xx answerAn errorA failed attempt, never followed

How do I attach the finished video to the product?

Sume POSTs one format.run.terminal event when the run completes or fails. On status: "OK", payload.primary_output_url is a durable media.sume.com URL, and payload.artifacts[] lists each file with content_type, size_bytes, and duration_ms; check those against Shopify's video limits. Don't pass the Sume URL straight to fileCreate: Shopify's `FileCreateInput` takes an external URL only for images, generic files, or external (YouTube or Vimeo) videos, and a Shopify-hosted video needs a staged upload URL. Download the MP4 and upload it in steps:

  • Request a target with stagedUploadsCreate (mutation below). Shopify requires fileSize for videos; send the artifact's size_bytes.
  • POST the MP4 to the returned url as multipart form data, with the returned parameters.
  • Call `fileCreate` with the resourceUrl as originalSource and contentType: VIDEO.
  • Files are processed asynchronously. Poll fileStatus until it is READY (or FAILED), then attach the file with productSet, productCreate, or productUpdate, referencing it by ID.
  • A failed run arrives with status: "ERROR". If the receipt was over 1 MiB, payload is null and error.result_url says where to fetch it.
mutation {
  stagedUploadsCreate(input: [{
    filename: "product-video.mp4",
    mimeType: "video/mp4",
    resource: VIDEO,
    fileSize: "899765"
  }]) {
    stagedTargets { url resourceUrl parameters { name value } }
    userErrors { field message }
  }
}

What are the limits?

Shopify limits the file you import; Sume's rules shape the run that makes it.

  • Shopify videos: MP4, MOV, or WEBM, up to 1 GB, 10 minutes, and 3840x2160. Apps can create up to 1,000 videos per store per week.
  • A Format run over the API is unattended. Approvals a recipe would ask a person for are pre-granted, and a run that cannot finish comes back failed.
  • Shopify's media guide assumes the read_products, write_products, and write_files access scopes.
  • Format run media URLs are public to anyone holding them. Proxy or copy them if you need per-customer access control.

Sources

Related posts

More in Integrations

All Integrations posts

Written by Sume