Skip to content
API reference OpenAPI file

Algia API

The Algia API lets your own tools read and add to your own pain diary: a script, a spreadsheet, a home automation or an agent you run yourself. It reaches one account's data, with a key that account made.

It is for personal automation, not for building a service for other people. It never changes an account, a password or a second factor, never erases an account and never downloads everything at once; those stay in the application. It returns what was recorded and interprets none of it.

Base address
https://api.algia.be/v1
Format
JSON in UTF-8
Version
1, in the path
Specification
OpenAPI 3.1

Who can use it

The API is part of Plus, and it is off for every account until it is asked for and granted.

  1. An account on Plus asks for access in the application, under Security, API, with a sentence or two on what it is for. The API page in the application.
  2. The operator reads the request and grants it by hand. Until then the page shows the request and its date.
  3. Once access is granted, the same page shows the form for personal access tokens.

If the account leaves Plus, every token stops working until the account is on Plus again. If the operator revokes access, every token is revoked with it, for good.

Personal access tokens

  • A token starts with algia_pat_ and is shown once, when it is made. Algia keeps only a SHA-256 fingerprint of it, so a lost token cannot be shown again: revoke it and make a new one.
  • Making a token asks for the password and the second-factor code again, unless both were given in the last 5 minutes.
  • A token is valid for 90 days unless another period is chosen, and for at most 365 days. It can be revoked at any moment on the same page, which also shows when each token was last used.
  • A token carries the scopes chosen for it, and nothing more.

A token is a password to the diary. Keep it in a secret store or an environment variable, never in a web page, a shared document or a repository. The API sends no cross-origin headers, so a web page cannot call it from a browser.

Scopes

ScopeAllowsEndpoints
entries:read Read scores, places and answers GET /entries
entries:write Add and delete entries POST /entries
DELETE /entries/{id}
diary-text:read Read diary notes Adds the diary text and each place's note to GET /entries
medication:read Read medication and reminders GET /medications
GET /intakes
medication:write Answer reminders POST /intakes/{id}/answer

Diary text is a scope of its own, so a dashboard that reads scores never receives free text. A token with entries:read alone gets scores, places and answers, without the diary or the notes.

Making a request

Every request carries the token in the Authorization header, over HTTPS:

curl "https://api.algia.be/v1/entries?from=2026-10-01&to=2026-10-06" \
  -H "Authorization: Bearer $ALGIA_TOKEN" \
  -H "Accept: application/json"
  • A body is JSON, sent with Content-Type: application/json.
  • Dates in a query are YYYY-MM-DD; a value in another shape is ignored rather than refused.
  • recorded_at is ISO 8601 in UTC. date and time in an answer are the local day and time where the entry was recorded.
  • Every request needs a current consent for health data on the account, given in the application. Without it every endpoint answers 403 consent_required.
  • When processing is paused on the account, reads still work and writes answer 403 processing_restricted.

Rate limits

Each token may make 60 reads and 20 writes a minute. Past either, the answer is 429 rate_limited with a Retry-After header in seconds. Writing or deleting an entry also counts towards the account's own limit, which the application shares.

Retries and the Idempotency-Key

A tool that retries after a timeout must not record the same entry twice. Send an Idempotency-Key header of up to 120 characters with POST /entries. A repeat with the same key from the same token within 24 hours returns the first answer, with Idempotent-Replay: true, and writes nothing. The body of the repeat is not compared, so use a new key for every new entry.

curl -X POST "https://api.algia.be/v1/entries" \
  -H "Authorization: Bearer $ALGIA_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f3c2a90-entry-2026-10-06-0830" \
  -d '{"overall_score": 4, "regions": ["neck_back"]}'

Deleting an entry and answering a reminder take no key: repeating them changes nothing. A second delete answers 404, a second taken or skipped answers 409.

Errors

An error is a short JSON object with one code, and nothing that names the account or its data:

{"error": "insufficient_scope"}

An invalid entry also lists the fields that failed:

{"error": "invalid", "fields": ["overall_score", "region_detail.neck_back.score"]}
CodeStatusMeaning
unauthenticated 401 No token, or one that is unknown, expired or revoked, or an account without API access.
insufficient_scope 403 The token does not carry the scope this endpoint needs.
consent_required 403 The account has no current consent for health data.
processing_restricted 403 Processing is paused on the account, so writes are refused. Reads still work.
rate_limited 429 Past the minute's limit. Wait the seconds in Retry-After.
not_found 404 No entry with this id belongs to the account.
invalid 422 A field failed the same checks as the form; the fields list names each one.
not_answerable 409 The reminder is already answered, the answer is not one of the three, or it is not the account's.

Endpoints

