API for hospital, laboratory and sponsor systems
A key per system, what it may write and read, the calls with examples, the audit.
The API lets a hospital system (МИС) or a laboratory send patients and form data to a study by itself, without anyone typing or loading files, and lets the sponsor's system take the data back. Each system gets its own key. Everything it sends goes through the same edit checks, consent gate, automatic queries and audit trail as data typed by a person.
Keys
The study manager opens API in the study menu and makes a key for each system: its name (“Laboratory of site 01”), what it may do (write, read or both), the sites it works with, whether it may enrol new patients, and how long it works (30, 90 or 365 days). The key is shown once: copy it into the system's settings. The portal keeps only its fingerprint, so a lost key cannot be shown again; make a new one and revoke the old one.
- A key works only for its study and only for its sites.
- A key stops when it is revoked, when its term ends, or when the person who made it is no longer the study's manager.
- The keys table shows when each key was last used and how many requests it made.
1. Read the design
The system first asks for the study design: the sites of its key, the visits, the forms and the codes of their fields, with types, units, ranges and answer options. The codes are the same as in the eCRF builder and in the export.
curl https://youedc.com/api/v1/studies/REG-DIAB-01 \
-H "Authorization: Bearer yk_…"
2. Enrol a patient
A key that may enrol sends the site number, sex, year of birth and enrolment date. The portal gives the next patient ID of the site, or takes the one sent in subject when it is free.
curl https://youedc.com/api/v1/studies/REG-DIAB-01/patients \
-H "Authorization: Bearer yk_…" -H "Content-Type: application/json" \
-d '{"site": "01", "sex": "F", "birth_year": 1961, "enrolled_on": "2026-10-05"}'
→ 201 {“subject”: “REGDIA-01-0031”, “site”: “01”}
3. Send visit forms
Up to 500 records go in one request. A record names the patient, the visit, the form and the values by field code; instance is the occurrence of a repeated visit, status is complete (the default) or draft. A form already filled in is skipped unless the record has "update": true; then every changed value is in the audit trail.
Example: the laboratory of the demo registry REG-DIAB-01 sends the Month 6 results. HbA1c 11.8% is above the expected range, so the second record is loaded and an automatic query opens for site 02, as if the value had been typed.
curl https://youedc.com/api/v1/studies/REG-DIAB-01/records \
-H "Authorization: Bearer yk_…" -H "Content-Type: application/json" \
-d '{"records": [
{"subject": "REGDIA-01-0004", "visit": "Month 6", "form": "LB",
"values": {"LB_DATE": "2026-09-28", "HBA1C": "7.4", "GLUC": "6.8"}},
{"subject": "REGDIA-02-0004", "visit": "Month 6", "form": "LB",
"values": {"LB_DATE": "2026-09-29", "HBA1C": "11.8", "GLUC": "9.1"}}
]}'
→ 200 {“results”: [{“index”: 0, “status”: “ok”, “message”: “Loaded.”},
{“index”: 1, “status”: “warn”, “message”: “Loaded. Automatic queries: 1.”}],
“counts”: {“ok”: 1, “warn”: 1, “skip”: 0, “error”: 0}}
4. Take the data out
A key that reads takes the study's data into the sponsor's warehouse, a statistics program or a CTMS. It is made by a manager who may export the data; when making the key, pick “Read” or “Write and read”. The key sees what the export gives: only its sites, no forms for the unblinded team unless the person who made it is unblinded, and no patients who withdrew the use of their data. The patient's e-mail, PIN, date of birth and initials are never in the answers.
GET …/patients: the patients with their ID, site, sex, year of birth, enrolment date and status.GET …/records: the saved forms with their values by field code, the ND/UNK/NA marks and the rows of tables. Filters:subject,site,visit,form,status.GET …/queries: the queries with their field, form, visit and status.
The answer comes in pages of up to 1000 rows (limit, 500 by default). When the answer has next, pass it as after to get the next page. To take only the changes every night, add updated_since with the time of the last load.
curl "https://youedc.com/api/v1/studies/REG-DIAB-01/records?form=LB&updated_since=2026-10-08T00:00:00Z" \
-H "Authorization: Bearer yk_…"
→ 200 {“records”: [{“id”: 5120, “subject”: “REGDIA-01-0004”, “site”: “01”, “visit”: “Month 6”,
“form”: “LB”, “instance”: 1, “status”: “complete”, “source”: “import”,
“updated_at”: “2026-10-08T07:12:40Z”,
“values”: {“LB_DATE”: “2026-09-28”, “HBA1C”: “7.4”, “GLUC”: “6.8”}, “not_done”: {}}],
“next”: null}
The description of all the calls in OpenAPI 3.1 is at /api/v1/openapi.json: the system's developer generates a client from it or opens it in any OpenAPI viewer.
5. Send a patient's health record in FHIR R4
A hospital system that exports HL7 FHIR R4 posts the patient's record as it is, with no mapping of its own: a Bundle, a single resource or NDJSON, up to 5 MB, to POST …/fhir?subject=<patient ID>. The study's FHIR mapping decides where lab results, vital signs, conditions and medications go. By default (mode=review) nothing is saved: the answer lists every value with its place in the eCRF, and the import waits on the patient's card for the site team to check and confirm it. With mode=save the key saves the values that fill empty places and the new records itself, on behalf of the person who made the key; a value that would change a saved one is never saved this way, it stays for the site's review.
curl "https://youedc.com/api/v1/studies/DEMO-CKD/fhir?subject=CK-01-0004" \
-H "Authorization: Bearer yk_…" -H "Content-Type: application/fhir+json" \
--data-binary @record.json
→ 201 {“import”: “FH-2”, “subject”: “CK-01-0004”, “status”: “proposed”,
“counts”: {“values”: 4, “conflicts”: 1, “same”: 0, “skipped”: 1},
“review_url”: “https://youedc.com/p/DEMO-CKD/s/CK-01-0004/fhir/2”,
“items”: [{“resource”: “Observation/lab-creat-1”, “code”: “LOINC 2160-0”, “form”: “LAB”,
“field”: “CREAT”, “value”: “203”, “state”: “conflict”, …}, …]}
A file for another patient, two patients in one file, a body that is not FHIR JSON and a file over 5 MB are refused (422 or 413) and nothing is kept.
Answers and errors
- Each record gets its own answer:
okloaded,warnloaded with automatic queries or as a draft,skipalready filled in,errornot loaded, with the reason. - The request as a whole is refused with 401 (no key, a wrong, revoked or expired key), 403 (the key may not write, read or enrol, or the API is switched off), 400 (a wrong read filter), 422 (no such form or visit), 404 (another study), 413 (more than 500 records), 423 (the study is locked or enrolment is closed) or 429 (more than 600 requests a minute).
- Messages are in English; add
?lang=ruor the headerAccept-Language: rufor Russian.
Security and the audit trail
- Every change is in the audit trail with the key's name as the actor, for example “Laboratory of site 01 (API)”, and the reason “Sent through the API key …”. Making and revoking keys is recorded too.
- Every read is logged: which key, when, which call with which filters and how many rows it gave. The last reads are at the bottom of the API page, and the keys table shows how many rows each key has read.
- A key that reads stops when the manager who made it may no longer export the data.
- When the study asks for consent before data entry, the data of a patient without a consent that stands is not loaded.
- In a blinded study a key reads and writes the forms for the unblinded team only if the manager who made it is unblinded.
- Send keys only over HTTPS and keep them in the system's settings, never in e-mails or documents.
© 2026 Т.Г. (contact@youedc.com), YouEDC. All rights reserved. Terms of use. Data entered by users belongs to them.
MainEDC™ is a trademark of DM365.