Make a share link of the user's records
A SMART Health Link (HL7 FHIR IG "SMART Health Cards and Links", STU1) that the person
gives to whoever they choose. The server reads the user's records of categories in
[start, end) (the merged view, as the FHIR routes serve them), writes them as one
FHIR R4 collection Bundle (a Patient with no identifier, the Observations, the
Devices), compresses it (DEFLATE) and encrypts it as a compact JWE (alg dir,
enc A256GCM) with a fresh random 256-bit key. It stores the ciphertext only. The
answer holds the link (uri) and the built-in viewer's link (viewer_url), each
carrying the key, this once: the server keeps neither and cannot show them again.
A category holds every metric the consent model files under it. Records of a source
whose consent refuses the category, or whose purge is pending, are left out. The
snapshot is fixed when it is made (no L flag): later records are not added. At most
50000 records; more is a 400. A sleep session's, a workout's or a daily summary's
figures of another category (a resting heart rate is heart) are kept only on the
terms of their own category. The records are read and the share stored in one
transaction that holds the user and their consent: a consent change or an erasure
that starts meanwhile waits, then revokes the share if it holds what they remove.
The route takes no Idempotency-Key: a stored response would keep the key. Sent with
Cache-Control: no-store. See docs/share-links.md.
tenantKeyAuthorizationBearer <token>Tenant API key, ohs_sk_ + 43 base62 characters.
id*stringuuidapplication/json- body
categories*array<>1 <= itemsstart*|Inclusive start of the window, RFC 3339 or YYYY-MM-DD.
end*|Exclusive end of the window, after start.
expires_at*|When the link stops working, in the future and at most 365 days ahead.
passcode?|When set, the reader must give it. 6 to 64 characters, no control character. The server keeps a PBKDF2-SHA256 hash of it only.
6 <= length <= 64label?stringShown to the reader, for example who the link is for. One line.
length <= 80The share and its link, shown only this once. Sent with Cache-Control: no-store.
application/json- response
A share link as its owner reads it. Never the link, its key or the passcode.
id*stringuuidlabel*stringShown to the reader; empty for none.
length <= 80categories*array<>start*stringInclusive start of the time window.
date-timeend*stringExclusive end of the time window.
date-timeexpires_at*stringWhen the link stops working.
date-timepasscode*booleanWhether the link needs a passcode.
passcode_failures*integerWrong or missing passcodes so far; the 10th disables the link.
status*stringactive: the link works. expired: past expires_at. revoked: stopped before its
expiry (see revoked_reason). disabled: too many wrong passcodes.
"active""expired""revoked""disabled"revoked_at*|date-timerevoked_reason*|"owner""consent""provider_erased""passcode_attempts"nullobservations*integerHow many Observations the file holds.
file_bytes*integerThe size of the encrypted file when it was made.
accesses*integerHow many manifest requests were served the file.
last_accessed_at*|The latest of them.
date-timecreated_at*stringdate-timeuri*stringThe link, shlink:/ + the base64url payload (url, key, exp, flag P
with a passcode, label). It carries the key: shown only this once.
viewer_url*stringThe built-in viewer with the link in its fragment (.../shl/view#shlink:/...).
curl -X POST 'http://localhost:8080/v1/users/497f6eca-6276-4993-bfeb-53cbbbba6f08/shares' \ -H 'Authorization: Bearer ohs_sk_...' \ -H 'Content-Type: application/json' \ -d '{ "categories": [ "activity" ], "start": "2019-08-24T14:15:22Z", "end": "2019-08-24T14:15:22Z", "expires_at": "2019-08-24T14:15:22Z"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "label": "string", "categories": [ "activity" ], "start": "2019-08-24T14:15:22Z", "end": "2019-08-24T14:15:22Z", "expires_at": "2019-08-24T14:15:22Z", "passcode": true, "passcode_failures": 0, "status": "active", "revoked_at": "2019-08-24T14:15:22Z", "revoked_reason": "owner", "observations": 0, "file_bytes": 0, "accesses": 0, "last_accessed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "uri": "string", "viewer_url": "string"}