cd /news/developer-tools/before-i-call-gpt-image-2-i-validate… · home topics developer-tools article
[ARTICLE · art-118870] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Before I Call GPT Image 2, I Validate These 7 Things

An engineer at XPLA detailed a seven-check preflight validation workflow for GPT Image 2 API calls, emphasizing contract-based request validation, dimension conflict checks, and idempotency handling to prevent duplicate billable generations. The approach includes rejecting unsupported fields, storing product identity and allowed transformations, and persisting generation state to reconcile uncertain transport outcomes.

read5 min views1 publishedSep 2, 2026

I used to debug a bad AI product image by rewriting the prompt. Now I check

the request contract first.

A GPT Image 2 API request can be valid JSON and still be wrong for the selected

model. A generic UI can leak a field from another provider. Two dimension

controls can conflict. A timeout can turn one intended image into two

generations. A technically successful output can still change the product.

This is the seven-check preflight I put in front of the generation call.

Disclosure: I work on XPLA. The workflow below is an engineering pattern,

not a promise about price, access, speed or image quality.

I do not let one universal form submit every visible field to every image

model. The application selects a model contract first:

const imageContracts = {
  "gpt-image-2": {
    endpoint: "/v1/images/generations",
    allowed: new Set([
      "model", "prompt", "image", "images",
      "size", "aspectRatio", "quality", "replyType", "n"
    ]),
    forbidden: new Set(["imageSize"])
  }
};

The UI should be generated from that record. A control the selected model does

not support should not appear.

Silently removing an unsupported field creates plausible but uncontrolled

outputs. The user chooses a setting, the backend drops it, a default is used,

and everyone blames the model.

function rejectUnknownFields(body, contract) {
  const errors = [];

  for (const key of Object.keys(body)) {
    if (!contract.allowed.has(key)) {
      errors.push(`Unsupported field for ${body.model}: ${key}`);
    }
  }

  for (const key of contract.forbidden) {
    if (body[key] !== undefined) {
      errors.push(`Forbidden field for ${body.model}: ${key}`);
    }
  }

  return errors;
}

An explicit local error is easier to fix than an attractive image produced

from the wrong request.

An image form may expose a ratio, a pixel size, a provider-specific size field

and an orientation inferred from the prompt. I allow one supported decision:

function validateDimensions(body) {
  if (body.imageSize !== undefined) {
    return ["imageSize is not valid for this standard contract"];
  }

  const supplied = [
    body.size !== undefined,
    body.aspectRatio !== undefined
  ].filter(Boolean).length;

  return supplied > 1
    ? ["Choose size or aspectRatio, not both"]
    : [];
}

I store the requested orientation beside the output so QA can verify it.

A reference is more than a URL. I store the product identity and the allowed

transformation:

{
  "source_type": "merchant_upload",
  "rights_state": "confirmed_for_internal_calibration",
  "product_id": "merchant-sku-104",
  "variant": "matte-black-500ml",
  "must_preserve": [
    "single bottle",
    "matte black body",
    "silver cap",
    "existing label geometry"
  ],
  "allowed_changes": [
    "background",
    "surface",
    "lighting direction"
  ]
}

A marketplace image being public does not automatically grant permission to

download, transform or use it in advertising.

This is the operational rule I care about most.

If a client times out, it may not know whether the server failed before or

after generation. Repeating the request can create another billable task.

Before submission, I persist:

{
  "generation_id": "img-job-20260902-001",
  "intent": "new_calibration",
  "request_hash": "sha256-of-normalized-request",
  "state": "submitted",
  "attempt": 1,
  "result_state": "unknown",
  "next_action": "check_before-repeating"
}

My state transition is:

draft
  -> approved
  -> submitted
  -> completed
  -> accepted | repair | rejected

submitted
  -> transport_unknown
  -> reconcile before another generation

A new creative candidate receives a new generation ID. An uncertain transport

result enters reconciliation. I do not hide both actions behind one “Try

again” button.

For the first run I use:

The question is narrow: can the workflow preserve the product facts that

matter? More outputs do not improve the evidence if no one reviews them.

My QA table looks like this:

Check Expected Decision
Product count one unit accept / repair / reject
Body color matte black accept / repair / reject
Cap silver accept / repair / reject
Label geometry unchanged accept / repair / reject
Invented claims none accept / repair / reject
Orientation requested ratio accept / repair / reject
Crop safety fully visible accept / repair / reject

“Looks good” is not a release decision. An attractive output can still invent

a bundle, accessory, certification or quantity.

function preflightGPTImage2(body, rightsRecord) {
  const contract = imageContracts[body.model];
  const errors = [];

  if (!contract) errors.push(`Unknown model contract: ${body.model}`);
  if (!body.prompt?.trim()) errors.push("prompt is required");
  if (body.n !== undefined && body.n !== 1) {
    errors.push("Use n: 1 and create separate intentional requests");
  }
  if (body.replyType !== undefined && body.replyType !== "json") {
    errors.push('replyType must be "json"');
  }

  if (contract) {
    errors.push(...rejectUnknownFields(body, contract));
    errors.push(...validateDimensions(body));
  }

  if ((body.image || body.images) &&
      rightsRecord?.rights_state !== "confirmed_for_internal_calibration") {
    errors.push("Reference-image rights are not confirmed");
  }

  return { ok: errors.length === 0, errors };
}

This is only the request boundary. A production implementation still needs

media-type, file-size, URL, privacy, account, policy and storage checks.

Failure class Example Default action
Client empty prompt fix locally
Contract unsupported field reject before submission
Access unauthorized key stop and fix access
Transport lost response reconcile before repeating
Provider transient failure bounded retry policy
Safety risky request stop or revise
Output QA altered product repair or reject

I keep the final order simple:

contract -> preflight -> approval -> one calibration
-> product QA -> intentional scale

The current XPLA-specific request shape and model-name boundaries are

documented in the GPT Image 2 API guide.

Recheck the live contract before production integration.

── more in #developer-tools 4 stories · sorted by recency
── more on @xpla 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/before-i-call-gpt-im…] indexed:0 read:5min 2026-09-02 ·