{"openapi":"3.1.0","info":{"title":"Sequency Labs reactions API","description":"Ask the lab for reactions and get back what it measured, with the evidence behind each number. Customers ask for jobs and follow them. The lab's own systems send the files and records its chemists and instruments make.\n\n- Every call sends an API key as `Authorization: Bearer <key>`. A key acts for a customer or for one of the lab's systems, and the API decides which calls each may make.\n- Fields are snake_case. Units are in their names: `_mg`, `_mmol`, `_ml`, `_c`, `_h` and `_pct`.\n- Instants are RFC 3339 and end in `_at`. Responses give them in UTC.\n- A field the schema does not mark as required may be left out. Only a field marked nullable may be null. A response writes every field, null when unknown.\n- A field the schema does not define is an error, so a misspelled field fails rather than vanishing.\n- A job's ID is a TypeID, such as `job_01h455vb4pex5vsknk084sn02q`: `job_` and the job's UUID in base32.\n- Every error is an RFC 9457 problem, sent as `application/problem+json`, whose `detail` says what went wrong.","version":"1"},"paths":{"/v1/credits":{"get":{"tags":["credits"],"summary":"Get the customer's credits.","description":"Only a customer's key may. A job holds the most it may cost from the balance until it completes, then gives back\nwhat it did not cost.","operationId":"get_credits","responses":{"200":{"description":"The customer's balance, and what this key may still spend","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credits"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a customer's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/entries/{key}":{"put":{"tags":["lab"],"summary":"Send an ELN entry.","description":"Send its files first. An entry for a job starts the job, so its customer can no longer cancel it.","operationId":"put_entry","parameters":[{"name":"key","in":"path","required":true,"schema":{"$ref":"#/components/schemas/RecordKey"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entry"}}},"required":true},"responses":{"200":{"description":"The entry is the same as the last one sent"},"201":{"description":"The entry is new, or changed"},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a lab system's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"The body is larger than 1 MiB.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"The body is not sent as `application/json`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The entry does not parse, names a file not yet sent, or names a job that does not exist or was canceled","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/files/{sha256}":{"put":{"tags":["lab"],"summary":"Send a file.","description":"The body is the file's bytes, with its `Content-Length`, and its `Content-Type` when known. The store checks that\nthe bytes hash to the URL's SHA-256.","operationId":"put_file","parameters":[{"name":"sha256","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Sha256"}}],"requestBody":{"description":"The file's bytes","content":{"*/*":{"schema":{"type":"array","items":{"type":"integer","format":"int32","minimum":0}}}},"required":true},"responses":{"200":{"description":"The store already held the file"},"201":{"description":"The store now holds the file"},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a lab system's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"411":{"description":"The request has no `Content-Length`","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The URL does not parse, or the bytes do not hash to its SHA-256","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"head":{"tags":["lab"],"summary":"Whether the lab's file store holds a file.","description":"Ask before sending a file, to skip sending one the store already holds.","operationId":"has_file","parameters":[{"name":"sha256","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Sha256"}}],"responses":{"200":{"description":"The store holds the file"},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a lab system's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"The store does not hold the file","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs":{"get":{"tags":["jobs"],"summary":"List jobs, newest first.","description":"A customer's key lists its own jobs. A lab system's key lists every job not canceled.","operationId":"list_jobs","parameters":[{"name":"before","in":"query","description":"List only jobs older than this one: the `next` of the page before.","required":false,"schema":{"$ref":"#/components/schemas/JobId"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","description":"How many jobs a page holds, from 1 to 100. It is 20 when not given.","maximum":100,"minimum":1}}],"responses":{"200":{"description":"A page of jobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobList"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["jobs"],"summary":"Ask for a job.","description":"Only a customer's key may ask. The job holds the most it may cost from the customer's credits until it completes:\neach reaction at its kind's rate (`GET /v1/prices`), or a synthesis's `max_credits`. To retry a call that may have\nfailed, such as one that timed out, send it again with the same `Idempotency-Key`: that gives back the job the first\ncall made rather than a second one.","operationId":"create_job","parameters":[{"name":"Idempotency-Key","in":"header","description":"1 to 255 visible ASCII characters that name this request","required":false,"schema":{"type":["string","null"]}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobRequest"}}},"required":true},"responses":{"201":{"description":"The job, new or made by an earlier call with the same idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"The job may cost more than the balance, or than is left of the key's limit","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a customer's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The idempotency key was used for a different request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"The body is larger than 1 MiB.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"The body is not sent as `application/json`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"This kind of job has no price yet","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}":{"get":{"tags":["jobs"],"summary":"Get a job.","operationId":"get_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/JobId"}}],"responses":{"200":{"description":"The job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such job, or not one this key may see","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/cancel":{"post":{"tags":["jobs"],"summary":"Cancel a job.","description":"A job can be canceled until the lab starts it. Canceling a canceled job changes nothing.","operationId":"cancel_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/JobId"}}],"responses":{"200":{"description":"The canceled job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a customer's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such job of this customer's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The lab has started the job","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/finish":{"post":{"tags":["lab"],"summary":"Say a job's records are all sent.","description":"Send this once the lab has sent the last record for a job it started, so the job can be packaged. Saying it again\nchanges nothing. The job stays `running` until its package is ready.","operationId":"finish_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/JobId"}}],"responses":{"204":{"description":"The job's records are all sent"},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a lab system's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such job, or the lab has not started it","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/package":{"get":{"tags":["jobs"],"summary":"Get a complete job's package.","description":"Only the job's customer may.","operationId":"get_package","parameters":[{"name":"id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/JobId"}}],"responses":{"200":{"description":"The job's files, rewards and review","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Package"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such job of this customer's, or it is not complete","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/package/files/{path}":{"get":{"tags":["jobs"],"summary":"Download a file of a job's package.","operationId":"get_package_file","parameters":[{"name":"path","in":"path","description":"The file's `path` in the package, such as `raw/nmr/1.zip`","required":true,"schema":{"$ref":"#/components/schemas/FilePath"}},{"name":"id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/JobId"}}],"responses":{"200":{"description":"The file's bytes. Its ETag is its SHA-256.","content":{"*/*":{}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such file in a package of this customer's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"A parameter or the body does not parse.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/prices":{"get":{"tags":["credits"],"summary":"Get what jobs cost.","operationId":"get_prices","responses":{"200":{"description":"Each kind of job's rate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Prices"}}}},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/runs/{key}":{"put":{"tags":["lab"],"summary":"Send an instrument run.","description":"Send its files first.","operationId":"put_run","parameters":[{"name":"key","in":"path","required":true,"schema":{"$ref":"#/components/schemas/RecordKey"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}},"required":true},"responses":{"200":{"description":"The run is the same as the last one sent"},"201":{"description":"The run is new, or changed"},"401":{"description":"Send a valid API key as `Authorization: Bearer <key>`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is not a lab system's","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"The body is larger than 1 MiB.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"The body is not sent as `application/json`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The run does not parse, or names a file not yet sent","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Something went wrong on our side.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"schemas":{"Celsius":{"type":"number","format":"double","description":"A temperature in degrees Celsius, from absolute zero to 5000.","maximum":5000,"minimum":-273.15},"Confidence":{"type":"string","description":"How sure a chemist is that something will work.","enum":["high","medium","low"]},"Credits":{"type":"object","description":"A customer's credits, as one of its keys sees them.","required":["balance","key_spent"],"properties":{"balance":{"type":"number","format":"double","description":"The credits the customer has bought that no job holds or has cost. A correction of ours may take it below zero."},"key_limit":{"oneOf":[{"$ref":"#/components/schemas/Positive","description":"The most this key's jobs may hold or cost in total. It is null when they may spend the whole balance."},{"type":"null"}]},"key_spent":{"$ref":"#/components/schemas/NonNegative","description":"What this key's jobs hold or have cost."}},"additionalProperties":false},"Entry":{"type":"object","description":"An ELN entry: one experiment as its chemist recorded it.","required":["title","chemist","started_at","outcome","procedure","language","materials","products"],"properties":{"ambient_temp_c":{"oneOf":[{"$ref":"#/components/schemas/Celsius"},{"type":"null"}]},"chemist":{"$ref":"#/components/schemas/Name","description":"The chemist's ID in the lab's system, never their name."},"files":{"type":"array","items":{"$ref":"#/components/schemas/FileRef"},"description":"Notebook pages, photos and TLC plates. Send each file first."},"finished_at":{"type":["string","null"],"format":"date-time"},"humidity_pct":{"oneOf":[{"$ref":"#/components/schemas/Percent"},{"type":"null"}]},"job":{"oneOf":[{"$ref":"#/components/schemas/JobLink","description":"The job this experiment ran for. Sending it starts the job."},{"type":"null"}]},"language":{"$ref":"#/components/schemas/Language","description":"The language the entry is written in."},"log":{"type":"array","items":{"$ref":"#/components/schemas/LogLine"}},"materials":{"$ref":"#/components/schemas/NonEmpty_Input","description":"What went into the experiment."},"outcome":{"$ref":"#/components/schemas/Outcome"},"procedure":{"$ref":"#/components/schemas/Text"},"products":{"$ref":"#/components/schemas/NonEmpty_Product","description":"What the experiment made, or meant to."},"started_at":{"type":"string","format":"date-time"},"title":{"$ref":"#/components/schemas/Name"}},"additionalProperties":false},"FilePath":{"type":"string","description":"A file's path within a record or a package, such as `notebook/page-1.jpg`: relative, with no empty or `..`\npart and no control characters.","pattern":"^(?!\\.\\.(/|$))(?!.*/\\.\\.(/|$))[^/\\u0000-\\u001f\\u007f-\\u009f]+(/[^/\\u0000-\\u001f\\u007f-\\u009f]+)*$"},"FileRef":{"type":"object","description":"A file a record names. Send the file to `/v1/files/{sha256}` before the record.","required":["path","sha256"],"properties":{"path":{"$ref":"#/components/schemas/FilePath"},"sha256":{"$ref":"#/components/schemas/Sha256"}},"additionalProperties":false},"Input":{"type":"object","description":"A material that went into the experiment.","required":["role","name","smiles"],"properties":{"amount_mmol":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]},"cas":{"oneOf":[{"$ref":"#/components/schemas/Name"},{"type":"null"}]},"equivalents":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]},"mass_mg":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]},"name":{"$ref":"#/components/schemas/Name"},"note":{"oneOf":[{"$ref":"#/components/schemas/Text"},{"type":"null"}]},"role":{"$ref":"#/components/schemas/Role"},"smiles":{"$ref":"#/components/schemas/Smiles"},"supplier":{"oneOf":[{"$ref":"#/components/schemas/Name"},{"type":"null"}]},"volume_ml":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]}},"additionalProperties":false},"Job":{"type":"object","description":"A job and where it is.","required":["id","status","request","created_at"],"properties":{"canceled_at":{"type":["string","null"],"format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"credits":{"oneOf":[{"$ref":"#/components/schemas/NonNegative","description":"What the job holds until it completes, then what it cost, in credits. It is null for a lab system's key."},{"type":"null"}]},"id":{"$ref":"#/components/schemas/JobId"},"request":{"$ref":"#/components/schemas/JobRequest","description":"The request as the API accepted it."},"started_at":{"type":["string","null"],"format":"date-time"},"status":{"$ref":"#/components/schemas/JobStatus"}},"additionalProperties":false},"JobId":{"type":"string","description":"A job's ID: `job_` and then the job's UUID in 26 characters of base32, as a TypeID\n(github.com/jetify-com/typeid).","example":"job_01h455vb4pex5vsknk084sn02q","pattern":"^job_[0-7][0-9a-hjkmnp-tv-z]{25}$"},"JobLink":{"type":"object","description":"The job an entry ran for.","required":["id"],"properties":{"id":{"$ref":"#/components/schemas/JobId"},"reaction":{"oneOf":[{"$ref":"#/components/schemas/Name","description":"The ID of the job's reaction this ran."},{"type":"null"}]}},"additionalProperties":false},"JobList":{"type":"object","description":"A page of jobs, newest first.","required":["jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"next":{"oneOf":[{"$ref":"#/components/schemas/JobId","description":"Pass it as `before` for the next page. It is null on the last page."},{"type":"null"}]}},"additionalProperties":false},"JobRequest":{"type":"object","description":"What a customer asks the lab to do.","required":["exclusive","reuse","work"],"properties":{"exclusive":{"type":"boolean","description":"Whether only this customer may ever see the job's results. It cannot change later."},"reuse":{"type":"boolean","description":"Whether the lab may hand back results it already measured for the same reaction, at the reuse rate, instead of\nrunning it again."},"work":{"$ref":"#/components/schemas/Work"}},"additionalProperties":false},"JobStatus":{"type":"string","description":"Where a job is. The database works it out; a job starts when the lab sends its first record for it.","enum":["queued","running","completed","canceled"]},"Language":{"type":"string","description":"A language as its ISO 639-1 code, such as `zh` or `en`.","pattern":"^[a-z]{2}$"},"LogLine":{"type":"object","description":"A line of the experiment's log.","required":["occurred_at","text"],"properties":{"occurred_at":{"type":"string","format":"date-time"},"text":{"$ref":"#/components/schemas/Text"}},"additionalProperties":false},"Measure":{"type":"string","description":"What can be measured of a reaction's product, each as a percentage.","enum":["yield_pct","conversion_pct","purity_pct"]},"Name":{"type":"string","description":"A short name, such as a reaction's ID or a chemist's: 1 to 200 printable characters, not all spaces.","maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f-\\u009f]*[^\\s\\u0000-\\u001f\\u007f-\\u009f][^\\u0000-\\u001f\\u007f-\\u009f]*$"},"NonEmpty_FileRef":{"type":"array","items":{"$ref":"#/components/schemas/FileRef"},"minItems":1},"NonEmpty_Input":{"type":"array","items":{"$ref":"#/components/schemas/Input"},"minItems":1},"NonEmpty_PlannedMaterial":{"type":"array","items":{"$ref":"#/components/schemas/PlannedMaterial"},"minItems":1},"NonEmpty_Product":{"type":"array","items":{"$ref":"#/components/schemas/Product"},"minItems":1},"NonEmpty_Reaction":{"type":"array","items":{"$ref":"#/components/schemas/Reaction"},"minItems":1},"NonNegative":{"type":"number","format":"double","description":"An amount of zero or more, up to 10¹².","maximum":1000000000000,"minimum":0},"Outcome":{"type":"string","description":"How the experiment went, in its chemist's judgment.","enum":["success","failure","uncertain"]},"Package":{"type":"object","description":"What a complete job hands back: its files, its rewards and, for a route review, the chemist's review.","required":["files","rewards"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/PackageFile"},"description":"Reaction records in Open Reaction Database form under `ord/`, instrument files under `raw/` and notebook pages\nunder `notebook/`."},"review":{"oneOf":[{"$ref":"#/components/schemas/Review","description":"What the chemist made of the route. It is null for any job but a route review."},{"type":"null"}]},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/Reward"}}},"additionalProperties":false},"PackageFile":{"type":"object","description":"One file of a package. Download it at `/v1/jobs/{id}/package/files/{path}`.","required":["path","sha256","size_bytes","media_type"],"properties":{"media_type":{"$ref":"#/components/schemas/Name"},"path":{"$ref":"#/components/schemas/FilePath"},"sha256":{"$ref":"#/components/schemas/Sha256"},"size_bytes":{"type":"integer","format":"int64","minimum":0}},"additionalProperties":false},"Percent":{"type":"number","format":"double","description":"A percentage, from 0 to 100.","maximum":100,"minimum":0},"PlannedMaterial":{"type":"object","description":"A material a reaction is planned with.","required":["role","smiles"],"properties":{"equivalents":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]},"name":{"oneOf":[{"$ref":"#/components/schemas/Name"},{"type":"null"}]},"role":{"$ref":"#/components/schemas/Role"},"smiles":{"$ref":"#/components/schemas/Smiles"},"volume_ml":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]}},"additionalProperties":false},"Positive":{"type":"number","format":"double","description":"An amount greater than zero, up to 10¹².","maximum":1000000000000,"exclusiveMinimum":0},"Prices":{"type":"object","description":"What jobs cost now.","required":["rates"],"properties":{"rates":{"type":"array","items":{"$ref":"#/components/schemas/Rate"},"description":"One for each kind of job, exclusive or not, that the lab takes. A kind without one cannot be asked for yet."}},"additionalProperties":false},"Problem":{"type":"object","description":"What went wrong, as RFC 9457 describes. Every error response carries one, as `application/problem+json`.","required":["type","title","status","detail"],"properties":{"detail":{"type":"string","description":"What went wrong with this request, in words."},"status":{"type":"integer","format":"int32","minimum":0},"title":{"type":"string","description":"The status's name, such as \"Not Found\"."},"type":{"type":"string","description":"Always `about:blank`: the status says what kind of problem it is."}},"additionalProperties":false},"Product":{"type":"object","description":"A product the experiment made, or meant to.","required":["name","smiles","is_desired","mass_mg"],"properties":{"conversion_pct":{"oneOf":[{"$ref":"#/components/schemas/Percent"},{"type":"null"}]},"is_desired":{"type":"boolean","description":"Whether this is the product the experiment was for, rather than a side product."},"mass_mg":{"$ref":"#/components/schemas/NonNegative","description":"What was isolated: 0 when nothing was."},"name":{"$ref":"#/components/schemas/Name"},"note":{"oneOf":[{"$ref":"#/components/schemas/Text"},{"type":"null"}]},"smiles":{"$ref":"#/components/schemas/Smiles"},"theoretical_mg":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]},"yield_pct":{"oneOf":[{"$ref":"#/components/schemas/NonNegative"},{"type":"null"}]}},"additionalProperties":false},"Rate":{"type":"object","description":"What one reaction of a kind of job costs, in credits. A new job holds each of its reactions at `reaction`, or a\nsynthesis its `max_credits`, and costs no more than that once it completes.","required":["kind","exclusive","reaction","reused_reaction"],"properties":{"exclusive":{"type":"boolean","description":"Whether this is the rate for exclusive jobs."},"kind":{"$ref":"#/components/schemas/WorkKind"},"reaction":{"$ref":"#/components/schemas/NonNegative","description":"What a reaction the lab runs costs."},"reused_reaction":{"$ref":"#/components/schemas/NonNegative","description":"What a reaction costs when the lab hands back results it already measured, for a job that allows `reuse`."}},"additionalProperties":false},"Reaction":{"type":"object","description":"One reaction the customer asks for.","required":["id","materials","product_smiles"],"properties":{"id":{"$ref":"#/components/schemas/Name","description":"The customer's own name for the reaction, unique within the job. Its rewards carry it."},"materials":{"$ref":"#/components/schemas/NonEmpty_PlannedMaterial"},"procedure":{"oneOf":[{"$ref":"#/components/schemas/Text"},{"type":"null"}]},"product_smiles":{"$ref":"#/components/schemas/Smiles"},"scale_mmol":{"oneOf":[{"$ref":"#/components/schemas/Positive","description":"The amount of the limiting reactant. The lab chooses it when absent."},{"type":"null"}]},"temperature_c":{"oneOf":[{"$ref":"#/components/schemas/Celsius"},{"type":"null"}]},"time_h":{"oneOf":[{"$ref":"#/components/schemas/Positive"},{"type":"null"}]}},"additionalProperties":false},"ReactionReview":{"type":"object","description":"A chemist's judgment of one reaction of a route.","required":["reaction","confidence"],"properties":{"confidence":{"$ref":"#/components/schemas/Confidence","description":"How sure the chemist is that the reaction works as the route asks."},"reaction":{"$ref":"#/components/schemas/Name","description":"The ID of the request's reaction this is for."},"reason":{"oneOf":[{"$ref":"#/components/schemas/Text","description":"Why the chemist judged it so. It is null when they gave no reason."},{"type":"null"}]}},"additionalProperties":false},"Reactions":{"$ref":"#/components/schemas/NonEmpty_Reaction","description":"At least one reaction, with unique IDs, so that a reward can name one."},"RecordKey":{"type":"string","description":"The lab system's own key for a record, such as its ELN's entry number: a name with no slash.","maxLength":200,"pattern":"^[^/\\u0000-\\u001f\\u007f-\\u009f]*[^/\\s\\u0000-\\u001f\\u007f-\\u009f][^/\\u0000-\\u001f\\u007f-\\u009f]*$"},"RecordRef":{"type":"object","description":"A record another of the lab's systems sent, or will send: it may arrive after the record that names it.","required":["system","key"],"properties":{"key":{"$ref":"#/components/schemas/RecordKey"},"system":{"$ref":"#/components/schemas/Name","description":"The system's ID, as the lab's keys are registered under."}},"additionalProperties":false},"Review":{"type":"object","description":"A chemist's judgment of a route: how sure they are that it gives its target, and what they advise.","required":["confidence","summary","reactions","chemist","site","reviewed_at"],"properties":{"chemist":{"$ref":"#/components/schemas/Name","description":"A pseudonym for the chemist who reviewed it."},"confidence":{"$ref":"#/components/schemas/Confidence","description":"How sure the chemist is that the route as a whole gives its target."},"reactions":{"type":"array","items":{"$ref":"#/components/schemas/ReactionReview"},"description":"One for each of the route's reactions the chemist judged. It may be empty."},"reviewed_at":{"type":"string","format":"date-time"},"site":{"$ref":"#/components/schemas/Name"},"summary":{"$ref":"#/components/schemas/Text","description":"What the chemist advises, in words."}},"additionalProperties":false},"Reward":{"type":"object","description":"What the lab measured and how, and the chain from that number to the raw file, chemist, site and time.","required":["measure","measured","method","source"],"properties":{"measure":{"$ref":"#/components/schemas/Measure"},"measured":{"$ref":"#/components/schemas/NonNegative","description":"What the lab measured."},"method":{"$ref":"#/components/schemas/Text","description":"How the lab measured it, such as \"isolated mass\" or \"HPLC area at 254 nm\"."},"reaction":{"oneOf":[{"$ref":"#/components/schemas/Name","description":"The ID of the request's reaction this is for. It is null for a synthesis's final product."},{"type":"null"}]},"source":{"$ref":"#/components/schemas/RewardSource"}},"additionalProperties":false},"RewardSource":{"type":"object","description":"Where a measurement came from.","required":["experiment_id","file","chemist","site","measured_at"],"properties":{"chemist":{"$ref":"#/components/schemas/Name","description":"A pseudonym for the chemist who measured it."},"experiment_id":{"$ref":"#/components/schemas/Name","description":"The experiment's ID, as our data releases name it."},"file":{"$ref":"#/components/schemas/FilePath","description":"The file in this package that holds the measurement."},"measured_at":{"type":"string","format":"date-time"},"site":{"$ref":"#/components/schemas/Name"}},"additionalProperties":false},"Role":{"type":"string","description":"What a material that goes into a reaction does in it.","enum":["reactant","reagent","catalyst","solvent"]},"Run":{"type":"object","description":"One instrument run and the sample it measured.","required":["entry","sample","technique","instrument","acquired_at","files"],"properties":{"acquired_at":{"type":"string","format":"date-time"},"entry":{"$ref":"#/components/schemas/RecordRef","description":"The ELN entry whose sample this measured."},"files":{"$ref":"#/components/schemas/NonEmpty_FileRef","description":"The run's files. Send each file first."},"instrument":{"$ref":"#/components/schemas/Name"},"sample":{"$ref":"#/components/schemas/Name","description":"The sample's name as the lab labels it."},"technique":{"$ref":"#/components/schemas/Technique"}},"additionalProperties":false},"Sha256":{"type":"string","description":"A file's SHA-256 hash, as 64 lowercase hexadecimal characters. The API names every file by it.","pattern":"^[0-9a-f]{64}$"},"Smiles":{"type":"string","description":"A molecule as SMILES. The lab checks the chemistry; the API checks only that it is printable ASCII without\nspaces.","pattern":"^[!-~]+$"},"Technique":{"type":"string","description":"How a sample was measured.","enum":["nmr_1h","nmr_13c","nmr_qnmr","nmr_other","lcms","hplc","gc","gcms","ms","ir","uv","tlc","other"]},"Text":{"type":"string","description":"Text that says something, such as a procedure: not empty, not all spaces, and with no NUL character. It may\nhold line breaks.","pattern":"^[^\\u0000]*[^\\s\\u0000][^\\u0000]*$"},"Work":{"oneOf":[{"type":"object","description":"Chemists review a route to a target and say what they would change. It hands back their review and no rewards.","required":["target_smiles","route","kind"],"properties":{"kind":{"type":"string","enum":["route_review"]},"route":{"$ref":"#/components/schemas/Reactions","description":"The route's reactions, in order."},"target_smiles":{"$ref":"#/components/schemas/Smiles"}},"additionalProperties":false},{"type":"object","description":"The lab runs each reaction. Each hands back its yield.","required":["reactions","kind"],"properties":{"kind":{"type":"string","enum":["reaction_batch"]},"reactions":{"$ref":"#/components/schemas/Reactions"}},"additionalProperties":false},{"type":"object","description":"The lab runs each reaction as one well of a plate. Each hands back its conversion or yield.","required":["reactions","kind"],"properties":{"kind":{"type":"string","enum":["reaction_screen"]},"reactions":{"$ref":"#/components/schemas/Reactions"}},"additionalProperties":false},{"type":"object","description":"The lab makes an amount of a target at a purity. It hands back the final yield and purity.","required":["target_smiles","amount_mg","purity_pct","max_credits","kind"],"properties":{"amount_mg":{"$ref":"#/components/schemas/Positive"},"kind":{"type":"string","enum":["synthesis"]},"max_credits":{"$ref":"#/components/schemas/Positive","description":"The most credits the job may cost. The job holds them until it completes."},"purity_pct":{"$ref":"#/components/schemas/Percent"},"route":{"oneOf":[{"$ref":"#/components/schemas/Reactions","description":"The route to follow, in order. Leave it out for the lab to choose one."},{"type":"null"}]},"target_smiles":{"$ref":"#/components/schemas/Smiles"}},"additionalProperties":false}],"description":"Which of the four jobs this is, and what it needs. `kind` says which."},"WorkKind":{"type":"string","description":"A kind of job, as `Work`'s `kind` names it. A test checks that the two list the same names.","enum":["route_review","reaction_batch","reaction_screen","synthesis"]}},"securitySchemes":{"api_key":{"type":"http","scheme":"bearer","description":"An API key, made as apps/api/README.md says"}}},"security":[{"api_key":[]}]}