Skip to main content

Authentication & API Tokens

The Public API (reading and downloading the dataset) requires no authentication — it stays open to everyone.

Writing data — submitting or updating experiment records from a script, notebook, or CI pipeline — requires a personal access token (PAT). This is the same mechanism the Python client uses.

[!TIP] For an exhaustive list of every REST endpoint and Python client method, see the Complete API Reference.


Creating a token​

  1. Log in at electrospinning-data.org.
  2. Open Profile Settings → API Tokens.
  3. Give the token a name (e.g. "Lab laptop" or "CI pipeline") and choose an expiry (30, 90, 365 days, or no expiry).
  4. Click Create token.

[!IMPORTANT] The token's full value is shown only once, immediately after creation. Copy it somewhere safe (e.g. a password manager or CI secret store) — the server only ever stores a hash of it, so it cannot be recovered later. If you lose it, revoke it and create a new one.

A token looks like esd_pat_<random string>. Treat it like a password: anyone holding it can submit data as you.


Using a token​

Send it as a standard bearer token in the Authorization header of any write request.

curl -X POST "https://api.electrospinning-data.org/data/submit" \
-H "Authorization: Bearer esd_pat_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"userMetadata": {"name": "Jane Doe", "email": "jane@example.com", "consentTerms": true},
"researchMetadata": {"publicationTitle": "My study", "doi": "10.1234/example"},
"experimentData": [{ "polymerProperty": { }, "processParameter": { } }]
}'

/data/submit, /data/update/{id}, and /data/update-submission/{id} all return a JSON body describing the outcome per record, e.g.:

{
"message": "Data submitted successfully",
"submissionId": 512,
"records": [
{ "recordId": 1044, "status": "PENDING", "missingFields": [] }
]
}

Submitted records go through the same moderation queue as web-form submissions, but are attributed to your account instead of being anonymous.


Record statuses & incomplete submissions​

A submitted experiment record has one of four statuses. GET /data/statuses (no auth required) returns the current list programmatically.

StatusMeaning
PENDINGComplete and awaiting moderator review.
APPROVEDReviewed and published to the public dataset.
REJECTEDReviewed and declined by a moderator.
NEEDS_UPDATESaved, but missing mandatory scientific fields (see below) — not yet in the moderation queue.

Incomplete submissions (NEEDS_UPDATE). When you submit with a personal access token and the payload is missing a mandatory field, the record is not rejected. The mandatory fields are the ones the web form requires: at least one polymer and one solvent (each with a name), the solution concentration, the needle type with its gauge(s), the collector type (plus the rotation speed for drums and mandrels, the gap for parallel electrodes, and so on), voltage, flow rate, tip-collector distance and fiber diameter, a weight ratio for every polymer in a blend and a volume ratio for every solvent in a mixture, and a unit for every value you give. It's saved with status NEEDS_UPDATE, and the response tells you exactly what's missing:

{
"message": "Data submitted successfully",
"submissionId": 513,
"records": [
{
"recordId": 1045,
"status": "NEEDS_UPDATE",
"missingFields": ["polymerProperty.polymerComponents[].polymerName"]
}
]
}

This leniency only applies to missing fields, and only for PAT-authenticated requests — anonymous/web-form submissions keep today's strict validation (a 400 error) since they have no way to come back and finish the record. A field that's provided but invalid is always a hard 400 error, in every mode — that's a data-quality problem, not incompleteness. Examples: a polymer name that doesn't exist in our reference list, an unknown unit, a zero or negative voltage, humidity above 100 %, or a diameter range whose lower value is larger than its upper one. The error message names the field.

To complete a NEEDS_UPDATE record, PUT /data/update/{recordId} with the missing fields filled in:

client.update(1045, {
"userMetadata": {"name": "Jane Doe", "email": "jane@example.com", "consentTerms": True},
"experimentData": [{
"polymerProperty": {"polymerComponents": [{"polymerName": "PVA"}]},
}],
})
# -> {"recordId": 1045, "status": "PENDING", "missingFields": [], "message": "..."}

Once all mandatory fields are present, the record automatically flips back to PENDING and re-enters the moderation queue.


Listing your own records​

Query the records you've submitted — filtered to a single status (e.g. just the ones that NEEDS_UPDATE), or all together. Both endpoints require authentication (session or PAT) and only ever return records you own.

EndpointReturns
GET /data/my-recordsFull record data (same shape as submit's experimentData items).
GET /data/my-records/idsJust the record ids — cheaper if you only need to know what to look at.

Both accept an optional status query parameter (PENDING, APPROVED, REJECTED, or NEEDS_UPDATE). Omit it to get every record regardless of status.

curl "https://api.electrospinning-data.org/data/my-records/ids?status=NEEDS_UPDATE" \
-H "Authorization: Bearer esd_pat_your_token_here"
# -> [1045, 1052]

This complements /data/my-submissions (which groups your records by submission, with no status filter): /data/my-records gives you a flat, filterable list at the individual record level.


Revoking and regenerating​

From Profile Settings → API Tokens you can:

  • Revoke a token immediately — any script still using it will start getting 401 TOKEN_REVOKED errors.
  • Regenerate a token — keeps the same name and expiry, but issues a brand-new secret (the old one stops working immediately). Useful if a token may have leaked.

Error responses​

Every write request with a bad token gets a 401 with a JSON body identifying exactly what went wrong:

SituationHTTP statuscode
No Authorization header at alldepends on the endpoint (public endpoints just proceed unauthenticated)—
Token doesn't exist / malformed401TOKEN_INVALID
Token was revoked401TOKEN_REVOKED
Token expired401TOKEN_EXPIRED
{
"success": false,
"message": "This API token has expired.",
"code": "TOKEN_EXPIRED"
}

Notes for the future​

Tokens currently carry a single WRITE scope — everything a token can do today is submit or update experiment data on your behalf. The token model supports additional scopes being added later (e.g. read-only tokens, admin actions) without requiring you to recreate existing tokens.