Skip to content

API reference (light)

Basics

API endpoint

Depending on the Pryv.io setup or distribution, the root endpoint can have the following formats:

Pryv Lab: https://{username}.pryv.me Own Domain: https://{username}.{domain} DNS-less (Open): https://{hostname}/{username}

Each user account has a dedicated root API endpoint as it is potentially served from a different location. The API endpoint format may vary, so check your platform’s service information if needed.

You can adapt the examples with “API” selector in the top navigation bar.

Call with HTTP

The API serves regular REST-like HTTP requests, with the usual verbs for reading and manipulating data:

  • GET (parameters: query string)
    for reading resources
  • POST (parameters: request body)
    for creating new resources and other methods modifying data
  • PUT (parameters: request body)
    for modifying resources
  • DELETE (parameters: query string)
    for removing resources; logical deletion (trashing) is supported for some resources such as events and streams

Alternative HTTP request method

For those having trouble with HTTP access control (CORS) rules, the API allows web apps to fake POST, PUT and DELETE requests through application/x-www-form-urlencoded POST requests with the following fields (all optional):

_method

The HTTP override method to use (usually PUT or DELETE; POST is used if not set).

_auth

The Authorization header value (alternative to sending the header itself).

_json

Considered as the JSON request body if set (overriding all other body content, if any).

Call with websockets

The API supports real-time interaction by accepting websocket connections via Socket.io 2.0

For API versions prior to 1.5.8, use Socket.io 0.9.

Connecting

First, load the right Socket.IO client library.

Then initialize the connection with the URL:

Pryv Lab:

https://{username}.pryv.me/{username}?auth={accessToken}

Own Domain:

https://{username}.{domain}/{username}?auth={accessToken}

DNS-less:

https://host.your-domain.io/{username}/{username}?auth={accessToken}

Yes, the username is quoted 2 times…

For API versions prior to 1.5.8, append &resource={username}.

Call methods

You call API methods by sending a corresponding Socket.IO {method-id} message, passing a parameters object and a callback:

// javascript
socket.emit('{method-id}', {/*parameters*/}, function (error, result) {
  // handle result
});

See methods ids

Specific errors

invalid-method
HTTP404

The given method id is invalid.

Subscribe to changes

Get notified when data changes by subscribing to messages. Available messages are:

  • eventsChanged
  • streamsChanged
  • accessesChanged
  • systemBoot (webhooks only)

Messages do not include the content of the changes, but they describe what type of resource has been changed (created, updated or deleted). They inform the server that it needs to fetch new or updated data through the API by doing a HTTP GET request with a valid access token. The systemBoot message is executed when the notifications system is started in order to query possibly missed data changes.

Both transports can be narrowed to named scopes so you are notified only of matching changes — see scoped subscriptions for websockets and the webhook scopes field for webhooks. A scoped subscription replaces the coarse messages above with the matched scope keys.

With websockets

Get notified of data changes in a web application using websockets.

Scoped subscriptions (websockets)

By default a websocket connection receives the coarse eventsChanged / streamsChanged / accessesChanged messages above for every change in the account. You can instead register one or more named scopes so the server wakes you only when a matching change occurs.

Manage scopes by emitting these messages (each takes a callback that receives an acknowledgement):

  • subscribe — register scopes. Payload is a single { key, kind, query } or a bulk { scopes: { key: { kind, query } } }. kind is one of events (default), streams or accesses; query is shaped like the parameters of the matching read method (an events.get query for events, { streams } for streams, an accesses filter for accesses). Acknowledged with { ok: true, keys: [...] }.
  • unsubscribe — remove scopes. Payload is { key }, { keys: [...] } or { all: true }. Acknowledged with { ok: true, keys: [...] }.
  • getSubscriptions — list the active scopes. Acknowledged with { scopes: { key: { kind, query } } }.

As soon as a connection holds at least one scope, it opts out of the coarse broadcasts and instead receives a single notificationsChanged message whose payload is { keys: [...] } — the matched scope keys. Older servers that don’t support scoped subscriptions reject subscribe (treating it as an unknown method); clients should fall back to the coarse messages in that case.

With webhooks

Get notified of data changes in a web service using webhooks.

An unfiltered webhook reports the coarse change types (eventsChanged, streamsChanged, …). A scoped webhook (one created with a scopes map) instead reports the matched scope keys in the same messages array — see the second example below.

Method ids

Pryv.io API methods have ids that are available at each method’s doc. For example, the id of the Get events method is events.get. This id is useful in the following:

Service info

Service information provides a unified way for third party services to access the necessary information related to a Pryv.io platform as this route is served by any Pryv.io API endpoint.

For many applications, the first step is to authenticate a user. For this you need to know the path to access which is usually set to https://access.{domain}/ or https://{hostname}/access/. Fetching the path /service/info on any valid URL endpoint will return you a list of useful informations, such as access, containing the URL to access.

See Auto-Configuration in the guide App Guidelines.

Parameters

Result

HTTP200 OK
register
string

The URL of the register service.

access
string

The URL to perform authentication requests.

api
string

The API endpoint format.

name
string

The platform name.

home
string

The URL of the platform’s home page.

support
string

The email or URL of the support page.

terms
string

The terms and conditions, in plain text or the URL displaying them.

eventTypes
string

The URL of the list of validated event types.

version
string

The API version.

account
stringoptional

The root URL of the platform’s account app (self-service account management, e.g. app-web-user-account), when the platform names one. The lib-js sign-in button uses it for its Manage my account link.

features
objectoptional

Capabilities of the platform, so clients need not probe for them. Among them: noHF (no high-frequency series), contentQueries (content queries on events.get), mfa.methods (active multi-factor methods), emailVerification, and delegation (true when account delegation is available: an auth page may then offer to grant an app access for an account the user controls). An absent key means an older server: treat the capability as unknown.

Data format

The API exchanges data with clients in JSON (MIME type application/json), except when uploading/downloading attached files.

As input, the API accepts JSON payloads of maximum 10MB.

Authorization

All requests for retrieving and manipulating activity data must carry a valid access token. The preferred method is to use the HTTP Authorization header.

Access tokens are obtained via the app authentication or from sharing.

Alternative methods:

  1. Pryv.io supports the Basic HTTP Authorization Scheme This allows to present a Pryv.io endpoint as a single URL without exposing the token in query parameters:

    curl https://{token}@{username}.pryv.me/access-info
    

    This method is not supported by modern browsers but by tools such as cURL, the Node.js library superagent or Postman. These tools implicitly translate the ${token}@ part of the URL to the Authorization header in basic auth format. Please use the main authorization method for tools that do not operate this translation, such as Grafana.

    Note that Pryv.io does not require a username, so only the token should be Base64 encoded. For more information see RFC671.

  2. The access token can be provided in the query string’s auth parameter, for example during the Socket.IO handshake or for a direct HTTP GET call in a browser:

    curl https://{username}.pryv.me/access-info?auth={token}
    

v2 additions and changes

API methods added or whose semantics changed in Pryv.io v2 (open-pryv.io ≥ 2.0.0-pre.X) are tagged with v2

v2 is backwards-compatible by default: existing v1 clients continue to work against a v2 server, and v1 servers ignore v2-only request parameters they don’t recognise. The badge highlights the surfaces where behaviour or shape changed between major versions, so SDK authors and integrators can scope their compatibility work.

See the change log for the full per-release breakdown.

Authenticate your app

To authenticate users in your app, and thus for users to grant your app access to their data, you must:

  1. Choose an app identifier (min. length 6 chars)

  2. Fetch the service information

  3. Send an auth request to the URL exposed by the access parameter of the service information

  4. Open the authUrl field of the HTTP response in a browser or webframe. The web page will prompt the user to sign in using her Pryv.io credentials (or to create an account if she doesn’t have one).

  5. The result of the sign-in process: an authenticated Pryv API endpoint or a refusal can be obtained in two ways:

    • by polling the URL obtained in the poll field of the HTTP response to the auth request (preferred method)
    • by being redirected to the returnURL provided in the auth request with the result in query parameters

Generate token app

The Access token generator is a simple web application that allows its user to enter the parameters of the Auth request and performs it. It is accessible at the following URL:

https://pryv.github.io/app-web-access/?pryvServiceInfoUrl=${pryvServiceInfoUrl}

For example:

https://pryv.github.io/app-web-access/?pryvServiceInfoUrl=https://reg.pryv.me/service/info

Auth request

idauth-requestHTTP-onlyPOST to {serviceInfo.access}

The API endpoint to use is given by the service information’s access property.

Parameters

requestingAppId
string

Your app’s identifier.

requestedPermissions
array of permission request objects

The requested permissions. Each permission request has properties:

streamId

The id of the requested stream.

level
read|contribute|manage

The required permission level.

defaultName
string

The name to create the stream if needed (in the language of the user).

consent
objectoptional

How the authentication page should present each requested permission. Its lists name permission ids: a stream permission’s streamId, or a feature permission’s feature.

The permission is Write it as The user sees
required for the app to work listed in mandatory ticked and locked, with a “required by this app” note
optional, expected to be kept in neither list ticked, and they may untick it
optional, chosen deliberately listed in optIn unticked, and they may tick it

Where consent is your lawful basis under the GDPR, prefer optIn: Recital 32 states that pre-ticked boxes do not constitute consent.

A core that does not support this ignores the whole object, so the authentication falls back to all-or-nothing rather than failing. The result below echoes consent only when the core understood it, which is how you detect support.

The request fails with invalid-parameters (HTTP 400) if an id matches no requested permission or matches more than one, if an id appears in both lists, or if a requested permission uses level none.

allowUserChoice
booleanoptional

Whether the user may grant a subset. Default false: the consent is all or nothing, whatever the lists below say.

mandatory
array of stringsoptional

Ids of permissions the user cannot leave out.

optIn
array of stringsoptional

Ids of permissions presented NOT pre-selected, so the user has to choose them.

languageCode
stringoptional

The two-letter ISO (639-1) code of the language in which to display user instructions, if possible. Default: en.

