REST API

Read data and submit records programmatically.

Conventions

All endpoints are prefixed with /api/v1. Responses are JSON. List endpoints are paginated and return a total plus an items array; walk large sets with limit (max 500) and offset. Dates are ISO 8601 strings. Most IDs are integers; users and jobs use UUIDs, and proteins are addressed by their PlasticDB accession string.

Reading data, searching, and bulk downloads are public — no credentials required. Only submitting data, running jobs, and account operations need authentication.

Authentication

Two credential types are accepted, and either identifies you on protected endpoints:

  • API key (recommended for scripts) — generate one at Profile › API Keys; it does not expire until revoked. Send it in the X-API-Key header:
X-API-Key: YOUR_API_KEY
  • JWT (short-lived) — obtain one from POST /api/v1/auth/login, then send it as a bearer token:
Authorization: Bearer YOUR_JWT

An API key is also accepted as a bearer token, so a single Authorization: Bearer code path works for both if you prefer.

MethodEndpointAuthDescription
POST/auth/registerPublicCreate an account (inactive until email confirmation). Body: {email, password, full_name}.
POST/auth/loginPublicGet a JWT. Body: {username: email, password}. Returns {access_token, token_type}.
POST/auth/logoutPublicClear the session cookie.
GET/auth/confirm-email?token=PublicConfirm a registration email.
POST/auth/resend-confirmationPublicResend the confirmation email.
POST/auth/forgot-password · /auth/reset-passwordPublicPassword-reset request and completion.
GET/auth/meAuthCurrent user profile.
PATCH/auth/meAuthUpdate profile. Body: {full_name, password}.
POST/auth/api-keyAuthGenerate a new API key (returned once — save it).
DELETE/auth/api-keyAuthRevoke your current API key.

Rate limits

Rate-limited endpoints default to 200 requests/hour, bucketed per user for authenticated requests and per IP for anonymous ones. Exceeding the limit returns 429 Too Many Requests; back off and retry after the window resets. Some endpoints set their own limits:

Endpoint(s)Limit
Most list & search endpoints, bulk downloads200 / hour
/search/autocomplete300 / hour
POST /jobs, POST /submissions, DOI / taxid lookups30 / hour
POST /submissions/lookup-sequence, /validate-sequence30 / minute
POST /auth/login10 / minute
POST /auth/register, /forgot-password5 / hour

Entity detail routes (e.g. /plastics/{id}) are not rate-limited.

Entity endpoints

Plastics

MethodEndpointDescription
GET/plasticsList plastics with per-plastic microorganism and protein counts. Query: q, name, cas_number, polymer_class, sort_by (name, full_name, cas_number), sort_order, limit, offset.
GET/plastics/namesAll plastic names and IDs (for dropdowns).
GET/plastics/{plastic_id}Plastic detail. Paginate sub-entities with microorganism_offset/limit, protein_offset/limit, and filter with microorganism_polarity / protein_polarity.

Microorganisms

MethodEndpointDescription
GET/microorganismsList. Query includes q, name, plastic, tax_id, temp_class, environment, location, year, min_year, max_year, the taxonomic ranks (domaingenus), polarity, include_negative, plus sort_by (name, tax_id, growth_temp_opt), limit, offset.
GET/microorganisms/search?q=Autocomplete by name or tax ID.
GET/microorganisms/lineage-levelsDistinct values per taxonomic rank, for building filter dropdowns.
GET/microorganisms/{tax_id}Detail keyed by NCBI tax ID: lineage, plastics, proteins, and papers.

Proteins & variants

MethodEndpointDescription
GET/proteinsUnified list of wild-type proteins and engineered variants. Query: q, name, plasticdb_id, accession, plastic, microorganism, year, min_year, max_year, kind (wild_type / engineered / both), kinetic filters (min_kcat, max_km…), polarity, sort and pagination params.
GET/proteins/{accession}Protein detail by PlasticDB accession — sequence, structure, engineered versions, plastics, source organisms. Returns 301 if the accession was merged, 410 if tombstoned.
GET/proteins/{protein_id}/fastaAmino-acid sequence in FASTA (numeric protein id).
GET/proteins/{protein_id}/structurePDB structure file, when available (numeric protein id).
GET/variants/{variant_id}Engineered variant detail (numeric id): mutations, kinetics, properties, parent protein, and the plastics it acts on.
GET/engineering/proteins · /engineering/proteins/{accession}Enzymes that have engineered variants, and one enzyme's variant lineage.

Papers & compounds

MethodEndpointDescription
GET/papersList papers. Query: q, year, doi, journal, authors, country, min_year/max_year, sort_by (year, citation, doi), pagination.
GET/papers/{paper_id}Paper detail with the microorganisms, proteins, and variants derived from its interactions.
GET/papers/{paper_id}/footprintPublic aggregate of everything the paper contributed.
GET/compounds · /compounds/{compound_id}Chemical compounds (monomers, additives, pathway intermediates): list and detail.
GET/stats · /stats/charts · /stats/by-countryDatabase statistics powering the statistics page and country map.

Bulk downloads

Public export endpoints under /api/v1/downloads return the whole database or a filtered slice. The per-entity exports accept the same filter query params as their list endpoints, so an export always matches the on-screen result set.

EndpointContents
/downloads/dataset.zip · /dataset.jsonThe complete dataset, including protein_variants.
/downloads/proteins.fasta · /proteins.csv · /proteins.jsonProteins (sequences and metadata). Wild-type and engineered variants — see below.
/downloads/microorganisms.csv · .jsonMicroorganisms.
/downloads/plastics.csv · .jsonPlastics.
/downloads/papers.csv · .jsonPapers (aliased as /references.*).
/downloads/protein-variants.csv · .jsonEngineered-variant detail: mutations, engineering method, kinetics, sequence (aliased as /engineered-versions.*).
/downloads/search.zip · /search.jsonThe current search result set.

