{"components":{"schemas":{"Account":{"properties":{"active_jobs":{"description":"The account's unfinished jobs (queued or running) right now.","minimum":0,"type":"integer"},"active_jobs_max":{"description":"How many unfinished jobs the account may have at once. Each account has its own number: 3 by default, 5 or 10 on request. A further submission gets 429 `too_many_active_jobs`.","minimum":1,"type":"integer"},"credits_available":{"type":"integer"},"credits_balance":{"type":"integer"},"credits_held":{"type":"integer"},"limits":{"properties":{"active_jobs":{"description":"The same number as `active_jobs_max`.","type":"integer"},"idempotency_ttl_seconds":{"type":"integer"},"job_cost":{"type":"integer"},"max_upload_bytes":{"type":"integer"},"max_upload_pixels":{"type":"integer"},"reads_per_minute":{"type":"integer"},"result_ttl_seconds":{"type":"integer"},"submissions_per_minute":{"type":"integer"}},"type":"object"}},"required":["credits_balance","credits_held","credits_available","active_jobs","active_jobs_max","limits"],"type":"object"},"Job":{"properties":{"created_at":{"format":"date-time","type":"string"},"credits_charged":{"minimum":0,"type":"integer"},"error":{"properties":{"code":{"enum":["processing_failed","interrupted"],"type":"string"},"detail":{"type":"string"}},"required":["code","detail"],"type":["object","null"]},"finished_at":{"format":"date-time","type":["string","null"]},"id":{"pattern":"^job_[0-9a-f]{32}$","type":"string"},"options":{"properties":{"background":{"enum":["keep","remove"],"type":"string"},"colors":{"type":["integer","null"]},"dpi":{"type":"integer"},"format":{"enum":["svg","pdf","eps","png"],"type":"string"},"size":{"type":"string"}},"required":["format","size","colors","background"],"type":"object"},"phase":{"enum":["queued","analysing","building","finishing",null],"type":["string","null"]},"progress":{"maximum":100,"minimum":0,"type":["integer","null"]},"result":{"properties":{"background_removed":{"type":"boolean"},"bytes":{"type":"integer"},"colors":{"type":"integer"},"expires_at":{"format":"date-time","type":"string"},"format":{"enum":["svg","pdf","eps","png"],"type":"string"},"height":{"type":"integer"},"url":{"format":"uri","type":"string"},"width":{"type":"integer"}},"required":["format","width","height","bytes","colors","background_removed","url","expires_at"],"type":["object","null"]},"status":{"enum":["queued","running","succeeded","failed","canceled"],"type":"string"}},"required":["id","status","phase","progress","created_at","finished_at","options","credits_charged","result","error"],"type":"object"},"Problem":{"properties":{"code":{"enum":["unauthenticated","account_disabled","insufficient_credits","invalid_parameter","image_too_large","unsupported_image","rate_limited","too_many_active_jobs","server_busy","idempotency_key_reused","not_found","method_not_allowed","result_not_ready","job_not_cancelable","result_expired","internal_error"],"type":"string"},"detail":{"type":"string"},"param":{"type":"string"},"status":{"type":"integer"},"title":{"type":"string"},"type":{"format":"uri","type":"string"}},"required":["type","title","status","detail","code"],"type":"object"}},"securitySchemes":{"apiKey":{"description":"An API key from your account page, sent as `Authorization: Bearer <key>`. Keep it on your server.","scheme":"bearer","type":"http"}}},"info":{"contact":{"email":"support@optracy.com"},"description":"Send an image from your own software and get one print file back: SVG, PDF, EPS or a print PNG. A job that succeeds costs 1 credit; a job that fails, is canceled or is interrupted costs nothing. Errors are application/problem+json with a stable `code`, explained at https://optracy.com/docs/api#errors.","title":"Optracy processing API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/v1/account":{"get":{"description":"The credits of the key's account (balance, held by unfinished jobs, available), its unfinished jobs and how many it may have at once, and the limits that apply to it.","operationId":"getAccount","responses":{"200":{"content":{"application/json":{"example":{"active_jobs":1,"active_jobs_max":3,"credits_available":119,"credits_balance":120,"credits_held":1,"limits":{"active_jobs":3,"idempotency_ttl_seconds":86400,"job_cost":1,"max_upload_bytes":31457280,"max_upload_pixels":3000000,"reads_per_minute":120,"result_ttl_seconds":86400,"submissions_per_minute":10}},"schema":{"$ref":"#/components/schemas/Account"}}},"description":"Credits, unfinished jobs and limits."},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unauthenticated`: Authentication required","headers":{"WWW-Authenticate":{"description":"`Bearer realm=\"optracy\"`, with `error=\"invalid_token\"` when a key was sent.","schema":{"type":"string"}}}},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`account_disabled`: Account disabled"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`internal_error`: Internal error"}},"summary":"Read your credits and limits"}},"/v1/jobs":{"post":{"description":"Sends one image with the options of the file you want. The answer comes at once with the job (202); the file is made in the background. 1 credit is held while the job runs and charged only when it succeeds. An account may have 3 unfinished jobs at once unless it was given a higher number (`active_jobs_max` of `GET /v1/account`).","operationId":"createJob","parameters":[{"description":"Optional. 1 to 255 letters, digits and `. _ : -` (a UUID works). The same image with the same options and the same key within 24 hours returns the first job instead of starting a new one.","in":"header","name":"Idempotency-Key","required":false,"schema":{"pattern":"^\"?[A-Za-z0-9._:-]{1,255}\"?$","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"properties":{"background":{"default":"keep","description":"`keep`, or `remove`: the background color is left out of a vector file and transparent in a PNG. When removing it would leave nothing, nothing is removed; `result.background_removed` says what happened.","enum":["keep","remove"],"type":"string"},"colors":{"description":"Empty for automatic, or the number of flat colors you want, 1 to 1,000. An image with fewer colors keeps the ones it has; `result.colors` says how many the file has.","maximum":1000,"minimum":1,"type":"integer"},"dpi":{"default":300,"description":"Only with an explicit `size`: the resolution the file states, 1 to 10,000.","maximum":10000,"minimum":1,"type":"integer"},"format":{"description":"The file you get: `svg`, `pdf`, `eps`, or `png`, a print PNG at 300 dpi.","enum":["svg","pdf","eps","png"],"type":"string"},"image":{"contentMediaType":"application/octet-stream","description":"The image: PNG, JPEG, GIF, BMP or WebP, at most 3 megapixels, each side at least 16 px and the long side at most 20 times the short one. The whole request is at most 30 MB.","type":"string"},"size":{"default":"original","description":"`original`, or `<width>x<height>` in pixels: each side 1 to 20,000 and at most 40 megapixels in all. The design is fitted inside with its proportions kept. A `png` of size `original` is the print canvas, 4,500 \u00d7 5,400 px at 300 dpi.","pattern":"^(original|[0-9]{1,6}[xX][0-9]{1,6})$","type":"string"}},"required":["image","format"],"type":"object"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"created_at":"2026-10-06T08:00:00Z","credits_charged":0,"error":null,"finished_at":null,"id":"job_8f14e45fceea167a5a36dedd4bea2543","options":{"background":"keep","colors":null,"format":"svg","size":"original"},"phase":"queued","progress":0,"result":null,"status":"queued"},"schema":{"$ref":"#/components/schemas/Job"}}},"description":"The job was accepted (or, with a repeated Idempotency-Key, the first job).","headers":{"Idempotent-Replayed":{"description":"`true` when a repeated Idempotency-Key returned the first job.","schema":{"type":"string"}},"Location":{"description":"The address of the new job.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_parameter`: Invalid parameter"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unauthenticated`: Authentication required","headers":{"WWW-Authenticate":{"description":"`Bearer realm=\"optracy\"`, with `error=\"invalid_token\"` when a key was sent.","schema":{"type":"string"}}}},"402":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`insufficient_credits`: Not enough credits"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`account_disabled`: Account disabled"},"413":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`image_too_large`: Image too large"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unsupported_image`: Unsupported image; `idempotency_key_reused`: Idempotency key reused"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: Too many requests; `too_many_active_jobs`: Too many unfinished jobs","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`internal_error`: Internal error"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`server_busy`: Server busy","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}}},"summary":"Submit an image"}},"/v1/jobs/{job_id}":{"get":{"description":"The job's status, its phase and progress while it runs, and its result or error once it has ended. While it runs, ask again after the seconds in `Retry-After`.","operationId":"getJob","parameters":[{"description":"The job's `id`, as the submission returned it.","in":"path","name":"job_id","required":true,"schema":{"pattern":"^job_[0-9a-f]{32}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"failed":{"value":{"created_at":"2026-10-06T08:00:00Z","credits_charged":0,"error":{"code":"processing_failed","detail":"The image could not be processed. No credit was charged."},"finished_at":"2026-10-06T08:00:09Z","id":"job_8f14e45fceea167a5a36dedd4bea2543","options":{"background":"keep","colors":null,"format":"svg","size":"original"},"phase":null,"progress":null,"result":null,"status":"failed"}},"running":{"value":{"created_at":"2026-10-06T08:00:00Z","credits_charged":0,"error":null,"finished_at":null,"id":"job_8f14e45fceea167a5a36dedd4bea2543","options":{"background":"keep","colors":null,"format":"svg","size":"original"},"phase":"building","progress":57,"result":null,"status":"running"}},"succeeded":{"value":{"created_at":"2026-10-06T08:00:00Z","credits_charged":1,"error":null,"finished_at":"2026-10-06T08:00:16Z","id":"job_8f14e45fceea167a5a36dedd4bea2543","options":{"background":"keep","colors":null,"format":"svg","size":"original"},"phase":"finishing","progress":100,"result":{"background_removed":false,"bytes":180651,"colors":13,"expires_at":"2026-10-07T08:00:16Z","format":"svg","height":1448,"url":"https://api.optracy.com/v1/jobs/job_8f14e45fceea167a5a36dedd4bea2543/result","width":1086},"status":"succeeded"}}},"schema":{"$ref":"#/components/schemas/Job"}}},"description":"The job.","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unauthenticated`: Authentication required","headers":{"WWW-Authenticate":{"description":"`Bearer realm=\"optracy\"`, with `error=\"invalid_token\"` when a key was sent.","schema":{"type":"string"}}}},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`account_disabled`: Account disabled"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`not_found`: Not found"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`internal_error`: Internal error"}},"summary":"Read a job"}},"/v1/jobs/{job_id}/cancel":{"post":{"description":"Stops a queued or running job; nothing is charged. Canceling a canceled job again changes nothing; a job that succeeded or failed cannot be canceled (409).","operationId":"cancelJob","parameters":[{"description":"The job's `id`, as the submission returned it.","in":"path","name":"job_id","required":true,"schema":{"pattern":"^job_[0-9a-f]{32}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"created_at":"2026-10-06T08:00:00Z","credits_charged":0,"error":null,"finished_at":"2026-10-06T08:00:05Z","id":"job_8f14e45fceea167a5a36dedd4bea2543","options":{"background":"keep","colors":null,"format":"svg","size":"original"},"phase":null,"progress":null,"result":null,"status":"canceled"},"schema":{"$ref":"#/components/schemas/Job"}}},"description":"The job, canceled."},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unauthenticated`: Authentication required","headers":{"WWW-Authenticate":{"description":"`Bearer realm=\"optracy\"`, with `error=\"invalid_token\"` when a key was sent.","schema":{"type":"string"}}}},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`account_disabled`: Account disabled"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`not_found`: Not found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`job_not_cancelable`: Job cannot be canceled"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`internal_error`: Internal error"}},"summary":"Cancel a job"}},"/v1/jobs/{job_id}/result":{"get":{"description":"The file of a job that succeeded, as an attachment. It is kept 24 hours after the job ends; after that the answer is 410.","operationId":"getResult","parameters":[{"description":"The job's `id`, as the submission returned it.","in":"path","name":"job_id","required":true,"schema":{"pattern":"^job_[0-9a-f]{32}$","type":"string"}}],"responses":{"200":{"content":{"application/pdf":{},"application/postscript":{},"image/png":{},"image/svg+xml":{}},"description":"The file, in the format the job asked for.","headers":{"Content-Disposition":{"description":"`attachment; filename=\"<job id>.<format>\"`.","schema":{"type":"string"}}}},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unauthenticated`: Authentication required","headers":{"WWW-Authenticate":{"description":"`Bearer realm=\"optracy\"`, with `error=\"invalid_token\"` when a key was sent.","schema":{"type":"string"}}}},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`account_disabled`: Account disabled"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`not_found`: Not found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`result_not_ready`: Result not ready"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`result_expired`: Result expired"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}}}},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`internal_error`: Internal error"}},"summary":"Download the file"}},"/v1/openapi.json":{"get":{"description":"The OpenAPI 3.1 description of the API, for your own tools. No key needed.","operationId":"getOpenapi","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"The OpenAPI document."},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`internal_error`: Internal error"}},"security":[],"summary":"Read this description"}}},"security":[{"apiKey":[]}],"servers":[{"url":"https://api.optracy.com"}]}
