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.

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}")
Response
{
  "job_id": "job_abc123...",  // JOB_ID
  "status": "pending",
  "message": "Detail repair job created and queued"
}

Request parameters

FieldTypeDefaultDescription
project_idstringProject key the images belong to. Required.
imagestringfile_id of the image to fix. Required.
mask_imagestringnullfile_id of a binary mask (white = repair). Provide this or mask.
maskobjectnull{ "bbox_norm": [x, y, w, h] } rectangle in 0..1. Provide this or mask_image.
referencesstring[][]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_candidatesinteger1Variations to generate, 14. Each is billed separately.
categorystring"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_notestringnullTargeted instruction, e.g. "fix the first letter only".
image_notesstring[][]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_watermarkbooleanfalseBake 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.

FieldTypeDefaultDescription
modestring"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_factornumber3.0How much surrounding context the engine considers when regenerating the detail. Clamped to 1.510.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

StatusMeaning
400Missing/invalid input — no mask provided (mask_image and mask both absent), unknown image/mask_image/reference file_id, or an unreadable mask.
402Insufficient credits for the requested number of candidates.
403A subject was blocked by the content filter.
404Project not found.

See Errors for the full error model.

On this page