HEAD is accepted on every download route and answers 200 with the same Content-Type and Content-Disposition the GET would send, and an empty body — probe one before streaming it. No Content-Length is advertised: exports are streamed, so their size isn't known until generated, and a 0 there would be a lie rather than a number you could use.

In plain terms: you can check that any URL on this site works, and how big the file behind it is, without downloading it. That applies to every address here, pages included.

Technical detail: every endpoint that answers GET also answers HEAD with the same status and headers and no body, so curl -I, link checkers, and uptime monitors work against any URL — including /health. A HEAD on a URL that doesn't exist is a 404, as it should be. HEAD is deliberately absent from the OpenAPI schema below: RFC 9110 defines it as GET minus the body, so listing a twin of every endpoint would double the reference without telling you anything new.

Wild-type proteins and engineered variants

PlasticDB treats an engineered variant as a first-class protein entity with its own PB#### accession. The protein exports and /proteins therefore describe a union of two entity types, selected with kind:

kindReturns
both (default)Wild-type proteins followed by engineered variants.
wild_typeWild-type proteins only.
engineeredEngineered variants only.

Any other value is a 422. Until v0.43.0 a typo such as ?kind=enginered quietly fell back to both and returned the full export with a 200 — the wrong dataset, with nothing to tell you so.

Every row carries a kind column (wild_type or engineered). Because the two entity types have independent id sequences, the row key is (kind, id)id alone is not unique in a kind=both export. Variant rows also carry parent_accession.

Joining a record to its sequence. Every row carries seq_id, which is exactly the identifier of that record's FASTA entry, and it is never empty. Join on seq_idproteins.csvproteins.fastaprotein-variants.csv all agree on it. accession is the real PB#### registry value and is the better key when you specifically want registered records, but it is empty for a record whose accession has not been minted yet; seq_id falls back to PlasticDB_{id} (or PlasticDB_var_{id} for a variant) so those records stay joinable.

Variant rows populate their own interactions, kinetics, structures, and papers; the source organism is inherited from the parent. Columns with no variant analogue (plasticdb_id, gene, genbank_id, uniprot_*, …) are empty. For a variant's mutations and engineering method, join protein-variants.csv on seq_id.

Two deliberate differences. (1) proteins.fasta is a sequence file, so it omits records with no sequence; proteins.csv/.json keep them as metadata rows, and can be one or more rows longer. (2) dataset.zip/dataset.json are a complete archive and apply no include_negative filter, so their proteins set is a superset of the endpoint's default — pass ?include_negative=true to match.

Every filter applies to both entity types, on /proteins and its exports alike — only kind decides which entities you get back. A variant resolves a filter one of two ways. Inherited: microorganism, lineage, and plasticdb_id have no column on a variant, so they resolve through its parent protein — ?microorganism=Pseudideonella&kind=engineered returns the Pseudideonella-derived variants, because that is where a variant's organism actually lives. Its own: substrate_form, evidence_method, polarity, and the kinetic thresholds match the variant's own experiments and measurements, never its parent's — ?min_kcat=5&kind=engineered selects variants whose own kcat clears 5 s⁻¹, which is the point of having engineered them.

Before v0.43.0, microorganism, lineage, substrate_form, and the kinetic thresholds silently excluded every variant — even under kind=engineered, which returned an empty file for a question that had an answer.

Selecting evidence by assay method

/proteins, /microorganisms, and their exports accept evidence_method, which matches the assay a record's evidence rests on — weight_loss, hplc, sem, clear_zone, ftir, and so on, matched exactly against the method vocabulary. Example: /api/v1/downloads/proteins.fasta?evidence_method=hplc.

This is a descriptive axis, not a quality ranking. Every record in PlasticDB is curated from published literature; no method ranks above another, and a record is not more or less trustworthy for having been assayed one way rather than another. Pick the assay that suits your analysis.

Jobs

MethodEndpointAuthDescription
POST/jobsAuthSubmit a bioinformatics job. Multipart form: file/files[], job_type, and parameters evalue (default 1e-5), pident (default 30), organism_type, blast_type. See Bioinformatics Tools.
GET/jobsAuthList your jobs.
GET/jobs/{job_id}AuthJob status and results (including DIAMOND hits).

Status values: waitingrunningdone (or error). Poll the detail endpoint to track progress.

Submissions

MethodEndpointAuthDescription
POST/submissionsAuthCreate a data submission (interactions with actors, experiments, observations). See Contributing Data for the shape.
POST/submissions/lookup-doiPublicPaper metadata by DOI. Checks the database first, then Crossref. Body: {doi}.
GET/submissions/lookup-taxid?name=PublicSearch NCBI taxonomy by name.
POST/submissions/lookup-sequenceAuthFetch a protein sequence by accession. Body: {accession_id, database: genbank|uniprot}.
POST/submissions/validate-sequenceAuthValidate a sequence string (amino acid vs. nucleotide).
GET/submissions/mineAuthYour submissions.
GET/submissions/isolation-environments · /sample-types · /evidence-types · /methodsPublicVocabulary helpers for building the submission form.

Best practices

  1. Use an API key for automation. JWTs expire; API keys persist until revoked and suit scripts and pipelines.
  2. Paginate. List endpoints cap at 500 items per page — walk large sets with offset.
  3. Handle 429s. Respect the limits above; on a rate-limit response, back off and retry after the window resets.
  4. Read vocabularies at runtime. Pull allowed values from /vocabularies rather than hard-coding them, so your client stays current.
  5. Prefer bulk downloads for whole-dataset work instead of paginating every list endpoint.