Detail repair
Regenerate a masked logo, text, or small detail and blend only that region back
You will need an API token to send HTTP requests. See Authentication for instructions.
Detail Repair regenerates only a masked region of an image — a garbled logo, distorted text, a small artifact — and composites just that region back onto the original, so everything outside the mask stays untouched. Optional reference shots act as ground truth so the fix reproduces the real detail instead of inventing one.
It also doubles as a general-purpose masked inpainting tool: with category: "general" you can drive any edit inside the mask (hairstyle, garment color, object removal, …) from a text instruction. See General-purpose inpainting.
It is built for programmatic pipelines: upload the image to fix, (optionally) a few reference shots, and a binary mask image, then start a job. Each job returns num_candidates variations.
Quick start
Create a project to organize your images. The project_id is used in later requests.
Upload the image to fix, any reference shots, and your mask image — each via the two-step pre-signed upload. Collect every file_id.
Start a detail repair job with the image, the mask, and (optionally) the references.
Track progress via SSE or webhooks; stop on a terminal status, then fetch the results.
Uploading images
Every image (the one to fix, the references, and the mask) is uploaded the same way: request a pre-signed URL, then PUT the bytes. See Uploading images.
import requests
api_url = "https://v2.api.piktid.com"
access_token = "your_access_token"
project_name = "my-detail-repair-project"
def upload(path, filename):
r = requests.post(
api_url + "/upload",
headers={"Authorization": "Bearer " + access_token},
json={"project_name": project_name, "filename": filename},
).json()
with open(path, "rb") as f:
requests.put(r["upload_url"], headers={"Content-Type": r["content_type"]}, data=f.read())
return r["project_id"], r["file_id"]
project_id, image_id = upload("product.jpg", "product.jpg") # the image to fix
_, reference_id = upload("reference.jpg", "reference.jpg") # ground-truth shot (optional)
_, mask_id = upload("mask.png", "mask.png") # binary mask (see below)Providing the mask
The mask tells the engine which region to regenerate. There are two ways to supply it; a binary mask image is the recommended path for API pipelines.
Binary mask image (recommended)
Upload a black-and-white PNG where white (255) marks the area to repair and black is left untouched, then pass its file_id as mask_image.
The mask must be the same pixel dimensions as the image to fix (it is resized to match if it differs). The repair follows the exact shape of the white pixels — not just their bounding rectangle.
# A mask you produced however you like — segmentation model, OpenCV threshold,
# a hand-drawn PNG, etc. White = repair, black = keep.
_, mask_id = upload("mask.png", "mask.png")
# ... pass mask_image=mask_id when starting the job (see below).Bounding-box rectangle
For a coarse fix you can skip the mask image and send a normalized rectangle instead — mask.bbox_norm = [x, y, w, h] in 0..1 coordinates (origin top-left). The whole rectangle is regenerated and blended back.
mask = {"bbox_norm": [0.66, 0.30, 0.08, 0.05]} # x, y, width, height (fractions of the image)Provide either mask_image or mask.bbox_norm (at least one is required). A binary mask gives a pixel-precise repair; a bbox regenerates the whole rectangle. The app's brush-strokes format is also accepted but is intended for the UI — prefer mask_image for integrations.
Starting a job
import requests
api_url = "https://v2.api.piktid.com"
access_token = "your_access_token"
response = requests.post(
api_url + "/detail-repair",
headers={"Authorization": "Bearer " + access_token},
json={
"project_id": project_id,
"image": image_id, # the image to fix
"mask_image": mask_id, # binary mask (white = repair area)
"references": [reference_id], # optional ground-truth shots (max 10)
"num_candidates": 3, # 1-4 variations
"category": "logo", # logo | text | artifact | ...
"reviewer_note": "Fix the wordmark to match the reference exactly.",
"model": "auto",
},
).json()
job_id = response["job_id"]
print(f"Job started: {job_id}"){
"job_id": "job_abc123...", // JOB_ID
"status": "pending",
"message": "Detail repair job created and queued"
}Request parameters
| Field | Type | Default | Description |
|---|---|---|---|
project_id | string | — | Project key the images belong to. Required. |
image | string | — | file_id of the image to fix. Required. |
mask_image | string | null | file_id of a binary mask (white = repair). Provide this or mask. |
mask | object | null | { "bbox_norm": [x, y, w, h] } rectangle in 0..1. Provide this or mask_image. |
references | string[] | [] | file_ids of reference shots where the detail is clearly visible. Max 10. Strongly recommended — without them the engine reconstructs from context and may approximate the detail. |
num_candidates | integer | 1 | Variations to generate, 1–4. Each is billed separately. |
category | string | "logo" | Prompt family. logo (default) optimizes for logos / brand marks; general switches to general-purpose inpainting for any masked edit (see below). Free-form — other values (text, artifact, …) also use the logo-optimized prompt. |
reviewer_note | string | null | Targeted instruction, e.g. "fix the first letter only". |
image_notes | string[] | [] | Brand/style hints forwarded to the prompt (e.g. font, casing). |
model | "auto" | "nano_banana_2" | "nano_banana_pro" | "seedream" | "gpt_image" | "auto" | Which engine generates the fix. auto runs the default engine with a safety fallback; specifying an engine disables the fallback. |
add_ai_watermark | boolean | false | Bake an "AI-generated" disclosure mark into each output. Ignored (forced on) for free-tier accounts. |
Advanced controls (enterprise)
Enterprise/admin accounts can tune how the region is regenerated. Other tiers always use the defaults below.
| Field | Type | Default | Description |
|---|---|---|---|
mode | string | "guided-blend" | Generation strategy. Three techniques — guided (recommended, highest fidelity), annotated, and marked — each available with or without a -blend variant. The -blend variants (default) keep the change tightly confined to the masked detail for a seamless result; the non-blend variants regenerate the region more freely. If guided isn't ideal for a given detail, annotated and marked are alternative strategies to try. Six values: marked, marked-blend, annotated, annotated-blend, guided, guided-blend. |
context_factor | number | 3.0 | How much surrounding context the engine considers when regenerating the detail. Clamped to 1.5–10.0. Lower keeps the focus tight on the detail; higher takes in more of the surroundings. |
General-purpose inpainting
Detail Repair isn't only for logos. Set category: "general" to switch to a
general-purpose inpainting prompt for any masked edit — change a hairstyle,
recolor a garment, swap a detail, remove an object — while everything outside the
mask stays untouched. The edit is driven by your reviewer_note (the
instruction); references, when supplied, should show the desired result.
# Recolor the jacket inside the mask, guided by the instruction.
response = requests.post(
api_url + "/detail-repair",
headers={"Authorization": "Bearer " + access_token},
json={
"project_id": project_id,
"image": image_id,
"mask_image": mask_id, # the region to edit
"category": "general", # general-purpose inpainting
"reviewer_note": "Make the jacket forest green; keep the texture and folds.",
"references": [], # optional — show the target look if you have one
"num_candidates": 3,
},
).json()In general mode the instruction is the spec — be specific about what changes and what must stay the same. With no instruction, the engine simply regenerates the marked area to be clean and coherent with its surroundings. Everything else (engine selection, candidates, the quality check) works exactly as in logo mode.
Credits
Detail Repair costs a flat 3 credits per variation, regardless of resolution (the output is preserved at its original size; processing is capped at 2K internally). A 3-candidate job costs 9 credits, charged once on completion. Failed candidates are not charged. See Credits.
Tracking progress
Track the job with the notifications stream (SSE) or a webhook, filtering on your job_id and stopping on a terminal status (completed, failed, aborted). See Notifications and Webhooks.
Retrieving results
Once the job is completed, fetch its results like any other job (see Jobs). Each output is a standard image result with the repaired region composited onto the original.
Quality check. Each output carries an automatic signal. If the engine can't confirm the fix lines up cleanly with the original, the output is flagged (needs_review, with a reason such as scale_drift, framing_shift, or no_reference when the job ran without references). Treat a flagged output as "compare against the original before using" — a handy signal for ranking candidates.
Error handling
| Status | Meaning |
|---|---|
400 | Missing/invalid input — no mask provided (mask_image and mask both absent), unknown image/mask_image/reference file_id, or an unreadable mask. |
402 | Insufficient credits for the requested number of candidates. |
403 | A subject was blocked by the content filter. |
404 | Project not found. |
See Errors for the full error model.