X Enterprises
fastify-ximagepipeline

GET /image-pipeline/status/:jobId

Poll the processing status of an upload job — returns variant URLs, blurhash, and dimensions when COMPLETE.

GET /image-pipeline/status/:jobId

Poll the status of an image processing job. Returns different HTTP codes and payloads depending on the current job state.

Request

Method: GET
Path: /image-pipeline/status/:jobId

ParamTypeRequiredDescription
jobIdstringYesJob ID returned by the upload endpoint

Response by Status

Job StatusHTTPExtra Fields
PENDING202
PROCESSING202
COMPLETE200media object
REJECTED400reason, moderationDetails
FAILED500error, attempts

COMPLETE response (200)

{
  "jobId": "clx1234abcd",
  "status": "COMPLETE",
  "media": {
    "id": "med_abc",
    "sourceType": "avatar",
    "sourceId": "user-abc123",
    "urls": {
      "xs": "https://cdn.example.com/media/avatar/user-abc123/med_abc/xs.webp",
      "sm": "https://cdn.example.com/media/avatar/user-abc123/med_abc/sm.webp"
    },
    "originalUrl": "https://cdn.example.com/originals/avatar/user-abc123/med_abc/original.jpg",
    "width": 1200,
    "height": 800,
    "aspectRatio": "3:2",
    "blurhash": "LEHV6nWB2yk8pyo0adR*.7kCMdnj"
  }
}

REJECTED response (400)

{
  "jobId": "clx1234abcd",
  "status": "REJECTED",
  "reason": "Content moderation failed",
  "moderationDetails": { "flags": ["explicit"], "confidence": 0.97 }
}

FAILED response (500)

{
  "jobId": "clx1234abcd",
  "status": "FAILED",
  "error": "Sharp processing error",
  "attempts": 3
}

Examples

Poll until complete (client-side)

async function waitForProcessing(jobId, maxPolls = 30) {
  for (let i = 0; i < maxPolls; i++) {
    const res = await fetch(`/image-pipeline/status/${jobId}`);
    const body = await res.json();

    if (res.status === 200) return body.media;   // COMPLETE
    if (res.status === 400) throw new Error(body.reason);  // REJECTED
    if (res.status === 500) throw new Error(body.error);   // FAILED

    await new Promise((r) => setTimeout(r, 1500)); // 1.5 s between polls
  }
  throw new Error("Processing timed out");
}

// Usage
const jobId = (await uploadFile(file)).jobId;
const media = await waitForProcessing(jobId);
console.log(media.urls.sm); // ready-to-use URL

Server-side webhook — check status and notify user

fastify.post("/webhooks/image-ready", async (request, reply) => {
  const { jobId, userId } = request.body;

  const res = await fetch(`http://localhost:3000/image-pipeline/status/${jobId}`);
  const data = await res.json();

  if (data.status === "COMPLETE") {
    await fastify.notifications.send(userId, {
      type: "image_ready",
      avatarUrl: data.media.urls.sm,
    });
  }

  return { ok: true };
});

See Also

AI Context

package: "@xenterprises/fastify-ximagepipeline"
route: GET /image-pipeline/status/:jobId
use-when: Poll job processing status — returns variant URLs and blurhash when COMPLETE
returns: { status (PENDING|PROCESSING|COMPLETE|REJECTED|FAILED), media? { variants, blurhash, metadata } }
Copyright © 2026