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-Keyheader:
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.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /auth/register | Public | Create an account (inactive until email confirmation). Body: {email, password, full_name}. |
POST | /auth/login | Public | Get a JWT. Body: {username: email, password}. Returns {access_token, token_type}. |
POST | /auth/logout | Public | Clear the session cookie. |
GET | /auth/confirm-email?token= | Public | Confirm a registration email. |
POST | /auth/resend-confirmation | Public | Resend the confirmation email. |
POST | /auth/forgot-password · /auth/reset-password | Public | Password-reset request and completion. |
GET | /auth/me | Auth | Current user profile. |
PATCH | /auth/me | Auth | Update profile. Body: {full_name, password}. |
POST | /auth/api-key | Auth | Generate a new API key (returned once — save it). |
DELETE | /auth/api-key | Auth | Revoke 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 downloads | 200 / hour |
/search/autocomplete | 300 / hour |
POST /jobs, POST /submissions, DOI / taxid lookups | 30 / hour |
POST /submissions/lookup-sequence, /validate-sequence | 30 / minute |
POST /auth/login | 10 / minute |
POST /auth/register, /forgot-password | 5 / hour |
Entity detail routes (e.g. /plastics/{id}) are not rate-limited.
Search & vocabularies
| Method | Endpoint | Description |
|---|---|---|
GET | /search?q= | Cross-entity search over microorganisms, proteins, variants, plastics, and papers. Query: q (required), limit, offset. |
GET | /search/autocomplete?q= | Top matches per entity type for type-ahead (q ≥ 2 chars). |
GET | /vocabularies | All controlled vocabularies (methods, measurement types, environments, substrate forms, enzyme fields, variant types, plastics, compounds…). Cached one hour. See Controlled Vocabularies. |
Entity endpoints
Plastics
| Method | Endpoint | Description |
|---|---|---|
GET | /plastics | List 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/names | All 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
| Method | Endpoint | Description |
|---|---|---|
GET | /microorganisms | List. Query includes q, name, plastic, tax_id, temp_class, environment, location, year, min_year, max_year, the taxonomic ranks (domain…genus), 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-levels | Distinct 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
| Method | Endpoint | Description |
|---|---|---|
GET | /proteins | Unified 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}/fasta | Amino-acid sequence in FASTA (numeric protein id). |
GET | /proteins/{protein_id}/structure | PDB 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
| Method | Endpoint | Description |
|---|---|---|
GET | /papers | List 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}/footprint | Public 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-country | Database 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.
| Endpoint | Contents |
|---|---|
/downloads/dataset.zip · /dataset.json | The complete dataset, including protein_variants. |
/downloads/proteins.fasta · /proteins.csv · /proteins.json | Proteins (sequences and metadata). Wild-type and engineered variants — see below. |
/downloads/microorganisms.csv · .json | Microorganisms. |
/downloads/plastics.csv · .json | Plastics. |
/downloads/papers.csv · .json | Papers (aliased as /references.*). |
/downloads/protein-variants.csv · .json | Engineered-variant detail: mutations, engineering method, kinetics, sequence (aliased as /engineered-versions.*). |
/downloads/search.zip · /search.json | The 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:
kind | Returns |
|---|---|
both (default) | Wild-type proteins followed by engineered variants. |
wild_type | Wild-type proteins only. |
engineered | Engineered 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_id — proteins.csv ↔ proteins.fasta ↔ protein-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
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /jobs | Auth | Submit 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 | /jobs | Auth | List your jobs. |
GET | /jobs/{job_id} | Auth | Job status and results (including DIAMOND hits). |
Status values: waiting → running → done (or error). Poll the detail endpoint to track progress.
Submissions
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /submissions | Auth | Create a data submission (interactions with actors, experiments, observations). See Contributing Data for the shape. |
POST | /submissions/lookup-doi | Public | Paper metadata by DOI. Checks the database first, then Crossref. Body: {doi}. |
GET | /submissions/lookup-taxid?name= | Public | Search NCBI taxonomy by name. |
POST | /submissions/lookup-sequence | Auth | Fetch a protein sequence by accession. Body: {accession_id, database: genbank|uniprot}. |
POST | /submissions/validate-sequence | Auth | Validate a sequence string (amino acid vs. nucleotide). |
GET | /submissions/mine | Auth | Your submissions. |
GET | /submissions/isolation-environments · /sample-types · /evidence-types · /methods | Public | Vocabulary helpers for building the submission form. |
Best practices
- Use an API key for automation. JWTs expire; API keys persist until revoked and suit scripts and pipelines.
- Paginate. List endpoints cap at 500 items per page — walk large sets with
offset. - Handle 429s. Respect the limits above; on a rate-limit response, back off and retry after the window resets.
- Read vocabularies at runtime. Pull allowed values from
/vocabulariesrather than hard-coding them, so your client stays current. - Prefer bulk downloads for whole-dataset work instead of paginating every list endpoint.