{"openapi":"3.1.0","info":{"title":"MakeSeamless API","version":"1.0.0","summary":"Check whether an image tiles seamlessly, and make it tile seamlessly.","description":"Check a pattern tile for seams where its copies meet, and fix it so that it repeats without a\nvisible seam.\n\n- A check is free and needs no account. A fix needs an API key and costs credits (`GET /v1/plans`).\n- A fix runs in the background: `POST /v1/fix` answers `202` with a job. Poll\n  `GET /v1/jobs/{job_id}` until its `status` is `succeeded` or `failed`, waiting the seconds that\n  `Retry-After` gives.\n- Every image the API returns has the exact width and height of the uploaded image (after its\n  orientation is applied), as a fresh lossless PNG that carries no metadata of the upload.\n- Breaking changes come only under a new prefix (`/v2`). Fields may be added to responses; ignore\n  the fields you do not know.\n- Error codes are stable: read `error.code`, not `error.message`. Any request may also fail with\n  `500` and the code `internal_error`.\n","license":{"name":"Proprietary"}},"servers":[{"url":"https://makeseamless.com"}],"tags":[{"name":"check","description":"Seam check, answered at once."},{"name":"fix","description":"Fix job, run in the background."},{"name":"jobs","description":"Job status, result images and ratings."},{"name":"health","description":"Service status."},{"name":"account","description":"The account, its plan and credits."}],"paths":{"/v1/health":{"get":{"tags":["health"],"operationId":"getHealth","summary":"Service status","description":"`ok` while the service answers.","security":[],"responses":{"200":{"description":"The service answers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"},"example":{"status":"ok"}}}}}}},"/v1/check":{"post":{"tags":["check"],"operationId":"checkImage","summary":"Check an image for seams","description":"Says, for each requested repeat type, whether the image tiles seamlessly and where its edges\nbreak when copies of it meet. Only the tile's own edges are read; a seam inside the tile is not\nchecked, and the summary says so. Inputs: PNG, JPEG or WebP, at most 40 MB, at least 64 x 64 px,\nat most 64 MP. A repeat type that does not apply (an odd height for half-drop, an odd width for\nhalf-brick) is reported as `not_applicable`. No account is needed; checks are limited per client.\n","security":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The image file (PNG, JPEG or WebP)."},"repeats":{"type":"array","description":"Repeat types to check. Default all three.","items":{"$ref":"#/components/schemas/RepeatType"},"minItems":1,"uniqueItems":true}}},"encoding":{"repeats":{"style":"form","explode":true}}}}},"responses":{"200":{"description":"The check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckResult"},"example":{"input":{"sha256":"07c1858ff8d2c84e7ef521aa92e49ad251dec90553b65e600bd52ee84ef4065f","width":256,"height":256,"format":"PNG","has_alpha":true},"verdicts":{"straight":{"repeat":"straight","verdict":"bad","edges":[{"edge":"vertical","verdict":"bad","anomaly":1.9222,"broken":[[90,170]]},{"edge":"horizontal","verdict":"ok","anomaly":0.9328,"broken":[]}]},"half_drop":{"repeat":"half_drop","verdict":"bad","edges":[{"edge":"vertical","verdict":"bad","anomaly":2.164,"broken":[[83,172],[208,238]]},{"edge":"horizontal","verdict":"ok","anomaly":0.9328,"broken":[]}]},"half_brick":{"repeat":"half_brick","verdict":"bad","edges":[{"edge":"vertical","verdict":"bad","anomaly":1.9222,"broken":[[90,170]]},{"edge":"horizontal","verdict":"minor","anomaly":1.4314,"broken":[[0,72],[108,147],[149,201],[240,256]]}]}},"satisfied":[],"duplicate_edge":{"vertical":false,"horizontal":false},"summary":"Does not tile seamlessly as any checked repeat type. Straight: bad (left/right edge, 1 stretch). Half-drop: bad (left/right edge, 2 stretches). Half-brick: bad (left/right edge, 1 stretch; top/bottom edge, 4 stretches). Seams inside the tile are not checked."}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/fix":{"post":{"tags":["fix"],"operationId":"createFixJob","summary":"Start a fix","description":"Validates the image, then starts a job in the background that makes it tile seamlessly under\nthe requested repeat type, and answers `202` with the job. Poll `GET /v1/jobs/{job_id}`.\nInputs: PNG, JPEG or WebP, at most 40 MB, at least 64 x 64 px, at most 3600 px on a side; an\neven height for `half_drop` and an even width for `half_brick`; no transparent pixels near the\nedges.\n\nA fix costs one credit, or `Plans.fix_credits.large_credits` for a tile above `large_above_px`\non either side, paid from the account's credits. The credits are reserved when the job starts\nand come back when it fails with `no_seamless_candidate`, `service_unavailable` or\n`interrupted`. The same image with the same repeat type, fixed before, gets a job that has\nalready `succeeded`, marked `cached`, at no charge. Sent again while its fix is still `queued`\nor `running`, it gets that same job back, at no charge.\n","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","repeat"],"properties":{"file":{"type":"string","format":"binary","description":"The image file (PNG, JPEG or WebP)."},"repeat":{"$ref":"#/components/schemas/RepeatType"}}}}}},"responses":{"202":{"description":"The job, `queued`, or already `succeeded` when `cached`.","headers":{"Location":{"$ref":"#/components/headers/Location"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"},"example":{"id":"job_2432c1827f32450f800694e552e9915c","status":"queued","stage":"queued","repeat":"straight","cached":false,"input":{"sha256":"9cf95d486b4c7d1bd6022a3e51d7c89b89ba5239d0378033c9a9f53413dd7770","width":256,"height":256,"format":"PNG","has_alpha":true},"created_at":"2026-11-03T15:24:08.435Z","started_at":null,"finished_at":null,"result":null,"error":null,"candidates":[]}}}},"401":{"$ref":"#/components/responses/AuthRequired"},"402":{"description":"Not enough credits for the fix (`insufficient_credits`); `details.credits_needed` is what it\ncosts.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"insufficient_credits","message":"Not enough credits for this fix.","retryable":false,"details":{"credits_needed":1}}}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"Not now; `Retry-After` says when to try again. `daily_capacity_reached`: the service's\nfixes for the day are at capacity. `too_many_running_fixes`: the account already has 3\nfixes queued or running.\n","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfterLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/jobs/{job_id}":{"get":{"tags":["jobs"],"operationId":"getJob","summary":"A fix job","description":"The job as it stands. A succeeded job carries its `result` and the other images the fix made\n(`candidates`); a failed one its `error`. Anyone with the job's id can read it.\n","security":[],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"The job. While it is `queued` or `running`, `Retry-After` says when to poll again.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"},"example":{"id":"job_2432c1827f32450f800694e552e9915c","status":"succeeded","stage":"finished","repeat":"straight","cached":false,"input":{"sha256":"9cf95d486b4c7d1bd6022a3e51d7c89b89ba5239d0378033c9a9f53413dd7770","width":256,"height":256,"format":"PNG","has_alpha":true},"created_at":"2026-11-03T15:24:08.435Z","started_at":"2026-11-03T15:24:08.436Z","finished_at":"2026-11-03T15:24:08.953Z","result":{"outcome":"ok","image_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/result","changed_mask_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/changed_mask","visible_changed_mask_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/visible_mask","width":256,"height":256,"sha256":"d896bd338713c58bfc87b1c235410a4e663a37dcc67e6b5b9ea7197ce7905ee8","resampled":false,"changed_share":0.3017578125,"visible_changed_share":0.21240234375,"seam_report":{"before":{"repeat":"straight","verdict":"bad","edges":[{"edge":"vertical","verdict":"bad","anomaly":1.5306,"broken":[[33,97]]},{"edge":"horizontal","verdict":"ok","anomaly":0.9328,"broken":[]}]},"after":{"repeat":"straight","verdict":"ok","edges":[{"edge":"vertical","verdict":"ok","anomaly":0.9477,"broken":[]},{"edge":"horizontal","verdict":"ok","anomaly":0.9328,"broken":[]}]}},"alternative":{"id":"candidate_a","image_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/candidates/candidate_a","passed":false,"changed_share":1.0}},"error":null,"candidates":[{"id":"candidate_a","image_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/candidates/candidate_a","passed":false,"changed_share":1.0,"resampled":false},{"id":"candidate_b","image_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/candidates/candidate_b","passed":false,"changed_share":0.3017578125,"resampled":false},{"id":"candidate_c","image_url":"/v1/jobs/job_2432c1827f32450f800694e552e9915c/candidates/candidate_c","passed":false,"changed_share":1.0,"resampled":true}]}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/jobs/{job_id}/result":{"get":{"tags":["jobs"],"operationId":"getJobResult","summary":"The fixed image","description":"The result of a succeeded job as a PNG with the uploaded image's exact width and height.","security":[],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"The fixed image.","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"404":{"$ref":"#/components/responses/ImageNotFound"},"409":{"$ref":"#/components/responses/NoImage"}}}},"/v1/jobs/{job_id}/changed_mask":{"get":{"tags":["jobs"],"operationId":"getJobChangedMask","summary":"The changed area of the fixed image","description":"A grayscale PNG with the uploaded image's exact width and height: white (255) where the\nresult's pixels may differ from the upload and black (0) where they equal it. A band along the\nedges, outside which every pixel equals the upload, or all white when every pixel changed\n(`resampled`). Its white share is `result.changed_share`.\n","security":[],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"The changed area.","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"404":{"$ref":"#/components/responses/ImageNotFound"},"409":{"$ref":"#/components/responses/NoImage"}}}},"/v1/jobs/{job_id}/visible_mask":{"get":{"tags":["jobs"],"operationId":"getJobVisibleMask","summary":"The visibly changed area of the fixed image","description":"A grayscale PNG with the uploaded image's exact width and height: white (255) where the\nresult looks different from the upload and black (0) where it looks the same. It lies inside\nthe changed area. Its white share is `result.visible_changed_share`. A result without\n`visible_changed_mask_url` has none and answers 404.\n","security":[],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"The visibly changed area.","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"`not_found`: no job with this id, its result has no visible mask, or the image is no longer\nstored (images are kept for 30 days).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/NoImage"}}}},"/v1/jobs/{job_id}/candidates/{candidate_id}":{"get":{"tags":["jobs"],"operationId":"getJobCandidateImage","summary":"Another image of a succeeded job","description":"One of the other images the fix made, by its `id` in the job's `candidates`, as a PNG with the\nuploaded image's exact width and height. `candidate_a` is the one in `result.alternative`. It\nmay not have passed; its `passed` says so. An id the job does not have answers 404.\n","security":[],"parameters":[{"$ref":"#/components/parameters/JobId"},{"$ref":"#/components/parameters/CandidateId"}],"responses":{"200":{"description":"The image.","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"`not_found`: no job with this id, no image with this id in the job, or the image is no\nlonger stored (images are kept for 30 days).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/NoImage"}}}},"/v1/jobs/{job_id}/rating":{"post":{"tags":["jobs"],"operationId":"rateJobCandidate","summary":"Rate an image of a succeeded job","description":"Stores your rating of the result (`result`) or of another image of the job (its `id`):\n\"Seamless\" or \"Seam visible\". Ratings help us make better fixes. A new rating of the same\nimage replaces the last one. Only the account that started the job, or was served it as a\ncached job, rates it, within 30 days of the job's creation.\n","security":[{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/JobId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatingRequest"}}}},"responses":{"201":{"description":"The stored rating.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rating"},"example":{"job_id":"job_2432c1827f32450f800694e552e9915c","candidate":"result","rating":"seamless","created_at":"2026-11-03T15:24:08.963Z"}}}},"401":{"$ref":"#/components/responses/AuthRequired"},"404":{"description":"`not_found`: no job with this id that your account can rate, or the image is no longer\nstored.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to rate yet or any more: `result_not_ready` while the job is `queued` or `running`\n(poll the job again after `Retry-After`), `no_result` when it failed, `rating_closed` once\n30 days have passed since the job was created.\n","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`validation_error`: an unknown rating, or an image id the job does not have.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/plans":{"get":{"tags":["account"],"operationId":"getPlans","summary":"Plans and prices","description":"The plans in US dollars. One credit is one fix; a large tile costs more (`fix_credits`). Free:\nunlimited seam checks. Pro: credits each month by tier, billed monthly or yearly (the yearly price\nis shown as its monthly equivalent and billed once a year, with twelve months of credits). A\nPro account can buy top-up credits at its tier's price per credit. Enterprise: contact sales.\n","security":[],"responses":{"200":{"description":"The plans.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Plans"},"example":{"free":{"signup_credits":0},"fix_credits":{"credits":1,"large_credits":3,"large_above_px":2048},"pro":[{"credits":50,"monthly_usd":19,"yearly_monthly_usd":15,"yearly_usd":180,"yearly_credits":600,"topup_usd_per_credit":0.38},{"credits":135,"monthly_usd":49,"yearly_monthly_usd":39,"yearly_usd":468,"yearly_credits":1620,"topup_usd_per_credit":0.363},{"credits":280,"monthly_usd":99,"yearly_monthly_usd":79,"yearly_usd":948,"yearly_credits":3360,"topup_usd_per_credit":0.354},{"credits":430,"monthly_usd":149,"yearly_monthly_usd":119,"yearly_usd":1428,"yearly_credits":5160,"topup_usd_per_credit":0.347}],"topup":{"min_credits":10,"max_credits":10000},"enterprise":{"contact":true}}}}}}}},"/v1/me":{"get":{"tags":["account"],"operationId":"getMe","summary":"Your account, plan and credits","security":[{"apiKey":[]}],"responses":{"200":{"description":"The account of the API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"account_id":"user-ada","email":"ada@shop.test","plan":"free","tier":null,"interval":null,"subscription_status":null,"unlimited":false,"credits":{"subscription":0,"bonus":0,"topup":5,"total":5},"period_credits":null,"credits_used_this_period":0,"current_period_start":null,"current_period_end":null}}}},"401":{"$ref":"#/components/responses/AuthRequired"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"An API key of your account, created on makeseamless.com and sent in the `x-api-key` header. Keys start with `smls_`."}},"parameters":{"JobId":{"name":"job_id","in":"path","required":true,"description":"The job's `id`, from `POST /v1/fix`.","schema":{"type":"string","pattern":"^job_[0-9a-f]{32}$"}},"CandidateId":{"name":"candidate_id","in":"path","required":true,"description":"An image's `id` in the job's `candidates`.","schema":{"$ref":"#/components/schemas/CandidateId"}}},"headers":{"Location":{"description":"Path of the job, `/v1/jobs/{job_id}`.","schema":{"type":"string"}},"RetryAfter":{"description":"Seconds to wait before polling again.","schema":{"type":"integer","minimum":1}},"RetryAfterLimit":{"description":"Seconds to wait before trying again.","schema":{"type":"integer","minimum":1}}},"responses":{"PayloadTooLarge":{"description":"The image file is larger than 40 MB (`payload_too_large`); refused before it is read in full.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InvalidInput":{"description":"The request or the image cannot be used. Codes: `validation_error`, `unsupported_format`,\n`decode_failed`, `too_small`, `too_large`, `odd_dimension` (fix only), `transparent_seam_band`\n(fix only).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No job with this id (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ImageNotFound":{"description":"`not_found`: no job with this id, or the image is no longer stored (images are kept for 30\ndays).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NoImage":{"description":"No image yet or at all: `result_not_ready` while the job is `queued` or `running` (poll the job\nagain after `Retry-After`), `no_result` when it failed.\n","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"AuthRequired":{"description":"No API key, or one that is revoked or unknown (`auth_required`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests from this client in the last minute (`rate_limited`); `Retry-After` says when\nto try again.\n","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfterLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"RepeatType":{"type":"string","enum":["straight","half_drop","half_brick"],"description":"`straight`: plain repeat on both axes. `half_drop`: the next column is shifted down by half the\nheight (needs an even height). `half_brick`: the next row is shifted right by half the width\n(needs an even width).\n"},"Verdict":{"type":"string","enum":["ok","minor","bad","not_applicable"],"description":"`ok`: no seam. `minor`: a faint seam. `bad`: a visible seam. `not_applicable`: the repeat type does not fit this size."},"Range":{"type":"array","description":"Half-open pixel range `[start, end)` along an edge.","items":{"type":"integer","minimum":0},"minItems":2,"maxItems":2},"EdgeReport":{"type":"object","additionalProperties":false,"required":["edge","verdict","anomaly","broken"],"description":"One edge where copies of the tile meet. Positions along the `vertical` edge are rows of the\ntile; along the `horizontal` edge, columns.\n","properties":{"edge":{"type":"string","enum":["vertical","horizontal"],"description":"`vertical`: where the right side meets the left. `horizontal`: where the bottom meets the top."},"verdict":{"type":"string","enum":["ok","minor","bad"],"description":"The level of `anomaly`."},"anomaly":{"type":"number","minimum":0,"description":"How strong the seam is, on one scale for every edge; higher is stronger."},"broken":{"type":"array","description":"The stretches of the edge where the seam shows.","items":{"$ref":"#/components/schemas/Range"}}}},"RepeatVerdict":{"type":"object","additionalProperties":false,"required":["repeat","verdict","edges"],"description":"The verdict for one repeat type, with its seam report per edge.","properties":{"repeat":{"$ref":"#/components/schemas/RepeatType"},"verdict":{"$ref":"#/components/schemas/Verdict"},"edges":{"type":"array","description":"Empty when the verdict is `not_applicable`.","items":{"$ref":"#/components/schemas/EdgeReport"}}}},"InputInfo":{"type":"object","additionalProperties":false,"required":["sha256","width","height","format","has_alpha"],"properties":{"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"SHA-256 of the uploaded file bytes."},"width":{"type":"integer","minimum":64,"description":"Width in px, after the image's orientation is applied."},"height":{"type":"integer","minimum":64,"description":"Height in px, after the image's orientation is applied."},"format":{"type":"string","enum":["PNG","JPEG","WEBP"]},"has_alpha":{"type":"boolean"}}},"CheckResult":{"type":"object","additionalProperties":false,"required":["input","verdicts","satisfied","duplicate_edge","summary"],"properties":{"input":{"$ref":"#/components/schemas/InputInfo"},"verdicts":{"type":"object","additionalProperties":false,"description":"One entry per requested repeat type.","properties":{"straight":{"$ref":"#/components/schemas/RepeatVerdict"},"half_drop":{"$ref":"#/components/schemas/RepeatVerdict"},"half_brick":{"$ref":"#/components/schemas/RepeatVerdict"}}},"satisfied":{"type":"array","description":"The requested repeat types the image already tiles as (verdict `ok`).","items":{"$ref":"#/components/schemas/RepeatType"}},"duplicate_edge":{"type":"object","additionalProperties":false,"required":["vertical","horizontal"],"description":"A 1 px line repeated on both sides of an edge, which shows as a doubled line when tiled.","properties":{"vertical":{"type":"boolean"},"horizontal":{"type":"boolean"}}},"summary":{"type":"string","description":"One plain-language line; it says that seams inside the tile are not checked."}}},"JobStatus":{"type":"string","enum":["queued","running","succeeded","failed"]},"JobStage":{"type":"string","enum":["queued","fixing","finishing","finished"],"description":"Progress for display; it only moves forward. `queued`: waiting to start. `fixing`: seamless\nversions of the image are being made. `finishing`: the result and its files are being\nprepared. `finished`: the job succeeded or failed.\n"},"Outcome":{"type":"string","enum":["ok","resampled"],"description":"`ok`: the result passed every quality check. `resampled`: no version passed every quality\ncheck, so the result is one in which every pixel changed; it passes the seam check, and fine\ndetail may look a little softer.\n"},"CandidateId":{"type":"string","pattern":"^candidate_[a-z]+$","description":"The id of an image of the job other than the result: `candidate_a`, `candidate_b` and so on.\nIds are per job.\n"},"SeamReport":{"type":"object","additionalProperties":false,"required":["before","after"],"description":"The seam report for the requested repeat type, on the upload and on the result.","properties":{"before":{"$ref":"#/components/schemas/RepeatVerdict"},"after":{"$ref":"#/components/schemas/RepeatVerdict"}}},"Alternative":{"type":"object","additionalProperties":false,"required":["id","image_url","passed","changed_share"],"description":"The other candidate shown next to the result.","properties":{"id":{"$ref":"#/components/schemas/CandidateId"},"image_url":{"type":"string","description":"`/v1/jobs/{job_id}/candidates/{id}`."},"passed":{"type":"boolean","description":"True when it passed the same checks as a result. Offer its download only when true."},"changed_share":{"type":"number","minimum":0,"maximum":1,"description":"Share of the image inside its changed area."}}},"Candidate":{"type":"object","additionalProperties":false,"required":["id","image_url","passed","changed_share","resampled"],"description":"An image the fix made besides the result.","properties":{"id":{"$ref":"#/components/schemas/CandidateId"},"image_url":{"type":"string","description":"`/v1/jobs/{job_id}/candidates/{id}`."},"passed":{"type":"boolean","description":"True when it passed the same checks as a result."},"changed_share":{"type":"number","minimum":0,"maximum":1,"description":"Share of the image inside its changed area."},"resampled":{"type":"boolean","description":"True when every pixel changed (outcome `resampled`); fine detail may look a little softer."}}},"FixResult":{"type":"object","additionalProperties":false,"required":["outcome","image_url","changed_mask_url","width","height","sha256","resampled","changed_share","seam_report","alternative"],"properties":{"outcome":{"$ref":"#/components/schemas/Outcome"},"image_url":{"type":"string","description":"`/v1/jobs/{job_id}/result`."},"changed_mask_url":{"type":"string","description":"`/v1/jobs/{job_id}/changed_mask`, the changed area."},"visible_changed_mask_url":{"type":"string","description":"`/v1/jobs/{job_id}/visible_mask`, the visibly changed area. Absent on results made before\nit was offered.\n"},"width":{"type":"integer","description":"Always the uploaded image's width."},"height":{"type":"integer","description":"Always the uploaded image's height."},"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"SHA-256 of the result PNG bytes."},"resampled":{"type":"boolean","description":"True when every pixel changed (outcome `resampled`); fine detail may look a little softer."},"changed_share":{"type":"number","minimum":0,"maximum":1,"description":"Share of the image inside the changed area (the white share of `changed_mask_url`): the\nband along the edges, or 1 when every pixel changed.\n"},"visible_changed_share":{"type":"number","minimum":0,"maximum":1,"description":"Share of the image that looks different from the upload (the white share of\n`visible_changed_mask_url`), never more than `changed_share`. When every pixel changed but\nmost only slightly, `changed_share` is 1 and this share is much smaller. Absent on results\nmade before it was offered.\n"},"seam_report":{"$ref":"#/components/schemas/SeamReport"},"alternative":{"oneOf":[{"$ref":"#/components/schemas/Alternative"},{"type":"null"}],"description":"Null when the fix made no other image."}}},"Job":{"type":"object","additionalProperties":false,"required":["id","status","stage","repeat","cached","input","created_at","started_at","finished_at","result","error","candidates"],"properties":{"id":{"type":"string","pattern":"^job_[0-9a-f]{32}$"},"status":{"$ref":"#/components/schemas/JobStatus"},"stage":{"$ref":"#/components/schemas/JobStage"},"repeat":{"$ref":"#/components/schemas/RepeatType"},"cached":{"type":"boolean","description":"True when the same image was fixed before and this result was served again, at no charge."},"input":{"$ref":"#/components/schemas/InputInfo"},"created_at":{"type":"string","format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time"},"finished_at":{"type":["string","null"],"format":"date-time"},"result":{"oneOf":[{"$ref":"#/components/schemas/FixResult"},{"type":"null"}],"description":"Present when `status` is `succeeded`."},"error":{"oneOf":[{"$ref":"#/components/schemas/ErrorBody"},{"type":"null"}],"description":"Present when `status` is `failed`."},"candidates":{"type":"array","description":"The other images of a succeeded job, `candidate_a` (the `result.alternative`) first. Empty\nuntil the job succeeded, and for a failed job.\n","items":{"$ref":"#/components/schemas/Candidate"}}}},"Health":{"type":"object","additionalProperties":false,"required":["status"],"properties":{"status":{"type":"string","const":"ok"}}},"RatingValue":{"type":"string","enum":["seamless","seam_visible"],"description":"The two answers, \"Seamless\" and \"Seam visible\"."},"RatingCandidate":{"type":"string","pattern":"^(result|candidate_[a-z]+)$","description":"`result` for the fixed image, or the `id` of another image of the job."},"RatingRequest":{"type":"object","additionalProperties":false,"required":["rating","candidate"],"properties":{"rating":{"$ref":"#/components/schemas/RatingValue"},"candidate":{"$ref":"#/components/schemas/RatingCandidate"}}},"Rating":{"type":"object","additionalProperties":false,"required":["job_id","candidate","rating","created_at"],"properties":{"job_id":{"type":"string","pattern":"^job_[0-9a-f]{32}$"},"candidate":{"$ref":"#/components/schemas/RatingCandidate"},"rating":{"$ref":"#/components/schemas/RatingValue"},"created_at":{"type":"string","format":"date-time"}}},"ErrorCode":{"type":"string","enum":["validation_error","payload_too_large","unsupported_format","decode_failed","too_small","too_large","odd_dimension","transparent_seam_band","not_found","result_not_ready","no_result","no_seamless_candidate","service_unavailable","interrupted","internal_error","auth_required","insufficient_credits","daily_capacity_reached","too_many_running_fixes","rate_limited","already_subscribed","pro_required","no_subscription","rating_closed"],"description":"Stable codes. Of a failed job: `no_seamless_candidate` (no version of the image tiled\nseamlessly), `service_unavailable` (the fix could not run for now; try again later),\n`interrupted` (the service stopped while the job ran; start the fix again) and\n`internal_error`.\n"},"ErrorBody":{"type":"object","additionalProperties":false,"required":["code","message","retryable"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string","description":"Plain-language explanation; it may change, do not parse it."},"retryable":{"type":"boolean","description":"True when the same request can succeed later (a new fix, or polling again)."},"details":{"type":"object","description":"Optional machine-readable context, for example `{\"max_side\": 3600}`."}}},"Error":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"}}},"Plans":{"type":"object","additionalProperties":false,"required":["free","fix_credits","pro","topup","enterprise"],"properties":{"fix_credits":{"type":"object","additionalProperties":false,"required":["credits","large_credits","large_above_px"],"description":"What a fix costs, shown before it starts.","properties":{"credits":{"type":"integer","minimum":1,"description":"Credits of a fix."},"large_credits":{"type":"integer","minimum":1,"description":"Credits of a fix of a tile above `large_above_px` on either side."},"large_above_px":{"type":"integer","minimum":1}}},"free":{"type":"object","additionalProperties":false,"required":["signup_credits"],"properties":{"signup_credits":{"type":"integer","minimum":0,"description":"Credits a new account gets once."}}},"pro":{"type":"array","description":"The Pro tiers, from the smallest.","items":{"$ref":"#/components/schemas/ProTier"}},"topup":{"type":"object","additionalProperties":false,"required":["min_credits","max_credits"],"description":"How many top-up credits one purchase takes.","properties":{"min_credits":{"type":"integer","minimum":1},"max_credits":{"type":"integer","minimum":1}}},"enterprise":{"type":"object","additionalProperties":false,"required":["contact"],"properties":{"contact":{"type":"boolean","const":true,"description":"Sold by contact; no self-serve price."}}}}},"ProTier":{"type":"object","additionalProperties":false,"required":["credits","monthly_usd","yearly_monthly_usd","yearly_usd","yearly_credits","topup_usd_per_credit"],"properties":{"credits":{"type":"integer","description":"Credits a month; also the tier's id (`tier` in `GET /v1/me`)."},"monthly_usd":{"type":"number","description":"Price of a month, billed monthly."},"yearly_monthly_usd":{"type":"number","description":"Monthly equivalent of the yearly price."},"yearly_usd":{"type":"number","description":"The yearly price, billed once a year."},"yearly_credits":{"type":"integer","description":"Credits granted at each yearly invoice."},"topup_usd_per_credit":{"type":"number","description":"Price of one top-up credit on this tier."}}},"PlanName":{"type":"string","enum":["free","pro","enterprise"]},"Me":{"type":"object","additionalProperties":false,"required":["account_id","email","plan","tier","interval","subscription_status","unlimited","credits","period_credits","credits_used_this_period","current_period_start","current_period_end"],"properties":{"account_id":{"type":"string"},"email":{"type":["string","null"]},"plan":{"$ref":"#/components/schemas/PlanName"},"tier":{"type":["integer","null"],"description":"The Pro tier (its monthly credits); null on other plans."},"interval":{"type":["string","null"],"enum":["month","year",null]},"subscription_status":{"type":["string","null"],"description":"The subscription's status: `active`, `past_due`, `cancelled`, `incomplete`, `expired`, `unpaid` or `paused`; null without one. The plan is Pro while it is `active` or `past_due`."},"unlimited":{"type":"boolean","description":"True when fixes cost no credit."},"credits":{"$ref":"#/components/schemas/Credits"},"period_credits":{"type":["integer","null"],"description":"The plan's allowance; for a monthly plan the plan credits each paid invoice sets, for a yearly plan the year's credits as written (plan credits left plus used this period, so credits an upgrade carried in count); null off Pro."},"credits_used_this_period":{"type":"integer","minimum":0,"description":"Plan credits spent since the last paid invoice."},"current_period_start":{"type":["string","null"],"format":"date-time"},"current_period_end":{"type":["string","null"],"format":"date-time","description":"When the plan renews, or ends when a cancellation is set; null off Pro."}}},"Credits":{"type":"object","additionalProperties":false,"required":["subscription","bonus","topup","total"],"description":"Credits left by kind, in the order fixes spend them.","properties":{"subscription":{"type":"integer","minimum":0},"bonus":{"type":"integer","minimum":0,"description":"Signup credits."},"topup":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}}}}}}