Paths are relative to https://api.algia.be/v1. Every endpoint can also answer 401, 403 and 429 as described above.

GET /entries

The account's entries, oldest first, optionally between two local days.

Every entry, oldest first. With from and to, only the local days between them, both included. Diary text and notes appear only when the token also carries diary-text:read.

Scope entries:read

Parameters

NameInTypeDescription
from query string (YYYY-MM-DD) First local day to include, YYYY-MM-DD. A value in another shape is ignored.
to query string (YYYY-MM-DD) Last local day to include, YYYY-MM-DD. A value in another shape is ignored.

Answers

200
The entries.
{
  "data": [
    {
      "id": "01JABCDEF0123456789ABCDEFG",
      "recorded_at": "2026-10-05T18:30:00+00:00",
      "date": "2026-10-05",
      "time": "20:30",
      "overall_score": 4,
      "sleep": 3,
      "mood": 3,
      "activity": 2,
      "fatigue": 4,
      "noted_later": false,
      "edited": false,
      "regions": [
        {
          "code": "lower_back_left_back",
          "score": 5,
          "pain_type": "aching"
        }
      ]
    }
  ]
}
401
No token, or a token that is unknown, expired, revoked, or whose account no longer has API access.
403
The token lacks the scope, the account has no current health-data consent, or processing is paused (writes only).
429
More than 60 reads in a minute for this token.

POST /entries

Records an entry, with the same checks as the form in the application.

The same rules as the form: a score from 0 to 10, scales from 1 to 5, known region codes, and a moment no more than 7 days back and no more than 5 minutes ahead. The answer never carries diary text, whatever the token's scopes.

Scope entries:write

Parameters

NameInTypeDescription
Idempotency-Key header string, at most 120 characters Up to 120 characters, chosen by the client. A repeat with the same key from the same token within 24 hours returns the first answer with Idempotent-Replay set to true, and writes nothing. The body of the repeat is not compared.

Request body

FieldTypeDescription
overall_score required integer from 0 to 10
recorded_at string (ISO 8601) Up to 7 days back; now when absent.
sleep integer from 1 to 5
mood integer from 1 to 5
activity integer from 1 to 5
fatigue integer from 1 to 5
diary string Free text, stored encrypted.
regions list of strings Region codes.
region_detail object Per region code in regions, optional detail.
region_detail.<code>.score integer from 0 to 10
region_detail.<code>.pain_type one of aching, burning, stabbing, tingling, cramping, throbbing, numb
region_detail.<code>.radiates_to string Another region code.
region_detail.<code>.note string Free text, stored encrypted.

Example request

{
  "overall_score": 4,
  "recorded_at": "2026-10-06T06:30:00Z",
  "sleep": 3,
  "regions": [
    "lower_back_left_back",
    "neck_back"
  ],
  "region_detail": {
    "lower_back_left_back": {
      "score": 5,
      "pain_type": "aching"
    }
  }
}

Answers

201
Recorded. The entry as it was saved, without diary text.
{
  "data": {
    "id": "01JABCDEF0123456789ABCDEFH",
    "recorded_at": "2026-10-06T06:30:00+00:00",
    "date": "2026-10-06",
    "time": "08:30",
    "overall_score": 4,
    "sleep": 3,
    "mood": null,
    "activity": null,
    "fatigue": null,
    "noted_later": false,
    "edited": false,
    "regions": [
      {
        "code": "lower_back_left_back",
        "score": 5,
        "pain_type": "aching"
      },
      {
        "code": "neck_back",
        "score": null,
        "pain_type": null
      }
    ]
  }
}
401
No token, or a token that is unknown, expired, revoked, or whose account no longer has API access.
403
The token lacks the scope, the account has no current health-data consent, or processing is paused (writes only).
422
A field is not valid.
{
  "error": "invalid",
  "fields": [
    "overall_score"
  ]
}
429
More than 20 writes in a minute for this token. Entry writes also count towards the account's 60 a minute, shared with the application.

DELETE /entries/{id}

Deletes an entry. It can be restored from the diary in the application for 90 days.

Scope entries:write

Parameters

NameInTypeDescription
id required path string

Answers

204
Deleted. No body.
401
No token, or a token that is unknown, expired, revoked, or whose account no longer has API access.
403
The token lacks the scope, the account has no current health-data consent, or processing is paused (writes only).
404
No entry with this id belongs to the account.
{
  "error": "not_found"
}
429
More than 20 writes in a minute for this token. Entry writes also count towards the account's 60 a minute, shared with the application.

GET /medications

The account's current medication list with its reminder times. Archived medication is left out.

Scope medication:read

Answers

