{"openapi":"3.1.0","info":{"title":"Demarker API","description":"Identify what an AI image carries, then clean it. One credit is one QUICK image at 12 MP or less. Endpoints return the price table with every identify, so clients never compute prices.","version":"1.0.0","x-errors-reference":"/api/v1/errors"},"servers":[{"url":"/api/v1","description":"This deployment"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Upload","description":"Presigned image upload"},{"name":"Jobs","description":"Identify, process, fetch and delete"},{"name":"Account","description":"Balance and prices"},{"name":"Webhooks","description":"Event notifications"}],"paths":{"/upload":{"post":{"operationId":"createUpload","summary":"Get a presigned upload URL","description":"Returns a URL valid for 15 minutes. PUT the image with the returned Content-Type, then call /identify with the uploadKey. A key works once and only for the account that requested it.","tags":["Upload"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filename"],"properties":{"filename":{"type":"string"},"contentType":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"uploadUrl":{"type":"string"},"uploadKey":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"maxFileSizeBytes":{"type":"integer"},"contentType":{"type":"string"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/identify":{"post":{"operationId":"identifyImage","summary":"Identify an uploaded image (free)","description":"Creates the job and runs the free identify step. Waits up to 5 seconds. If identify is slower, responds 202 with the job id; poll GET /jobs/{id}. A refused image returns status REFUSED with refusalReason. Send an Idempotency-Key header to make retries safe.","tags":["Jobs"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uploadKey"],"properties":{"uploadKey":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"202":{"description":"Identify is still running","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/jobs":{"get":{"operationId":"listJobs","summary":"List jobs","description":"Newest first.","tags":["Jobs"],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"total":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"createJob","summary":"One-shot identify and process (not available yet)","description":"Returns 501. Use /identify then /jobs/{id}/process.","tags":["Jobs"],"responses":{"501":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}}}},"/jobs/{id}":{"get":{"operationId":"getJob","summary":"Get a job","description":"Status, report, offers and, when completed, a URL for the result valid for one hour (outputs.image).","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"default":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"deleteJob","summary":"Delete a job now","description":"Deletes the original and the result at once. Credits are refunded while the job is PENDING. A running job returns 409.","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"creditsRefunded":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/jobs/{id}/process":{"post":{"operationId":"processJob","summary":"Process an identified job","description":"Debits the offer for the chosen tier. A short balance returns 402 with requiredCredits, balance and purchaseUrl; the job stays IDENTIFIED. Images over 25 MP cannot be processed. rightsAttested must be true.","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tier","rightsAttested"],"properties":{"tier":{"type":"string","enum":["QUICK","GPU"]},"keepResolution":{"type":"boolean","description":"Keep original size above 12 MP. Priced at the large band."},"vendorHint":{"type":"string","description":"Where the image was made, for the GPU tier when identify found no hidden target."},"force":{"type":"boolean"},"marks":{"type":"array","items":{"type":"string"},"description":"Registry keys to remove. Defaults to all allowed."},"secondAttestation":{"type":"string"},"rightsAttested":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"402":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"451":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}}}},"/balance":{"get":{"operationId":"getBalance","summary":"Get credit balance","description":"","tags":["Account"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"balanceCredits":{"type":"integer"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/pricing":{"get":{"operationId":"getPricing","summary":"Get the price table","description":"Public. Credits per tier and band, and the credit packs.","tags":["Account"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"$ref":"#/components/responses/Error"}},"security":[]}},"/webhooks":{"get":{"operationId":"listWebhooks","summary":"List webhooks","description":"","tags":["Webhooks"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"createWebhook","summary":"Create a webhook","description":"https URLs only. The signing secret is shown once.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["job.identified","job.refused","job.process_blocked","job.completed","job.failed"]}}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"201":{"description":"Created"},"default":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}":{"delete":{"operationId":"deleteWebhook","summary":"Delete a webhook","description":"","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/errors":{"get":{"operationId":"listErrors","summary":"Error catalog","description":"Every error code with its resolution. Public.","tags":["Account"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"default":{"$ref":"#/components/responses/Error"}},"security":[]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Bearer sk_live_... key from Settings, API."}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"resolution":{"type":"string"},"docs":{"type":"string"}}}}}}}}},"schemas":{"Job":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["UPLOADED","IDENTIFYING","IDENTIFIED","HELD","PENDING","PROCESSING","COMPLETED","FAILED","REFUSED","EXPIRED"]},"width":{"type":"integer"},"height":{"type":"integer"},"megapixels":{"type":"number"},"hasInvisibleTarget":{"type":["boolean","null"]},"report":{"type":["object","null"],"description":"Engine provenance report, schema_version 1."},"cmiFields":{"description":"Author and copyright fields found. They are kept."},"offers":{"type":["array","null"],"items":{"type":"object","properties":{"tier":{"type":"string"},"keepResolution":{"type":"boolean"},"credits":{"type":"integer"}}}},"balance":{"type":"integer"},"refusalReason":{"type":["string","null"],"enum":["NSFW","THIRD_PARTY_OVERLAY",null]},"creditsCharged":{"type":"integer"},"errorCode":{"type":["string","null"]},"outputs":{"type":"object","properties":{"image":{"type":["string","null"],"format":"uri"}}},"createdAt":{"type":"string","format":"date-time"}}}}}}