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 — currently: polymer information, or the name of a solvent component you did include — the record is not rejected. 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 (e.g. a polymer name that doesn't exist in our reference list) is always a hard 400 error, in every mode — that's a data-quality problem, not incompleteness.

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.