200
The medication list.
{
  "data": [
    {
      "id": "01JABCDEF0123456789ABCDEFJ",
      "name": "Medicine A",
      "dose": "1 tablet",
      "reminders": [
        {
          "time": "08:00",
          "days": 127
        }
      ]
    }
  ]
}
401
No token, or a token that is unknown, expired, revoked, or whose account no longer has API access.
403
The token lacks the scope, the account has no current health-data consent, or processing is paused (writes only).
429
More than 60 reads in a minute for this token.

GET /intakes

Reminders that came due and their answers, oldest first, optionally between two local days.

Scope medication:read

Parameters

NameInTypeDescription
from query string (YYYY-MM-DD) First local day to include, YYYY-MM-DD. A value in another shape is ignored.
to query string (YYYY-MM-DD) Last local day to include, YYYY-MM-DD. A value in another shape is ignored.

Answers

200
The reminders.
{
  "data": [
    {
      "id": "01JABCDEF0123456789ABCDEFK",
      "date": "2026-10-06",
      "time": "08:00",
      "medication": "Medicine A",
      "answer": null
    }
  ]
}
401
No token, or a token that is unknown, expired, revoked, or whose account no longer has API access.
403
The token lacks the scope, the account has no current health-data consent, or processing is paused (writes only).
429
More than 60 reads in a minute for this token.

POST /intakes/{id}/answer

Answers a reminder with taken or skipped, or asks for it again in 15 minutes with later.

Scope medication:write

Parameters

NameInTypeDescription
id required path string

Request body

FieldTypeDescription
answer required one of taken, skipped, later

Example request

{
  "answer": "taken"
}

Answers

204
Answered. No body.
401
No token, or a token that is unknown, expired, revoked, or whose account no longer has API access.
403
The token lacks the scope, the account has no current health-data consent, or processing is paused (writes only).
409
Already answered, an answer other than the three, or not the account's reminder.
{
  "error": "not_answerable"
}
429
More than 20 writes in a minute for this token. Entry writes also count towards the account's 60 a minute, shared with the application.

Region codes

A place on the body is named by its code in regions and region_detail. The pain types are aching, burning, stabbing, tingling, cramping, throbbing and numb.

Head and neck (6)
CodePlace
head_frontFace
jaw_right_frontJaw, right
jaw_left_frontJaw, left
neck_frontFront of the neck
head_backBack of the head
neck_backBack of the neck
Torso (14)
CodePlace
chest_right_frontChest, right
chest_left_frontChest, left
abdomen_upper_frontUpper belly
abdomen_lower_frontLower belly
hip_right_frontHip, right
hip_left_frontHip, left
groin_right_frontGroin, right
groin_left_frontGroin, left
upper_back_left_backUpper back, left
upper_back_right_backUpper back, right
lower_back_left_backLower back, left
lower_back_right_backLower back, right
buttock_left_backButtock, left
buttock_right_backButtock, right
Arms (16)
CodePlace
shoulder_right_frontShoulder, right, front
shoulder_left_frontShoulder, left, front
upper_arm_right_frontUpper arm, right, front
upper_arm_left_frontUpper arm, left, front
elbow_right_frontElbow, right, inside
elbow_left_frontElbow, left, inside
forearm_right_frontForearm, right, inside
forearm_left_frontForearm, left, inside
shoulder_left_backShoulder, left, back
shoulder_right_backShoulder, right, back
upper_arm_left_backUpper arm, left, back
upper_arm_right_backUpper arm, right, back
elbow_left_backElbow, left, outside
elbow_right_backElbow, right, outside
forearm_left_backForearm, left, outside
forearm_right_backForearm, right, outside
Hands (6)
CodePlace
wrist_right_frontWrist, right
wrist_left_frontWrist, left
hand_right_frontPalm, right
hand_left_frontPalm, left
hand_left_backBack of the hand, left
hand_right_backBack of the hand, right
Legs (12)
CodePlace
thigh_right_frontThigh, right, front
thigh_left_frontThigh, left, front
knee_right_frontKnee, right, front
knee_left_frontKnee, left, front
shin_right_frontShin, right
shin_left_frontShin, left
thigh_left_backThigh, left, back
thigh_right_backThigh, right, back
knee_left_backKnee, left, back
knee_right_backKnee, right, back
calf_left_backCalf, left
calf_right_backCalf, right
Feet (10)
CodePlace
ankle_right_frontAnkle, right, front
ankle_left_frontAnkle, left, front
foot_right_frontTop of the foot, right
foot_left_frontTop of the foot, left
ankle_left_backAnkle, left, back
ankle_right_backAnkle, right, back
heel_left_backHeel, left
heel_right_backHeel, right
foot_left_backSole, left
foot_right_backSole, right