returnURL
stringoptional

The URL to redirect the user to after authentication completes. Required if you are not using polling to retrieve the authentication result (see Result below).

clientData
key-valueoptional

Additional client data that will be transmitted alongside the auth request (see Result below).

authUrl
stringoptional

Custom authentication-page URL for this request (your own auth UI instead of the platform’s default page). Honored only when it matches one of the operator-configured access.trustedAuthUrls entries: same protocol and host, and the path must equal the entry’s path or extend it on a / segment boundary. A non-matching authUrl (or any authUrl when the platform configures no trusted entries) fails the request with invalid-parameters (HTTP 400) — it is never silently ignored.

serviceInfo
objectoptional

Overrides the default service information object that will be transmitted in the polling responses.

deviceName
stringoptional
expireAfter
numberoptional
token
stringoptional

A fixed token for the access, applied as is by the authentication page. See access data structure. When the user grants the access for an account they control (see actAs), the same token value is used on that account: an app that sets a fixed token and lets the user choose between accounts holds the same token value on each of them. Set actAs to deny if that does not suit your app.

actAs
stringoptional

Who the access may be granted for, when the user controls other accounts through account delegation:

  • allow (the default behaviour when omitted): after sign-in, the authentication page may ask whether the access is for the signed-in account or for an account it controls;
  • deny: the signed-in account only;
  • a username: preselect that controlled account (the user can still choose another one; an account the user does not control is simply not preselected).

Any other value fails the request with invalid-parameters (HTTP 400). A core that does not support it ignores the field. The page offers the choice only when the platform’s service information reports features.delegation: true and the user controls at least one active account.

actAsManagedOnly
booleanoptional

true when the access must be granted for an account the user manages through account delegation, never for the signed-in account itself. Requires actAs set to allow or a username: true without actAs, or with actAs: 'deny', fails the request with invalid-parameters (HTTP 400), and so does a value that is not a boolean. false is the same as not sending the field.

The authentication page enforces it, not the core: the reference page lists only the active accounts the user manages and opens the account creation form when there is none yet; when no managed account can be used (for example on a platform without delegation), it says why and offers Cancel only, which ends the request REFUSED with reasonId: 'MANAGED_ACCOUNT_UNAVAILABLE'. The result below echoes actAsManagedOnly: true only when the core understood it, which is how you detect support: an older core drops the field, and an older authentication page ignores it and behaves per actAs. Requires open-pryv.io 2.0.0-rc.36 or later.

cmcInvites
array of invite objectsoptional

Cross-account messaging invites the user should answer on the authentication page, next to the app access: 1 to 8 entries, each with no other key than the properties below. The page shows each invite with its own Approve and Decline, accepts the approved ones (mandatory first) before it creates the app access or hands over one the app already holds, sends a refusal to the requester of each readable declined invite, and reports one outcome per invite in the ACCEPTED result (see Poll request). The reference authentication page supports it from app-web-user-account 0.11.0.

A malformed list fails the request with invalid-parameters (HTTP 400). A core that does not support it ignores the field; the result below echoes cmcInvites only when the core understood it, which is how you detect support. Requires open-pryv.io 2.0.0-rc.32 or later.

capabilityUrl
string

The invite’s capability URL: an absolute http or https URL of at most 2048 characters.

mandatory
booleanoptional

Default false. When true, declining this invite ends the request REFUSED with reasonId: 'REFUSED_MANDATORY_CONSENT', before the page writes anything, and failing to accept it ends the request REFUSED with reasonId: 'MANDATORY_CONSENT_FAILED' (invites accepted before it stay accepted). Enforced by the authentication page.

for
self|targetoptional

Default self: the signed-in account accepts. target: the account the access is granted for accepts, when the user grants it for an account they manage (see actAs); the page then accepts with its delegate token for that account.

accessName
stringoptional

The name of the data grant the user mints by accepting this invite: 1 to 256 characters, stored as sent and echoed with the invite. The core does not use it; the authentication page passes it to the accept. Without it, the grant takes the platform’s default name. An older core refuses an entry carrying it with invalid-parameters (HTTP 400). Requires open-pryv.io 2.0.0-rc.36 or later.

referer
stringoptional

Used when creating a user in the process of authentication. See Create user method.

Result: need sign-in

HTTP200
status
NEED_SIGNIN

Authentication in progress.

url
string

(DEPRECATED) Please use the authUrl parameter.

The URL of the authentication page to show the user from your app as popup or webframe.

authUrl
string

The URL of the authentication page to show the user from your app as popup or webframe.

key
string

The key used to identify the auth request. It is also part of the poll URL described just below.

poll
string

The poll URL to use for retrieving the auth result via an HTTP GET request. Responses to polling requests are the same as those from the auth request.

poll_rate_ms
number

The rate at which the poll URL can be polled, in milliseconds.

requestingAppId
string

The app identifier provided during the auth request.

requestedPermissions
string

The permissions provided during the auth request.

consent
objectoptional

The resolved consent form: the requested permissions with their annotations attached, as the authentication page renders them. Present ONLY when the request carried a consent object that this core understood, so its absence means the authentication will be all-or-nothing. Carries allowUserChoice and permissions, each entry being the requested permission plus mandatory: true or optIn: true where they apply.

lang
stringoptional

The language code provided during the auth request.

returnURL
stringoptional

The return URL provided during the auth request.

clientData
key-valueoptional

The client data provided during the auth request.

actAs
stringoptional

The actAs value provided during the auth request; absent when the request did not carry one.

actAsManagedOnly
trueoptional

Present, in the creation answer and in the NEED_SIGNIN poll, ONLY when the request carried actAsManagedOnly: true and this core understood it. Never on ACCEPTED.

cmcInvites
array of invite objectsoptional

The cmcInvites provided during the auth request, normalised (mandatory and for filled in with their defaults, accessName present only on an entry that carried it). Present, in the creation answer and in the NEED_SIGNIN poll, ONLY when the request carried cmcInvites and this core understood them. The capability URLs are readable by whoever holds the poll key, like the rest of the request.

serviceInfo
stringoptional

The service information. On a poll, this is the platform’s configured service information as is: values the server derives at runtime, such as features.delegation, may be missing from it. Read capabilities from service info itself.

Poll request

idpoll-requestHTTP-onlyGET {needSignInResponse.poll}

The polling URL is given by the poll parameter in the result the Auth Request or a Poll request.

Result: need sign-in

HTTP200

indentical to RESULT: SIGN-IN from Auth Request

Result: accepted

HTTP200
status
ACCEPTED

Authentication successful.

username
string

(DEPRECATED) Please use the apiEndpoint parameter.

The authenticated user’s username.

token
string

(DEPRECATED) Please use the apiEndpoint parameter.

Your app’s API access token.

apiEndpoint
string

The API endpoint containing the authorization token. See app guidelines.

delegation
objectoptional

Present when the user granted the access for an account they control (see actAs in the auth request); username and apiEndpoint then name that controlled account. Shape: { isDelegatedAccess: true, controlledUsername, delegate: { username, hostSlug? } }, where delegate is the signed-in user who granted it. The platform’s authentication page does not send delegate.hostSlug.

This is a display hint posted by the authentication page. The authoritative answer is the delegation field of access-info called with the received token.

cmcInvites
array of outcome objectsoptional

Present when the request carried cmcInvites and the authentication page processed them: one outcome per invite, in the order of the request, each one of { acceptEventId, dataGrantAccessId?, acceptedFor?: 'self' } (accepted; acceptedFor: 'self' marks a for: 'target' invite accepted by the signed-in account), { declined: true } or { reason } (an optional invite the page could not accept, or an accept still pending when the wait ended, cmc-capability-timeout). Carried whether the token is delivered inline or through a handoff.

This is a hint posted by the authentication page, not verified by the core. The requester of each invite learns the truth from its own inbox (the consent/accept-cmc delivered there). See Consent invites in the authorisation request.

serviceInfo
objectoptional

Result: refused

HTTP403
status
REFUSED

Authentication failed.

reasonId
string

A code indicating the reason for the failure. For a request with cmcInvites: REFUSED_MANDATORY_CONSENT when the user declined a mandatory invite, MANDATORY_CONSENT_FAILED when a mandatory invite could not be accepted (the message then names the invite and the platform’s error id). For a request with actAsManagedOnly: MANAGED_ACCOUNT_UNAVAILABLE when the user had no account they manage to grant the access for (the message then names the cause).

message
string

A message indicating the reason for the failure.

serviceInfo
objectoptional

Common metadata

General API and server information.

In HTTP headers

Every HTTP response has header:

API-Version

The version of the API in the form {major}.{minor}.{revision}. Mirrored in method results as meta.apiVersion.

Pryv-Access-Id
optional

The id of the Access used for the API call. Only present if a valid access token has been provided.

In method results

Every JSON method result has properties:

meta.apiVersion

The version of the API in the form {major}.{minor}.{revision}. Mirrored in HTTP header API-Version.

meta.serverTime

The current server time as a timestamp. Keeping track of server time is necessary to properly handle time in API calls.

meta.serial

The serial will change every time the core or register is updated. If you compare it with the serial of a previous response and notice a difference, you should reload the service information.

Errors

