Disclosure: I work on API Crest, the API platform used below. I checked the endpoint and parameters against the public API documentation on October 14, 2026. This is a documentation-based walkthrough: I did not execute paid generation requests, benchmark latency, or verify output quality or prices.
A product-photo editing pipeline starts with an existing image. The tricky engineering parts are uploading files, decoding the response, and not accidentally paying twice when a client times out. This guide demonstrates API Crest's synchronous image-editing route using Python and cURL. It differs from the platform's asynchronous media-generation endpoint.
1. Endpoint and preparation
The API docs document:
- Base URL:
https://api.vv666.ai - Image-edit endpoint:
POST /v1/images/edits - Model ID:
gpt-image-2.5(a provider-documented ID) - Auth:
Authorization: Bearer API_KEY - Multipart image field: repeated
image[] - Required text fields:
model,prompt - Default response:
data[0].b64_json; an optionalresponse_format=urlalso exists.
These are documented API Crest values, not universal guarantees of all OpenAI-compatible APIs. Check the live model catalog and account pricing before spending credits.
Install Python requests and place your secret in a local environment variable:
python -m pip install requests export APICREST_API_KEY="YOUR_API_KEY" In PowerShell, use $env:APICREST_API_KEY = "YOUR_API_KEY". Never hard-code or publish a live key.
2. Multipart cURL request
If you own or are authorized to process product.png:
curl --request POST "https://api.vv666.ai/v1/images/edits" \ --header "Authorization: Bearer APICREST_API_KEY" \ --form "model=gpt-image-2.5" \ --form "image[]=@product.png" \ --form "prompt=Place this product on a clean wooden desk in morning light. Keep its packaging colors and label as close to the reference as possible." \ --form "size=1536x1024" \ --form "quality=high" \ --form "response_format=b64_json" cURL builds the multipart boundary automatically; do not set Content-Type: application/json for this upload. A prompt cannot guarantee text, logo or packaging fidelity: manually review generated commercial assets.
3. Python: send one edit and save the image
This script deliberately does not automatically retry a possibly billable POST.
import base64 import os from pathlib import Path import requests source = Path("product.png") if not source.is_file(): raise FileNotFoundError(source) endpoint = "https://api.vv666.ai/v1/images/edits" headers = {"Authorization": f"Bearer {os.environ['APICREST_API_KEY']}"} with source.open("rb") as image: response = requests.post( endpoint, headers=headers, files={"image[]": (source.name, image, "image/png")}, data={ "model": "gpt-image-2.5", "prompt": "Place this product on a wooden desk in morning light. Preserve packaging as closely as possible.", "size": "1536x1024", "quality": "high", "response_format": "b64_json", }, timeout=(15, 360), # illustrative connect/read timeouts; not an SLA ) task_id = response.headers.get("X-Task-Id") if task_id: print("Task ID:", task_id) if not response.ok: try: error = response.json().get("error", {}) if isinstance(error, dict) and error.get("task_id"): print("Task ID for follow-up:", error["task_id"]) except (ValueError, AttributeError): pass response.raise_for_status() image_b64 = response.json()["data"][0]["b64_json"] output = Path("edited.png") output.write_bytes(base64.b64decode(image_b64, validate=True)) print("Saved:", output.resolve()) The endpoint is synchronous; the 360-second example read timeout is a client choice, not a claimed measurement. With the documented response_format=url, handle data[0].url instead; don't assume those URLs last forever.
4. Two reference images
The documented multipart API accepts repeated image inputs:
--form "image[]=@product.png" \ --form "image[]=@background.png" To send multiple files in Python requests, pass a list of repeated ("image[]", (filename, stream, mimetype)) entries, not a dictionary with duplicate keys. The docs describe up to 16 references, though individual channels may have lower limits. Validate permissions, file types and sizes.
5. Timeout and billing safety
A client timeout does not prove that the provider canceled processing. Blindly retrying the same POST could create a second billable edit. Don't implement automatic POST retries without a documented idempotency guarantee.
API Crest documents a response X-Task-Id header, possible error.task_id values, and a status/cost lookup:
GET https://api.vv666.ai/v1/skills/task-status?task_id=YOUR_TASK_ID Authorization: Bearer YOUR_API_KEY When is_final=true, the docs describe the settled cost as available in the task result. If the connection drops before any headers, you may have no ID: treat the outcome as unknown, reconcile activity/usage, and avoid infinite retries.
Production checklist:
- Secrets: keep keys server-side, redact logs, and restrict access.
- Cost: image edits use documented per-image billing; Enhanced channels can cost more. Check live channel/model prices and settled account charges; no invented dollar amounts or savings claims here.
- Inputs: validate file type, size, image rights, and user authorization.
- Errors: inspect sanitized status/error objects; IP allowlist restrictions may return 403 /
ip_not_allowed. - Capabilities: this documented interface does not support
maskorn > 1;input_fidelityis ignored. - Visual QA: review logos, ingredient text, labels, proportions, and advertising claims before publication.
- Protocol: the asynchronous
POST /v1/media/generateworkflow is separate from synchronous/v1/images/edits.
6. What to validate yourself
Before integrating with production, make one authorized low-volume request, check that the response can be decoded, record returned task IDs, and examine actual billing. I have not run that paid test for this article.
Docs: API Crest public API documentation · API Crest platform
For developers working with product images, what is hardest: reference fidelity, long-running requests, or avoiding duplicate charges?