When an error occurs, the API returns a response with an error object (see error detailing the cause. (Over HTTP, the response status is set to 4xx or 5xx.) In this documentation, errors are identified by their id.

Usual errors

invalid-request-structure
HTTP400

The request’s structure is not that expected; for example: invalid JSON syntax, unexpected multipart structure when uploading file attachments.

invalid-parameters-format
HTTP400

The request’s parameters do not follow the expected format. The error’s data contains an array of validation errors.

unknown-referenced-resource
HTTP400

One or more referenced resource(s) can’t be found. The error’s data.{method-parameter-key} (e.g. data.streamId) contains the unknown reference(s).

invalid-access-token
HTTP401

The access token is missing or invalid.

forbidden
HTTP403

The given access token does not grant permission for this operation. See accesses for more details about accesses and permissions.

unknown-resource
HTTP404

The resource can’t be found.

removed-method
HTTP410

The resource or method has been removed from the API.

too-many-results
HTTP413

The events.get method in batch or websocket call yielded too many results. Call the API method directly, narrow the request scope or page the request.

user-account-relocated
HTTP301

The user has relocated her account to another server. Both the Location header and the error’s data contain the equivalent URL pointing to the physical server now hosting the user’s account. This error can only occur between the moment the account is relocated and the moment your DNS is updated to point to the new server. So we’re stretching the HTTP convention a little, in that the returned URL should not be used permanently (only until {username}.pryv.me points to the correct server again). It’s up to you to decide whether to keep it for the duration of the session (if you use sessions), for a given time, etc.

user-intervention-required
HTTP402

The request cannot be served temporarily because the user’s account has exceeded its limits. The user must log into her account and fix the issue.

wrong-core
HTTP421

Multi-core deployments only. The request reached a core that does not host the requested user account. The error’s data.coreUrl contains the correct API endpoint for this user. Clients MUST retry the request directly against coreUrl. An HTTP redirect is not used because cross-origin redirects strip the Authorization header.

API methods

Registration

Method for user registration. This documentation has been moved to System reference.

Call batch

idcallBatchHTTPPOST /

Sends a batch of API methods calls in one go (e.g. for syncing offline changes when resuming connectivity).

Parameters

Array of method call objects, each defined as follows:

method
string

The method id.

params
object or array

The call parameters as required by the method.

Result

HTTP200 OK
results
array of call results

The results of each method call, in order.

Events

Methods to retrieve and manipulate events.

Get events

idevents.getHTTPGET /events

Queries accessible events.

Parameters

fromTime
timestampoptional

The start time of the timeframe you want to retrieve events for. Default is 24 hours before toTime if the latter is set; otherwise it is not taken into account.

toTime
timestampoptional

The end time of the timeframe you want to retrieve events for. Default is the current time if fromTime is set. We recommend to set both fromTime and toTime (for example by choosing a very small number for fromTime or a large one for toTime if you want to retrieve all events). Note: events are considered to be within a given timeframe based on their time and duration.

streams
array of stream identifiers or streams queryoptional

Array of streamIds: Events assigned to any of the specified streams or their children will be returned.

or

Streams query: Object used for filtering events by complex streamIds relations.

By default, all accessible events are returned regardless of their stream.

tags
array of stringsoptional

(DEPRECATED) Please use streams query instead.

If set, only events assigned to any of the listed tags will be returned.

types
array of stringsoptional

If set, only events of any of the listed types will be returned.

content
array of content query conditionsoptional

If set, only events whose content matches all the conditions will be returned. See content query for the condition syntax, supported operators and availability. Server support is advertised by features.contentQueries in service info.

clientData
array of content query conditionsoptional

Same as content, applied to the events’ clientData. Conditions from both parameters must all match.

running
booleanoptional

If true, only running period events will be returned.

sortAscending
booleanoptional

If true, events will be sorted from oldest to newest. Default: false (sort descending).

skip
numberoptional

The number of items to skip in the results.

limit
numberoptional

The number of items to return in the results. A default value of 20 items is used if no other range limiting parameter is specified (fromTime, toTime).

state
default|trashed|alloptional

Indicates what items to return depending on their state. By default, only items that are not in the trash are returned; trashed returns only items in the trash, while all return all items regardless of their state.

modifiedSince
timestampoptional

If specified, only events modified since that time will be returned. Events the server writes or changes itself (createdBy / modifiedBy reading system, see event) are returned like any other.

includeDeletions
booleanoptional

Whether to include event deletions since modifiedSince for sync purposes (only applies when modifiedSince is set). Defaults to false.

Result

HTTP200 OK
events
array of events

The accessible events ordered by time (see sortAscending above).

eventDeletions
array of item deletionsoptional

If requested by includeDeletions, the event deletions since modifiedSince, ordered by deletion time.

Get one event

idevents.getOneHTTPGET /events/{id}

Fetches a specific event. This request is mostly used to fetch an event’s version history, allowing to review all the modifications to an event’s data.

Parameters

includeHistory
booleanoptional

If true, the event’s history will be added to the response. Default: false (don’t include the history).

Result

HTTP200 OK
event

The event.

history
array of eventsoptional

If requested by includeHistory, the history of the event as an array of events, ordered by modification time.

Create event

idevents.createHTTPPOST /events

Records a new event, in addition to JSON, this request accepts standard multipart/form-data content to support the creation of event with attached files in a single request. When sending a multipart request, one content part must hold the JSON for the new event and all other content parts must be the attached files.

Parameters

The new event’s data: see Event.

Result

HTTP201 Created
event

The created event.

Specific errors

invalid-operation
HTTP400

The referenced stream is in the trash, and we prevent the recording of new events into trashed streams.

Update event

idevents.updateHTTPPUT /events/{id}

Modifies the event.

Parameters

id
identifierHTTPset in request path

The id of the event.

update
objectHTTPrequest body

New values for the event’s fields: see event. All fields are optional, and only modified values must be included.

Result

HTTP200 OK
event

The updated event.

Add attachment(s)

idevents.addAttachmentHTTP-onlyPOST /events/{id}

Adds one or more file attachments to the event. This request expects standard multipart/form-data content, with all content parts being the attached files.

Result

HTTP200 OK
event

The updated event.

Get attachment

idevents.getAttachmentHTTP-onlyGET /events/{id}/{fileId}[/{fileName}]

Gets the attached file. Accepts an arbitrary filename path suffix (ignored) for easier link readability. For this function using the auth query parameter is not accepted. You can either use the access token in the Authorization header or provide the readToken as query parameter.

Parameters

readToken
stringHTTPset in request path

Required if not using the Authorization HTTP header. The file read token to authentify the request. See event.attachments[].readToken for more info.

Result

HTTP200 OK

The file’s content, with a Digest header with SHA-256 hash of the file, encoded in base64, SHA-256=.... to check file integrity see RFC3230 and RFC5843

The file is always sent with Content-Disposition: attachment. Since open-pryv.io 2.0.0-rc.34, a file whose content type a browser executes or renders as a document (HTML, XHTML, SVG, XML, XSL, any +xml type, multipart/x-mixed-replace, JavaScript) is also sent with Content-Security-Policy: sandbox; default-src 'none': opened on the API’s origin, it cannot run scripts, load resources or call the API with the viewer’s session. To display such a file, fetch its content and render it in your app’s own sandbox. An SVG used as an <img src> is not affected.

Get event preview

idevents.getPreviewHTTP-onlyGET /previews/events/{id}[.jpg|.jpeg]

Gets a JPEG preview of a picture/attached event’s image, resized from its first attachment. Previews are generated on first request and cached until the event is modified. Authenticate with the access token in the Authorization header or the auth query parameter; the access needs read permission on one of the event’s streams.

Previews are served by the core’s previews worker (on by default). Since open-pryv.io 2.0.0-rc.36 this URL is answered on the API’s public port, like every other API call; before, it was reachable only through a reverse proxy routing it to the worker.

Parameters

id
identifierHTTPset in request path

The id of the event. An optional .jpg or .jpeg suffix is accepted.

w
numberoptional

The desired width in pixels (alias: width). Rounded up to 256, 512, 768 or 1024 (the maximum); the height follows the image’s aspect ratio.

h
numberoptional

The desired height in pixels (alias: height), rounded the same way. When both are set, the preview fits within them. When neither is set, the preview is 256 × 256.

Preview

HTTP200 OK

The preview image, Content-Type: image/jpeg.

No preview

HTTP204 No Content

The event is not of type picture/attached.

Delete attachment

idevents.deleteAttachmentHTTPDELETE /events/{id}/{fileId}

Irreversibly deletes the attached file.

Parameters

id
identifierHTTPset in request path

The id of the event.

fileId
identifierHTTPset in request path

The id of the attached file.

Result

HTTP200 OK
event

The updated event.

Delete event

idevents.deleteHTTPDELETE /events/{id}

Trashes or deletes the specified event, depending on its current state:

  • If the event is not already in the trash, it will be moved to the trash (i.e. flagged as trashed)
  • If the event is already in the trash, it will be irreversibly deleted (including all its attached files, if any).

Parameters

id
identifierHTTPset in request path

The id of the event.

Result: trashed

HTTP200 OK
event

The trashed event.

Result: deleted

HTTP200 OK
eventDeletion

The event deletion record.

HF events

Methods to manipulate high-frequency data through HF events and HF series.

Create HF event

idhfs.createHTTPPOST /events

Creates a new event that will be holding HF series.

Parameters

The new event’s data: see Event.

The content of HF events is read-only, so you should not provide any content. However, the event type should correspond to the type of the data points in the series, prefixed with series:. For example, to store HF series of mass/kg data points, the type of the holder event should be series:mass/kg.

Result

HTTP201 Created
event

The created event.

Specific errors

invalid-operation
HTTP400

The referenced stream is in the trash, and we prevent the recording of new events into trashed streams.

invalid-parameters-format
HTTP400

The event content’s format is invalid. Events of type High-frequency have a read-only content.

Get HF series data points

idhfs.getHTTP-onlyGET /events/{id}/series

Retrieves HF series data points from a HF event. Returns data in order of ascending deltaTime between “fromTime” and “toTime”. Data is returned as input, no sampling or aggregation is performed.

Parameters

fromDeltaTime
timestampoptional

Only returns data points later than this deltaTime. If no value is given the query will return data starting at the earliest deltaTime in the series.

toDeltaTime
timestampoptional

Only returns data points earlier than this deltaTime. If no value is given the server will return only data that is in the past.

Result

HTTP200 OK

The HF series data points.

Add HF series data points

idhfs.addHTTP-onlyPOST /events/{id}/series

Adds new HF series data points to a HF event.

The HF series data will only store one set of values for any given deltaTime. This means you can update existing data points by ‘adding’ new data with the original deltaTime.

Parameters

The new HF series data point(s), see HF series.

Result

HTTP200 OK
status
string

The string “ok”.

Specific errors

invalid-operation
HTTP400

The event is not a HF event.

invalid-operation
HTTP400

The referenced HF event is in the trash, and we prevent the recording of new data points into trashed events.

Add HF series batch

idhfs.addBatchHTTP-onlyPOST /series/batch

Adds data to multiple HF series (stored in multiple HF events) in a single atomic operation. This is the fastest way to append data to Pryv; it allows transferring many data points in a single request.

For this operation to be successful, all of the following conditions must be fulfilled:

  • The access token needs write permissions to all series identified by “eventId”.
  • All events referred to must be HF events (type starts with the string “series:”).
  • Fields identified in each individual message must match those specified by the type of the HF event; there must be no duplicates.
  • All the values in every data point must conform to the type specification.

If any part of the batch message is invalid, the entire batch is aborted and the returned result body identifies the error.

Parameters

format
string

The format string “seriesBatch”.

data
array

Array of batch entries. Each batch entry is defined as follows:

eventId
string

The id of the HF event.

data
object

HF series data to add to the HF event.

Result

HTTP201 Created
status
string

The string “ok”.

Specific errors

invalid-request-structure
HTTP400

The request was malformed and could not be executed. The entire operation was aborted.

Update HF event

idhfs.updateHTTPPUT /events/{id}

Similar to the standard Update event method.

You may update all non read-only fields, except content which is read-only for HF events.

Specific errors

invalid-parameters-format
HTTP400

The event content’s format is invalid. Events of type High-frequency have a read-only content.

Delete HF event

idhfs.deleteHTTPDELETE /events/{id}

Similar to the standard Delete event method.

Streams

Methods to retrieve and manipulate streams.

Get streams

idstreams.getHTTPGET /streams

Gets the accessible streams hierarchy.

Parameters

parentId
identifieroptional

The id of the parent stream from which to retrieve streams. Default: null (returns all accessible streams from the root level).

state
default|alloptional

By default, only items that are not in the trash are returned; all return all items regardless of their state.

includeDeletionsSince
timestampoptional

Whether to include stream deletions since that time for sync purposes.

Result

HTTP200 OK
streams
array of streams

The tree of the accessible streams, sorted by name.

streamDeletions
array of item deletionsoptional

If requested by includeDeletionsSince, the stream deletions since then, ordered by deletion time.

Create stream

idstreams.createHTTPPOST /streams

Creates a new stream.

Parameters

The new stream’s data: see stream.

Result

HTTP201 Created
stream

The created stream.

Specific errors

item-already-exists
HTTP409

A similar stream already exists. The error’s data contains the conflicting properties.

invalid-item-id
HTTP400

The specified id is invalid (e.g. it’s a reserved word such as null).

Update stream

idstreams.updateHTTPPUT /streams/{id}

Modifies the stream.

Parameters

id
identifierHTTPset in request path

The id of the stream.

update
objectHTTPrequest body

New values for the stream’s fields: see stream. All fields are optional, and only modified values must be included.

Result

HTTP200 OK
stream

The updated stream (without child streams).

Specific errors

item-already-exists
HTTP409

A similar stream already exists. The error’s data contains the conflicting properties.

Delete stream

idstreams.deleteHTTPDELETE /streams/{id}

Trashes or deletes the specified stream, depending on its current state:

  • If the stream is not already in the trash, it will be moved to the trash (i.e. flagged as trashed)
  • If the stream is already in the trash, it will be irreversibly deleted with its descendants (if any). If events exist that refer to the deleted item(s), you must indicate how to handle them with the parameter mergeEventsWithParent.

Since the deletion removes the whole subtree, an access other than a personal one needs a manage permission on every stream of the subtree (the stream and all its descendants), not only on the stream itself; with mergeEventsWithParent=true it also needs the right to create events on the parent stream, which receives them (create-only, contribute or manage). Otherwise the call answers 403 forbidden and nothing is deleted.

Parameters

id
identifierHTTPset in request path

The id of the stream.

mergeEventsWithParent
boolean

Required if actually deleting the item and if it (or any of its descendants) has linked events, ignored otherwise. If true, the linked events will be assigned to the parent of the deleted item; if false, the linked events will be deleted.

Result: trashed

HTTP200 OK
stream

The trashed stream.

Result: deleted

HTTP200 OK
streamDeletion

The stream deletion record.

Accesses

Methods to retrieve and manipulate accesses, e.g. for sharing. Any app token can manage shared accesses it created. Full access management is available to personal tokens.

Get accesses

v2idaccesses.getHTTPGET /accesses

Gets accesses that were created by your access token, unless you’re using a personal token then it returns all accesses. Only returns accesses that are active when making the request. To include accesses that have expired or were deleted, use the includeExpired or includeDeletions parameters respectively.

A delegated personal access (account delegation) also lists all accesses, but receives token and apiEndpoint only for itself and for the accesses it created; the other accesses are returned without them.

In v2 the returned id, createdBy, and modifiedBy fields use the composite reference format <base>:<serial> for accesses that have been updated at least once. Never-updated accesses still serialise as bare cuid (<base>) for full backwards-compatibility. Parse with pryv.utils.parseAccessRef(ref) if you need to extract the version.

Parameters

includeExpired
booleanoptional

If true, also includes expired accesses. Defaults to false.

includeDeletions
booleanoptional

If true, also includes deleted accesses. Defaults to false.

Result

HTTP200 OK
accesses
array of accesses

All manageable accesses in the user’s account, ordered by name.

accessDeletions
array of deleted accesses

If requested by includeDeletions, the access deletions, ordered by deletion time.

Get one access

v2idaccesses.getOneHTTPGET /accesses/{id}

Returns the access identified by {id}. The id can be either:

  • bare <base>, returns the current head row.
  • composite <base>:<serial> matching the current head’s serial, returns the current head row.
  • composite <base>:<serial> referring to an older serial, returns the historical snapshot from that version, alongside a current hint pointing at the live head’s composite id. Mirrors GitHub’s GET /repos/X/Y/commits/<sha> behaviour for ref-by-version.
  • any other id (unknown base, or a serial that never existed), 404 unknown-resource.

Pass ?includeHistory=true to also return the full chronological history of the access (oldest first) in a history array. Default false, the singular case covers the typical “audit this access” use case without the list-side overhead.

App callers can only fetch their own access (self) or shared accesses they directly manage; other access ids return 404 unknown-resource to avoid info leakage.

A delegated personal access (account delegation) receives token and apiEndpoint (in access and in history) only for itself and for the accesses it created.

Parameters

id
identifierHTTPset in request path

The access id to fetch. Bare cuid on never-updated accesses, composite <base>:<serial> once versioned.

includeHistory
booleanoptional

If true, include the chronological history of the access. Defaults to false.

Result

HTTP200 OK
access

The requested access (current head, or historical snapshot when the id targets an older serial).

current
stringoptional

Set when the request targeted an older serial, the composite id <base>:<serial> of the current head.

history
array of accessesoptional

Set when includeHistory=true, the chronological history of the access (oldest first). Each entry uses the composite id of the frozen version.

Specific errors

unknown-resource
HTTP404

The access does not exist, was soft-deleted, or the caller cannot see it (app caller visibility rule).

Create access

v2idaccesses.createHTTPPOST /accesses

Creates a new access. You can only create accesses whose permissions are a subset of those granted to your own access token.

v2 behaviour change (Pryv.io ≥ 2.0.0-pre.X): when an app access creates a shared access scoped under it, the new shared’s expires (resolved from expireAfter if provided) cannot exceed the managing app’s expires. Violations return invalid-operation with data: { parentExpires, requestedExpires }. A shared access created by an expiring app without expireAfter takes the app’s expires, so it never outlives it. Personal-issued accesses are not subject to this check (personal accesses typically have no expires).

Parameters

An object with the new access’s data: see access.

randomAlias
booleanoptional

When true, the access is issued a platform-unique, routable alias (r- followed by 8 characters) that replaces the username in the returned apiEndpoint and in the access-info response. The real username never appears for this access, so accesses handed to different parties cannot be cross-matched back to one account. The resolved value is returned as the access’s alias.

Result

HTTP201 Created
access

The created access. When randomAlias was set, its alias holds the issued alias and apiEndpoint is built from the alias.

Specific errors

invalid-item-id
HTTP400

The specified token is invalid (e.g. it’s a reserved word such as null).

Update access

v2idaccesses.updateHTTPPUT /accesses/{id}

Updates the access identified by {id}. Each successful update mutates the head row, snapshots the prior state into history, and bumps the access’s serial. The returned access carries the new wire-format composite id <base>:<serial> (or bare <base> when never updated).

Mutable fields (whitelist): name, deviceName, permissions, expireAfter / expires, clientData. Anything else returns invalid-parameters-format.

Caller-vs-target matrix:

  • personal accesses are immutable (no caller can update them).
  • A personal access can update any app or shared access.
  • An app access can update only the shared accesses it directly manages.
  • shared accesses cannot update anything.
  • No self-update via this method (self-revoke stays available via accesses.delete).

Chain rules enforced on update:

  • A managed shared’s new permissions must remain a subset of its managing app’s permissions.
  • Narrowing an app’s permissions (or expires) is strict-rejected if any managed shared would now sit outside the new scope or outlive the new expiry. The error includes data.offendingChildren: [ids] so the caller can resolve children first and retry.
  • A managed shared’s expires cannot exceed its managing app’s expires (parent with expires: null imposes no cap). A managed shared without expiry counts as outliving any expiry: clearing a managed shared’s expiry (expires: null) under an expiring app is refused (data.requestedExpires: null), and giving an app an expiry while a shared it manages has none is refused with data.offendingChildren. At authentication, a shared without expiry is refused once its managing app has expired.

Expiry: expireAfter (seconds, not negative) sets expires to the time of the update plus that many seconds; expires: null removes the expiry. deviceName applies to app accesses only, and an OAuth session access (named oauth:<clientId>) cannot be renamed.

Composite-id conflict: the {id} must match the current head’s serial. A stale composite returns 409 stale-resource with data: { provided, currentSerial }; refetch the access via Get one access and retry with the current head id. Bare <base> is only valid on a never-updated access.

When the caller is a delegated personal access (account delegation), the returned access carries token and apiEndpoint only if the delegated access created it.

On success, the server emits an accessesChanged socket.io event (coarse-grained) and an accessUpdated event with payload { type: 'access-updated', accessId, serial } (fine-grained).

Parameters

id
identifierHTTPset in request path

The access id (bare or composite) to update.

update
objectHTTPrequest body

Subset of mutable fields (name, deviceName, permissions, expireAfter, expires: null, clientData). Sent as the HTTP request body, the server wraps it into params.update.

Result

HTTP200 OK
access

The updated head, with new composite id and bumped serial.

Specific errors

stale-resource
HTTP409

The provided composite {id} does not match the current head’s serial. Refetch via accesses.getOne and retry.

invalid-operation
HTTP400

Chain rule violation. data.offendingChildren lists shared accesses that would be orphaned by a narrowing; data.parentExpires / data.requestedExpires are set for expiry-chain rejections.

forbidden
HTTP403

Caller is not allowed to update the target (personal access, self-update, app-trying-to-update-a-non-managed-access, or shared caller).

unknown-resource
HTTP404

Access not found or soft-deleted.

Delete access

v2idaccesses.deleteHTTPDELETE /accesses/{id}

Deletes the specified access. Personal accesses can delete any access. App accesses can delete shared accesses they created. Deleting an app access deletes the shared ones it created. All accesses can also perform a self-delete unless a forbidden selfRevoke permission has been set.

Deleting the data grant of a cross-account messaging consent withdraws that consent, and the requester is sent consent/revoke-cmc (best-effort). The person’s consent/accept-cmc event then records the withdrawal, content.withdrawal = { at, by: 'accesses.delete', accessId }, shortly after this call answers. Requires open-pryv.io 2.0.0-rc.36 or later for the withdrawal record.

v2 behaviour change (Pryv.io ≥ 2.0.0-pre.X): the {id} is composite-aware, pass the composite <base>:<serial> you last observed via Get accesses or Get one access. A stale composite returns 409 stale-resource with data: { provided, currentSerial }; refetch and retry. Bare <base> is only valid on a never-updated access.

Parameters

id
identifierHTTPset in request path

The id of the access.

Result

HTTP200 OK
accessDeletion

The deletion record.

relatedDeletions
array of item deletionsoptional

The deletion records of all the shared accesses that were generated from this app token when deleting it

Access Info

idgetAccessInfoHTTPGET /access-info

Retrieves information about the access in use.

Result

HTTP200 OK

The current Access properties, as well as:

calls

A map of API methods and the number of time each of them was called using the current access.

user

A map of user account properties.

delegation
objectoptional

Present only when the access comes from account delegation; absent for every other access. user.username stays the account the access lives on.

For a delegate token, and for an access granted with one (an app access an auth page created for an account the user controls, and the accesses that app creates in turn): { isDelegatedAccess: true, controlledUsername, delegate: { username, hostSlug } }, plus grantedVia: "app" for a granted access. For a control access: { kind: "control", controlledUsername, delegate }.

This is the authoritative answer to “is this app acting for a controlled account?”: the delegation block of an accepted auth request is only a display hint.

isDelegatedAccess
trueoptional

Set for a delegate token and for an access granted through a delegation.

controlledUsername
string

The controlled account (the account the access lives on).

delegate
object

The delegate the access acts for: username, and hostSlug (its core) when known.

grantedVia
appoptional

Set when the access was granted through the delegation rather than being the delegate token itself. Such an access is revoked when the delegate is removed from the controlled account.

kind
controloptional

Set, instead of isDelegatedAccess, for a control access.

Webhooks

Methods to retrieve and manipulate webhooks. These methods are only allowed for app and personal accesses.

Get webhooks

idwebhooks.getHTTPGET /webhooks

Gets manageable webhooks. Only returns webhooks that were created by the access, unless you are using a personal access which returns all existing webhooks in the user’s account.

Parameters

Result

HTTP200 OK
webhooks
array of webhooks

All manageable webhooks by the given access, ordered by modified date.

Get one webhook

idwebhooks.getOneHTTPGET /webhooks/{id}

Fetches a specific webhook. Only returns a webhook if it was created by the access, unless you are using a personal access which is allowed to fetch any existing webhook in the user’s account.

Parameters

id
identifierHTTPset in request path

The id of the webhook.

Result

HTTP200 OK
webhook

The webhook.

Create webhook

idwebhooks.createHTTPPOST /webhooks

Creates a new webhook. You can only create webhooks with app and shared accesses. An access carrying the feature permission { "feature": "webhooks", "setting": "forbidden" } cannot create webhooks (403 forbidden).

Only url and scopes are accepted; every other field of the webhook (id, state, retry settings, run counters, tracking properties) is set by the server, and sending one is refused. See the webhook’s url for the destinations a webhook can call.

Parameters

url
string

The URL the webhook posts to: https or http, without credentials (user:password@), at most 2048 characters.

scopes
objectoptional

Named scopes restricting the webhook to specific changes: see webhook.

Result

HTTP201 Created
webhook

The created webhook.

Specific errors

invalid-parameters-format
HTTP400

A field other than url and scopes is sent, or the url is not accepted (not http(s), with credentials, or too long).

Update webhook

idwebhooks.updateHTTPPUT /webhooks/{id}

Modifies the webhook. You can only modify webhooks with the access that was used to create them, unless you are using a personal token. Updating the state to active resets the currentRetries counter. Refused (403 forbidden) for an access carrying the feature permission webhooks: forbidden. A webhook owned by such an access does not fire: it is set inactive when it next would.

Parameters

id
identifierHTTPset in request path

The id of the webhook.

update
objectHTTPrequest body

New values for the webhook’s alterable fields: state (active or inactive) and scopes (see webhook). Both are optional, and only modified values must be included.

Result

HTTP200 OK
webhook

The updated webhook.

Specific errors

item-already-exists
HTTP409

There is already a webhook for this URL created by the given access.

Delete webhook

idwebhooks.deleteHTTPDELETE /webhooks/{id}

Deletes the specified webhook. You can only delete webhooks with the access that was used to create them, unless you are using a personal token.

Parameters

id
identifierHTTPset in request path

The id of the webhook.

Result

HTTP200 OK
webhookDeletion

The deletion record.

Test webhook

idwebhooks.testHTTPPOST /webhooks/{id}/test

Sends a post request containing a message called test to the URL of the specified webhook’s url. You can only test webhooks with the access that was used to create them, unless you are using a personal token.

The call follows the same rules as the webhook’s own calls (destination checked, no redirect followed, platform timeout). Whatever the reason of a failure, the answer is the same error.

Refused (403 forbidden) for an access carrying the feature permission webhooks: forbidden.

Parameters

id
identifierHTTPset in request path

The id of the webhook.

Result

HTTP200 OK
webhook

The webhook.

Specific errors

unknown-referenced-resource
HTTP400

The call failed: the destination is not accepted, cannot be reached or does not answer in time, or it answers with a status outside 2xx (a redirect included).

Shared secrets

Hand a secret to a third party by a one-time random key instead of embedding the credential (typically an apiEndpoint carrying an access token) in a URL, where it would persist in browser history, Referer headers and server access logs.

A key is redeemable exactly once and expires after a mandatory TTL. The server stores only the SHA-256 of the key’s random half, so the clear key exists only in the creation response and cannot be recovered afterwards.

The secret is scrubbed the moment the item stops being pending: when the key is redeemed, when the item is discarded, or on the first retrieval attempt made after the TTL has passed. Expiry is enforced on access, not by a background sweeper, so an item that expires and is never touched again keeps its stored payload until something reaches it or it is removed with events.delete.

The redemption call needs no credentials (the key itself is the credential), so the key always travels in the request body, never in the URL.

Shared secrets are stored as events under a reserved per-access stream and can be listed with a standard events.get naming that stream explicitly; they never appear in a wildcard query. An access can be barred from creating them with the secretSharing feature permission.

The feature is optional: on a platform where the operator has disabled it, all three methods below answer 451 unavailable-method.

Create shared secret

idsharedSecrets.createHTTPPOST /shared-secrets

Stores a secret and returns a one-time key for it. The key is returned once and is not recoverable afterwards. Requires an access whose secretSharing feature permission is not forbidden.

Parameters

ttl
number

Seconds the key stays redeemable. Required, must be greater than 0 and not exceed the configured maximum (30 days by default).

title
string

A label shown to the account owner.

onConsumed
object

{ message, returnUrl } returned to whoever presents the key once it is no longer available. message is required; the optional returnUrl must be an http(s) URL (it is followed by an unauthenticated third party).

secret
object

The payload to hand over: any non-null JSON value. Its serialized size must not exceed the configured maximum (4096 bytes by default).

signature
objectoptional

Optional proof required to redeem. { type: "secret", value } compares a passphrase shared out-of-band; { type: "hmac-sha256", value } verifies an HMAC the redeemer computes from a verifier secret that never reaches the server. For hmac-sha256, value must be the lowercase-hex HMAC-SHA256(verifierSecret, randomHalf) where randomHalf is the part of the key after the dot: the server compares the redeemer’s proof against this stored string byte-for-byte, so both sides must derive it the same way. A wrong proof discards the secret; a missing one is refused without discarding it.

keyHash
stringoptional

Hex SHA-256 of a random half you generate yourself (at least 192 bits of entropy), for binding an hmac-sha256 signature to the key before the item exists. When supplied, the response carries no key: compose it yourself as {id}.{yourRandomHalf}. Omit it to let the server mint and return the key.

The random half must be 32 to 128 characters from the base64url alphabet (A-Za-z0-9_-); lowercase hex qualifies. Creation only checks the hash, so a half that breaks this rule (standard base64 padding, for instance) is accepted here and then fails every redemption with the uniform refusal, leaving a secret that can never be reached.

Result

HTTP201 Created
sharedSecret
object

{ id, key, status, title, statusHistory, onConsumed, expires }, plus signatureType when a signature was set. key is present only when the server minted it (i.e. keyHash was not supplied) and is returned this one time only.

Specific errors

invalid-parameters-format
HTTP400

A required field is missing or malformed, including a non-positive or too-long ttl, an oversized secret, a non-http(s) returnUrl, or an unknown signature type.

forbidden
HTTP403

The access is barred from creating shared secrets by a secretSharing: forbidden feature permission.

Redeem shared secret

idsharedSecrets.retrieveHTTPPOST /shared-secrets/retrieve

Redeems a key for its secret. Unauthenticated (the key is the credential), so no access token is required. Succeeds exactly once; every later attempt returns the creator’s onConsumed message. Unknown or malformed keys receive a single uniform refusal that does not reveal whether a given item exists.

Parameters

key
string

The one-time key, as returned by (or composed from) the create call.

signature
objectoptional

{ type, payload } proof, required only if the secret was created with a signature. For secret, payload is the passphrase; for hmac-sha256, payload is the lowercase-hex HMAC-SHA256(verifierSecret, randomHalf), computed over the part of the key after the dot.

A wrong proof discards the secret permanently; nobody can redeem it afterwards. A missing proof is refused without discarding anything, so a client that knows a proof is needed may retry. There is no way to tell from the response that a proof is required: the refusal is byte-identical to the one for an already-consumed item, so the redeemer must learn it from the creator.

Result

HTTP200 OK
secret
object

The stored secret payload.

Specific errors

unknown-resource
HTTP404

The uniform refusal: the key is malformed, names nothing, or does not match the stored hash. It is deliberately the same answer in every case, so it cannot be used to learn whether an item exists, and it never consumes or discards anything.

forbidden
HTTP403

The secret is no longer available (already redeemed, expired, or discarded), or the signature proof was wrong. The response carries the creator’s message and optional returnUrl.

Get shared secret status

idsharedSecrets.getOneHTTPPOST /shared-secrets/status

Returns the status and metadata of a shared secret without consuming it. Available to the access that created the secret or to a personal token. Never returns the secret payload. An item past its TTL is reported as expired even before it is redeemed.

Parameters

key
string

The one-time key.

Result

HTTP200 OK
sharedSecret
object

{ id, title, status, statusHistory, onConsumed, expires }, plus signatureType when a signature was set and expired: true when the TTL has passed (the reported status is then discarded, though the stored item is left untouched). Never includes the secret.

Specific errors

unknown-resource
HTTP404

The key is malformed, names nothing, does not match the stored hash, or the caller is neither the access that created the secret nor a personal token. All four give the same answer, so status cannot be used to probe a key.

Profile sets

Methods to read and write profile sets. Profile sets are plain key-value stores of user-level settings.

Get app profile

idprofile.getAppHTTPGET /profile/app

Gets the app’s dedicated profile set, which contains app-level settings for the user. Available to app accesses.

Result

HTTP200 OK
profile
object

The app profile set. (Empty if the app never defined any setting.)

Update app profile

idprofile.updateAppHTTPPUT /profile/app

Adds, updates or delete app profile keys. Available to app accesses.

  • To add or update a key, just set its value
  • To delete a key, set its value to null

Existing keys not included in the update are left untouched.

Parameters

update
objectHTTPrequest body

An object with the desired key changes (see above).

Result

HTTP200 OK
profile
object

The updated app profile set.

Get public profile

idprofile.getPublicHTTPGET /profile/public

Gets the public profile set, which contains the information the user makes publicly available (e.g. avatar image). Available to all accesses.

Result

HTTP200 OK
profile
object

The public profile set.

Update public profile

idprofile.updatePublicHTTPPUT /profile/public

Adds, updates or delete public profile keys. Available to personal accesses.

  • To add or update a key, just set its value
  • To delete a key, set its value to null

Existing keys not included in the update are left untouched.

Parameters

update
objectHTTPrequest body

An object with the desired key changes (see above).

Result

HTTP200 OK
profile
object

The updated public profile set.

Get private profile

idprofile.getPrivateHTTPGET /profile/private

Gets the private profile set. Available to personal accesses.

Result

HTTP200 OK
profile
object

The private profile set.

Update private profile

idprofile.updatePrivateHTTPPUT /profile/private

Adds, updates or delete private profile keys. Available to personal accesses.

  • To add or update a key, just set its value
  • To delete a key, set its value to null

Existing keys not included in the update are left untouched.

Result

HTTP200 OK
profile
object

The updated private profile set.

Account delegation

Methods to manage account delegation: letting one account (a delegate, e.g. a parent or guardian) control another (a controlled account, e.g. a child or dependent).

A controlled account invites a delegate with invite a delegate; the delegate accepts with accept a delegation. A delegate may also create a controlled account outright with create a controlled account, and obtain a delegate access token for an active relationship with get a delegate token. A delegate token is a personal-class token that can do everything on the controlled account except remove a delegation: removing a delegation (detach, cancel invite) requires a genuine direct login on the controlled account, never a delegated session. See the Account delegation guide.

Requires the delegation:active platform setting (default on). All methods below require a personal access token; the genuine-login-only methods additionally reject delegate tokens. A set of internal core-to-core endpoints under /delegations/controlled-side/* handles cross-core handshake delivery and token issuance; they are authorized by plugin-minted marker credentials and are not called directly by clients.

Invite a delegate

v2iddelegations.requestAttachHTTPPOST /delegations/attach-request

Called by a controlled account to invite another account to become its delegate. Creates a pending invite the delegate can accept with accept a delegation. Requires a personal access token.

Parameters

delegateUsername
string

The username of the account being invited to control this one.

Result

HTTP201 Created
delegation
object

The created relationship: relId, delegate ({ username }), status ("invite"), and the requestedAt / expiresAt Unix timestamps.

Specific errors

delegation-unknown-username
HTTP404

The delegate account does not exist.

delegation-self-not-allowed
HTTP400

An account may not delegate to itself.

delegation-already-exists
HTTP409

A pending or active delegation to this delegate already exists.

delegation-delivery-failed
HTTP503

The invite could not be delivered to the delegate’s core.

Accept a delegation

v2iddelegations.acceptAttachHTTPPOST /delegations/controlled/{username}/accept

Called by an invited delegate to accept a pending delegation from the controlled account {username}. Idempotent: re-accepting an already active relationship returns the settled record. Requires a personal access token.

Parameters

username
stringHTTPset in request path

The username of the controlled account whose invite is being accepted.

Result

HTTP200 OK
delegation
object

The now-active relationship: relId, controlled ({ username, hostSlug }), status ("active") and activatedAt.

Specific errors

delegation-not-found
HTTP404

No pending invite from that controlled account.

delegation-invite-expired
HTTP410

The invite has expired or is no longer valid on the controlled account.

delegation-delivery-failed
HTTP503

The controlled account’s core could not be reached to confirm activation.

Refuse a delegation

v2iddelegations.refuseAttachHTTPPOST /delegations/controlled/{username}/refuse

Called by an invited delegate to decline a pending delegation from the controlled account {username}. Requires a personal access token.

Parameters

username
stringHTTPset in request path

The username of the controlled account whose invite is being refused.

Result

HTTP200 OK

Specific errors

delegation-not-found
HTTP404

No pending invite from that controlled account.

Cancel a sent invite

v2iddelegations.cancelInviteHTTPPOST /delegations/delegates/{username}/cancel

Called by a controlled account to cancel a pending invite it sent to {username}. Because cancelling removes a relationship record, it requires a genuine direct login on the controlled account: a delegate token is refused.

Parameters

username
stringHTTPset in request path

The username of the invited delegate whose pending invite is being cancelled.

Result

HTTP200 OK

Specific errors

delegation-genuine-login-required
HTTP403

The request used a delegate (or non-personal) token. A genuine login on the controlled account is required.

List delegates

v2iddelegations.listDelegatesHTTPGET /delegations/delegates

Lists the delegates that control this account (from the controlled account’s view). Requires a personal access token.

Result

HTTP200 OK
delegates
array of objects

One entry per delegate: relId, delegate ({ username, hostSlug }), status ("invite" | "active" | "stale"), requestedAt, activatedAt and lastTokenIssuedAt.

List controlled accounts

v2iddelegations.listControlledHTTPGET /delegations/controlled

Lists the accounts this account controls as a delegate (from the delegate’s view). Requires a personal access token.

Result

HTTP200 OK
controlled
array of objects

One entry per controlled account: relId, controlled ({ username, hostSlug }), status ("invite" | "active" | "stale"), requestedAt and activatedAt.

Create a controlled account

v2iddelegations.createAccountHTTPPOST /delegations/controlled

Called by a delegate to create a brand-new controlled account, active from birth, with this account as its delegate. The new account has no email and no usable password unless supplied, so it is reachable only through its delegates until someone sets real credentials. On a multi-core platform the target core defaults to the delegate’s own core. Requires a personal access token.

Parameters

username
string

The username for the new controlled account. Must be available and not reserved.

email
stringoptional

Optional e-mail address for the new account.

password
stringoptional

Optional password. When omitted, the account has no usable password and is reachable only via its delegates until one is set.

core
stringoptional

Optional target core (its id or URL) on a multi-core platform. Defaults to the delegate’s own core.

language
stringoptional

Optional two-letter language code for the new account.

Result

HTTP201 Created
delegation
object

The active relationship to the new account: relId, controlled ({ username, hostSlug }), status ("active") and activatedAt.

Specific errors

delegation-unknown-username
HTTP400

A username for the new account is required.

delegation-self-not-allowed
HTTP400

An account may not delegate to itself.

delegation-unknown-core
HTTP400

The requested target core is unknown to this platform.

delegation-username-taken
HTTP409

The requested username is already taken.

delegation-creation-failed
HTTP502

The target core could not create the account.

Get a delegate token

v2iddelegations.getTokenHTTPPOST /delegations/controlled/{username}/token

Called by a delegate to obtain a delegate access token for an active controlled account {username}. The returned token is a personal-class token over the controlled account, and its apiEndpoint points at the controlled account’s core so the delegate’s client talks to that core directly. Re-issuing while the session is alive returns the same token. Requires a personal access token.

Parameters

username
stringHTTPset in request path

The username of the active controlled account to get a token for.

Result

HTTP200 OK
token
string

The delegate access token (a personal-class token over the controlled account).

apiEndpoint
string

The controlled account’s API endpoint (token embedded), to be used directly against its core.

Specific errors

delegation-not-found
HTTP404

No delegation relationship with that controlled account.

delegation-not-active
HTTP410

The relationship is not active (for example it was detached on the controlled account).

delegation-delivery-failed
HTTP503

The controlled account’s core could not be reached to issue a token.

Detach a delegate

v2iddelegations.detachDelegateHTTPDELETE /delegations/delegates/{username}

Called by a controlled account to remove a delegate {username}. This is the authoritative teardown: it kills the delegate’s token and control access on this account, then best-effort notifies the delegate; a still-pending invite is cancelled instead. Because it removes a delegation relationship, it requires a genuine direct login on the controlled account: a delegate token is refused.

Parameters

username
stringHTTPset in request path

The username of the delegate to detach.

keepAccessIds
array of stringsoptional

The ids of the consent grants (cross-account messaging data grants) the delegate gave for this account that the account owner keeps. Over HTTP, repeat the query parameter: ?keepAccessIds=<id>&keepAccessIds=<id>. Nothing is kept by default.

A kept grant becomes the account owner’s own consent: its delegation lineage (clientData.delegation) is removed, access-info no longer reports a delegation, the requester is told nothing, and its accept event records content.ownerConfirmedAt (seconds). A grant not kept is deleted, its requester receives consent/revoke-cmc, and its accept event records content.withdrawal = { at, by: 'delegation-detach', relId } (the same server-owned record the other ways of ending a consent write, see Revoking). The other accesses granted through the delegation are deleted whatever this list holds.

Result

HTTP200 OK

Specific errors

delegation-invalid-keep-list
HTTP400

keepAccessIds is not an array of ids, or one of its ids is not a consent grant given through the relationship being removed. Nothing is written; error.data.accessId names the first id refused.

delegation-genuine-login-required
HTTP403

The request used a delegate (or non-personal) token. A genuine login on the controlled account is required to remove a delegation.

delegation-not-found
HTTP404

No delegation relationship with that delegate.

Dismiss a stale controlled entry

v2iddelegations.dismissControlledHTTPDELETE /delegations/controlled/{username}

Called by a delegate to remove a stale controlled-account entry from its own list (local housekeeping after the relationship ended on the controlled account). This removes no authority and never touches the controlled account. Only a stale entry may be dismissed. Requires a personal access token.

Parameters

username
stringHTTPset in request path

The username of the controlled account entry to dismiss.

Result

HTTP200 OK

Specific errors

delegation-not-found
HTTP404

No delegation relationship with that controlled account.

delegation-mirror-not-stale
HTTP409

The relationship is still invite or active; only a stale entry can be dismissed.

Data structure

Event

See also: core concepts.

id
identifieruniqueread-only (except at creation)

The identifier (collision-resistant cuid) for the event. Automatically generated if not set when creating the event.

streamIds
array of identifier

The ids of the belonging streams.

streamId

(DEPRECATED) Please use streamIds instead.

The id of the first element of the streamIds array.

time

The event’s time. For period events, this is the time the event started. Automatically set to the server time if not provided when creating the event.

duration
timestampoptional

If present and non-zero, indicates that the event is a period event. Running period events have a duration set to null. A duration set to zero is equivalent to no duration.

type
string

The type of the event. See the event type directory for a list of standard types.

content
any typeoptional

The type-specific content of the event, if any.

tags
array of stringsoptional (always present in read items)

(DEPRECATED) Please use streamIds instead.

The tags associated with the event.

description
stringoptional

User description or comment for the event.

attachments
array of attachment objectsoptionalread-only

An array describing the files attached to the event. Each item has the following structure:

id

The file’s id. The attached file’s URL is obtained by appending this id to the event’s resource URL.

fileName
string

The file’s name as uploaded.

type
string

The MIME type of the file.

size
number

The size of the file, in bytes.

readToken
string

The auth token to pass in the query string when reading the file (instead of the regular auth parameter). The token is unique for the file and the access used to read it. This is a security measure in situations where it is impractical to use the Authorization HTTP header and/or where the file’s URL is likely to be exposed. See also events method get attachment.

integrity
integrityoptionalread-only

Integrity check for attachment object.

clientData
key-valueoptional

Additional client data for the event.

trashed
booleanoptional

true if the event is in the trash.

integrity
integrityoptionalread-only

Integrity check for event object.

created
timestampread-only

The time the event was created.

createdBy
identifierread-only

The id of the access used to create the event. Reads system for an event the server writes itself on the user’s behalf (consent inbox copies and scope-update records, account email records, delegation records). Such events carry created, modified and modifiedBy like any other, so events.get with modifiedSince returns them. Since open-pryv.io 2.0.0-rc.48; events of this kind written by an earlier version get these fields when the operator runs the one-time repair.

modified
timestampread-only

The time the event was last modified.

modifiedBy
identifierread-only

The id of the last access used to modify the event. Reads system when the server itself made the last change (for example a consent request or trigger status, a consent withdrawal or a delegation record); the change also sets modified, so a modifiedSince sync returns the event. Since open-pryv.io 2.0.0-rc.48.

Stream

See also: core concepts.

id
identifieruniqueread-only (except at creation)

The identifier for the stream. Automatically generated if not set when creating the stream; slugified if necessary.

name
stringunique among siblings

A name identifying the stream for users. The name must be unique among the stream’s siblings in the streams tree structure.

parentId
identifieroptional

The identifier of the stream’s parent, if any. A value of null indicates that the stream has no parent (i.e. root stream).

clientData
key-valueoptional

Additional client data for the stream.

children
array of streamsread-only

The stream’s sub-streams, if any. This field cannot be set in requests creating a new streams: streams are created individually by design.

trashed
booleanoptional

true if the stream is in the trash.

created
timestampread-only

The time the stream was created.

createdBy
identifierread-only

The id of the access used to create the stream.

modified
timestampread-only

The time the stream was last modified.

modifiedBy
identifierread-only

The id of the last access used to modify the stream.

Access

See also: core concepts.

id
identifieruniqueread-only

The identifier for the access.

token
stringuniqueread-only (except at creation)

The token identifying the access. Automatically generated if not set when creating the access; slugified if necessary.

apiEndpoint
stringread-only

The API endpoint with the access’ authorization token. See app guidelines. When the access has an alias, the endpoint is built from the alias instead of the username.

alias
stringoptionalread-only

A platform-unique, routable de-identifying name (r- followed by 8 characters) substituted for the username in this access’s apiEndpoint and in the access-info response. Set by passing randomAlias: true when creating the access; released when the access is deleted.

type
personal|app|sharedoptionalread-only (except at creation)

The type — or usage — of the access. Default: shared.

name
stringunique per type and device

The name identifying the access for the user. (For personal and app access, the name is used as a technical identifier and not shown as-is to the user.)

Can be changed with update access, except on an OAuth session access (named oauth:<clientId>).

deviceName
stringunique per type and nameoptional

For app accesses only. The name of the client device running the app, if applicable. Can be changed with update access.

permissions
array of permission objects

Ignored for personal accesses. If permission levels conflict (e.g. stream set to “manage” and child stream set to “contribute”), the child stream level applies. Can be changed with update access, within the chain rules it enforces. Each permission object has the following structure:

streamId | tag
identifier | string

To be used with level property only. The id of the stream or the tag the permission applies to, or * for all streams/tags. Stream permissions are recursively applied to child streams.

level
read|contribute|manage|create-only

Used only with streamId or tag permissions. The level of access to the stream. With contribute, one can see and manipulate events for the stream/tag (and child streams for stream permissions); with manage, one can in addition create, modify and delete child streams.

The create-only level - only available for stream-based permissions - allows to read the stream and create events on it and its children.

feature
selfRevoke|secretSharing|webhooks

To be used only with setting property.

  • selfRevoke: with forbidden, the access cannot call accesses.delete {id} on itself (self revocation).
  • secretSharing: with forbidden, the access cannot create one-time shared secrets.
  • webhooks: with forbidden, the access cannot create, update or test webhooks, and the webhooks it owns do not fire.

An access carrying secretSharing or webhooks as forbidden passes the entry on to every access it creates; asking for allowed on such a child is refused.

setting
forbidden|allowed

To be used only with feature permission. forbidden restricts the access as described for each feature. allowed is the default and the explicit form of it.

lastUsed
timestampoptionalread-only

The time the access was last used.

expireAfter
numberoptional

If set, controls access expiry in seconds. When given a number in this attribute (positive or zero), the access will expire (and not be usable anymore) after this many seconds. Update access also accepts it and sets expires to the time of the update plus this many seconds.

expires
timestampoptional

If the access was set to expire: The timestamp after which the access will be deactivated. It is computed from expireAfter; update access accepts only null here, which removes the expiry.

deleted
timestampoptionalread-only

If the access has been deleted: The timestamp of the deletion.

clientData
key-valueoptional

Additional client data for the access. It can be set at creation and changed later with update access, for the accesses that method lets the caller update. An update merges the given keys into the stored ones as described in key-value (a key set to null is removed), and clientData: null removes all keys.

The dpop key is reserved for the sender-constrained (DPoP) key binding that the OAuth token endpoint writes: a create request that supplies it is refused, and an update that would add, change or remove it (including clientData: null on a bound access) is refused.

The delegation key is reserved: the server sets it on the accesses account delegation manages and on the accesses granted through a delegation, a request that supplies it is refused, and it is kept when the rest of clientData is updated.

integrity
integrityoptionalread-only

Integrity check for access object.

created
timestampread-only

The time the access was created.

createdBy
identifierread-only

The id of the access used to create the access.

modified
timestampread-only

The time the access was last modified.

modifiedBy
identifierread-only

The id of the last access used to modify the access.

HF series

High-frequency series are collections of homogenous data points.

To store a HF series in Pryv.io, you must first create a HF event.

Series data is encoded in the “flatJSON” format:

  • Each data point in a series has a "deltaTime" field that indicates its time difference, since the holder event’s timestamp. If a "timestamp" field is instead provided, the corresponding "deltaTime" will be automatically computed from the holder event’s timestamp.
  • For types that store a single value (e.g. “mass/kg”), a single additional field named "value" is created.
  • Types that contain multiple properties (e.g. “position/wgs84”) will have many fields, whose names can be inferred from the type reference.
  • Optional fields can either be provided or not; omitted values will be set as null.
format
string

The data format (for now only “flatJSON” format is supported).

fields
Array of fields

The “fields” array lists all the fields that you will be providing in the “points” array, including the “deltaTime” field in first position. If the data type contains a single field (ex.: mass/kg), the second field is “value”, otherwise, it is the list of fields with the required ones first.

points
Array of data points

The “points” array contains the data points, each data point is represented by a simple array. This makes the bulk of the message (your data points) very space-efficient; values are encoded positionally. The first value corresponds to the first field, and so on.

Webhook

Webhooks provide push notifications to web servers using HTTP POST requests.

Once created, they will run, executing a HTTP POST request to the provided URL for each data change in the user account.

When the webhooks service is booted, it will send a webhooksServiceBoot message to all active webhooks. This allows to query the API for potentially missed notifications during its down time.

Only the app access used to create the webhook or a personal access can retrieve and modify it. This is meant to separate the responsibilities between the actor that sets the webhooks and the one(s) that consume the data following the webhook setup.

id
identifierread-only

The identifier of the Webhook.

accessId
identifierread-only

The identifier of the access that was used to create the Webhook.

url
stringunique per app accessread-only (except at creation)

The URL where the HTTP POST requests will be made. To identify the source of the webhook on your notifications server, you can use the url’s hostname, path or query parameters. For example:

{
  "url": "https://${username}.my-notifications.com/${my-secret}/?param1=value1&param2=value2"
}

The URL must use https or http, carry no credentials (user:password@) and be at most 2048 characters long. At each call, the host is resolved and the call is not made when an address is not public: loopback, private networks, carrier-grade NAT, link-local (including cloud metadata services), unique-local or link-local IPv6, unspecified, multicast, broadcast or otherwise reserved. A platform can allow given hosts or ranges on its private network (webhooks.allowedPrivateHosts). Redirects are not followed (a 3xx answer is a failed call), and a call without an answer within the platform’s timeout (10 seconds by default, webhooks.requestTimeoutMs) is a failed call.

minIntervalMs
numberread-only

The webhooks run rate is throttled by a minimum interval between HTTP calls in milliseconds, sending an array of changes that occured during this period. Its value is set by the platform admin.

maxRetries
numberread-only

In case of failure to send a request, the webhook will retry maxRetries times at a growing interval of time before becoming inactive after too many successive failures. Its value is set by the platform admin.

currentRetries
numberread-only

The number of retries iterations since the last failed HTTP call. This number is 0 if the last HTTP call was successful.

state
active|inactive

The current state of the Webhook. An inactive Webhook will not make any HTTP call when changes occur. It must be activated using the update webhook method. Set by the server at creation (active); alterable with an update.

runCount
numberread-only

The number of times the Webhook has been run, including failures.

failCount
numberread-only

The number of times the Webhook has failed HTTP calls. Failed runs are HTTP requests that received a response with a status outside of the 200-299 range (redirects are not followed), no response in time, or were not made because the destination is not accepted.

lastRun
Run objectread-only

Represents the last Webhook call, comprised of its HTTP response status and timestamp.

status
number

The HTTP response status of the call.

timestamp

The time the call was started.

runs
array of Run objectsread-only

Array of Run objects in inverse chronological order (newest first) which allows to monitor a webhook’s health. Its length is set by the platform admin.

scopes
objectoptional

Optional map of named scopes that restrict the webhook to specific changes. When omitted, the webhook fires on every change in the account (default, unfiltered behaviour).

Each entry is keyed by a name you choose and has the shape { kind, query }:

  • kind — one of events (default), streams or accesses.
  • query — a filter shaped like the parameters of the matching read method: an events.get query for events (streams, types, content, clientData), a { streams } query for streams, or an accesses filter for accesses.

A scoped webhook receives notifications only for changes matching one of its scopes. Instead of the coarse eventsChanged / streamsChanged messages, the data changes payload then carries the matched scope keys — so your endpoint knows which subscription fired without inspecting the data:

{
  "scopes": {
    "newReadings": { "kind": "events", "query": { "streams": ["measurements"], "types": ["mass/kg"] } },
    "structure":   { "kind": "streams", "query": { "streams": ["measurements"] } }
  }
}

scopes is alterable: include it in an update webhook call to change the subscriptions of an existing webhook.

created
timestampread-only

The time the webhook was created.

createdBy
identifierread-only

The id of the access used to create the webhook.

modified
timestampread-only

The time the webhook was last modified.

modifiedBy
identifierread-only

The id of the last access used to modify the webhook.

Item deletion

A record of a deleted item for sync purposes.

id

The identifier of the deleted item.

deleted
timestampoptional

The time the item was deleted.

Key-value

An object (key-value map) for client apps to store additional data about the containing item (stream, event, etc.), such as a color, a reference to an associated icon, or other app-specific metadata.

Adding, updating and removing client data

When the containing item is updated, additional data fields can be added, updated and removed as follows:

  • To add or update a field, just set its value; for example: {"clientData": {"keyToAddOrUpdate": "value"}}
  • To delete a field, set its value to null; for example: {"clientData": {"keyToDelete": null}}

Fields you don’t specify in the update are left untouched.

Naming convention

The convention is that each app names the keys it uses with an {app-id}: prefix. For example, an app with id “riki” would store its data in fields such as "riki:key": "some value".

Error

id
string

Identifier for the error.

message
string

A human-readable description of the error.

data
any typeoptional

Additional machine-readable details (specified for each error if relevant).

subErrors
array of errorsoptional

Lists the detailed causes of the main error, if any.

streams query

The streams parameter for events.get query accepts an array of streamIds or a streams query for more complex requests.

Syntax:

The streams query must have at least one any property, with an optional not:

{ "any": ["streamA", "streamB"], "all": ["streamC"], "not": ["streamD"] }
  • any: any streamId must match
  • all: all streamIds must match
  • not: none of the streamIds must match

The returned events will be those matching all of the provided criteria.

Example:

To select all the events that are in activity or nutrition, tagged in health, but not in private:

{
  "any": ["activity", "nutrition"],
  "all": ["health"],
  "not": ["private"]
}

Format:

The JSON object representing the query must be sent stringified when passed as query parameter in a GET /events HTTP call. It can be sent as-is for batch and socket.io calls.

Content query

The content and clientData parameters of events.get each accept an array of conditions on the corresponding event field. All conditions (across both parameters) must match (AND); they combine freely with the other query parameters (streams, types, time bounds, paging).

Condition syntax:

Each condition is an object with a path and exactly one operator:

[
  { "path": "drug.codes.atc", "in": ["G03DA04", "B01AC06"] },
  { "path": "taken", "eq": true }
]
  • path: dot-separated segments addressing a value inside the field (segments match [a-zA-Z0-9_:-]+, so colon-namespaced clientData keys are queryable), or the reserved $ addressing the field’s root value (for scalar content, e.g. {"path": "$", "gte": 12}). No array indices or wildcards.
  • eq / neq: equals / exists-and-differs (string, number or boolean; null is not allowed — use exists)
  • in: equals any of the listed values (array of strings, numbers or booleans)
  • exists: true — a value is present at the path; false — no value at the path
  • gt, gte, lt, lte: numeric comparison (non-numeric values never match)
  • prefix: string value starts with the given prefix (covers hierarchical code classes, e.g. ATC "G03DA")

Matching is strict on JSON types: {"eq": true} matches JSON true only — never 1 nor "true"; numbers never match numeric strings. A missing path never matches any operator (use {"exists": false} to select absence). Only current event versions are considered.

Availability and performance:

Content queries work on every supporting deployment without any setup (engines scan). Operators can declare frequently-queried paths in the platform-wide storages.contentIndexes configuration to create acceleration indexes — declaration changes are reconciled at startup and never affect results, only speed.

Support is advertised by features.contentQueries: true in service info; older servers reject the parameters with a 400 error. Custom data stores declare their (possibly partial) support per field and operator; the declaration is visible to clients in the clientData of the store’s root stream under pryv-datastore:supports, and unsupported conditions are rejected with an invalid-operation error rather than returning unfiltered results.

Cross-references between events (convention):

To reference source events (e.g. events derived from a document), set outbound references under the related key of the referencing event’s clientData, mapping each referenced event id to a free-form relation label:

{ "clientData": { "related": { "ck...sourceEventId": "derived-from" } } }

The reverse direction (“all events created from this one”) is an ordinary content query: [{"path": "related.ck...sourceEventId", "exists": true}] on clientData. This is a documented convention, not a schema: events carry only the references their author asserted, and event integrity is unaffected.

Format:

Like the streams query, the conditions array must be sent stringified when passed as a query parameter in a GET /events HTTP call, and as-is for batch and socket.io calls.

Item identifier

A string uniquely identifying an item for a given user. For some types of items (e.g. “structural” ones such as streams), the identifier can be optionally set by API clients; otherwise it is generated by the server. Event ids are always collision-resistant cuids.

Timestamp

A positive floating-point number representing a number of seconds since any reference date and time, independently from the time zone. Because date and time synchronization between server time and client time is done by the client simply comparing the current server timestamp with its own, the reference date and time does not actually matter (but we do use standard Unix epoch time).

Integrity

An integrity hash computed from the JSON object it is contained in. The hash is prefixed with the data structure it is computed for, as well as a representation version.