API

De REST API is het hele oppervlak: documenten erin, patronen eruit, met correlaties, flows, beoordeling, een tijdlijn en zoeken ertussen, en daarnaast wat wearables maten en wat de Observer zei. Deze pagina legt de begrippen en de levenscyclus uit; de gegenereerde referentie op het API-domein heeft elk veld.

Basis

Elke route leeft op het API-domein, neemt en geeft JSON, en wil een bearer token. Antwoorden wikkelen de resource in data; lijsten voegen links en meta toe met de pagina en het totaal.

GET    /documents             GET    /patterns
POST   /documents             GET    /patterns/{id}
GET    /documents/{id}        PATCH  /patterns/{id}
DELETE /documents/{id}        PATCH  /correlations/{id}
GET    /search?q              GET    /timeline?from&to
GET    /observations          GET    /measurements?from&to
GET    /observations/{id}     GET    /settings/me
GET    /users/me              PUT    /settings/me/{key}
GET /documents · a list
{
  "data": [ … ],
  "links": {"first": "…", "last": "…", "prev": null, "next": "…"},
  "meta": {"current_page": 1, "per_page": 15, "total": 42, …}
}

De gegenereerde referentie heeft elke route, elk veld en elke fout, afgelezen van de code, dus altijd actueel. Deze pagina vertelt wat de resources betekenen. /docs/api, /openapi.json.

Abonnementen

Een token leest wat het abonnement van het account leest, of het nu van de gebruiker zelf is of aan een app is gegeven. Op het gratis abonnement zijn twee dingen anders:

  • undrstand leest dertig documenten per maand. Eén daarboven wordt bewaard met status waiting, nooit geweigerd, en wordt gelezen als er een nieuwe maand begint of het abonnement verandert.
  • Alleen het sterkste patroon is open. De andere staan in de lijst met locked true en hoe zwaar ze wegen, maar zonder naam, beschrijving of gevoelens, en er een op id lezen geeft 402. Het open patroon draagt correlations_count en flows_count in plaats van de lijsten.
GET /patterns · a locked one
{"id": "4b0a…", "locked": true, "sentiment": "negative", "impact": "moderate", "urgent": false,
 "status": "detected", "documents_count": 3, "last_detected_at": "…", "closed_at": null, "created_at": "…"}
HTTP/1.1 402 Payment Required
{
  "error": "plan_required",
  "message": "Upgrade to read every pattern.",
  "feature": "patterns",
  "upgrade_plan": "clarity"
}

Op een betaald abonnement wordt elk document meteen gelezen en is elk patroon open.

Wat er met een document gebeurt

Na het insturen wordt een document op de achtergrond gelezen en komt wat erin gevonden is bij je patronen. Reken op dertig seconden tot twee minuten. Patronen worden ook elke nacht om jouw lokale middernacht opnieuw bekeken, dus ze kunnen verschijnen, veranderen of sluiten zonder nieuw document.

Documenten

Een document is de tekst die je hebt ingeleverd. Velden: original, precies zoals gepost; translated, altijd Engels; language, de gevonden ISO-code; origin, voorlopig text; source, de app die het inleverde, of null als je dat zelf deed; occurred_at, het moment waar het over gaat; status; en segments zodra verwerkt.

Status loopt van queued naar processing naar processed of failed, met waiting vóór queued op een abonnement waarvan de maand op is. Een mislukt document houdt zijn tekst en verder niets; stuur het opnieuw in. Een document verwijderen haalt weg wat erin gevonden is en worden je patronen opnieuw bekeken, dus een patroon dat alleen in dat document leefde sluit.

Lijsten zijn gepagineerd met page en limit, nieuwste eerst.

Segmenten en tags

Een segment is een letterlijk stuk van de vertaalde tekst: één ding dat gebeurde met het gevoel dat het gaf en wat je deed. Elk draagt tags van een type: trigger, positive_feeling, negative_feeling, good_behaviour, bad_behaviour, person, location, activity. Triggers en gedrag noemen ook hun categorie.

Patronen

Een patroon is een categorie die steeds terugkomt met dezelfde gevoelens: iets wat je steeds raakt, of iets wat je steeds doet. Het heeft minstens drie verschillende dagen nodig. Velden:

  • name — de categorie, zoals werkcontact of uitstelgedrag.
  • locked — true als het abonnement dit patroon niet toont; name, description en feelings blijven dan weg.
  • sentiment — positive of negative. Goed gedrag maakt een positief patroon, slecht gedrag een negatief, een trigger kan beide maken.
  • impact — low, moderate of high: hoe vaak het opduikt, afgewogen tegen hoeveel je schrijft.
  • urgent — true als het in de afgelopen week op drie verschillende dagen opdook.
  • feelings — tot vier gevoelens waarmee het komt.
  • description — een paar zinnen, voor jou geschreven, in jouw taal.
  • status — detected, accepted of rejected.
  • documents_count, last_detected_at, closed_at — waar het op rust, wanneer het voor het laatst gezien is, en wanneer het ophield op te duiken.

Een patroon dat een week stil is sluit en gaat weer open als het terugkomt; hetzelfde patroon, geen nieuw. Eén patroon lezen voegt zijn documenten als samenvattingen toe, zijn correlaties en zijn flows.

GET /patterns/{id}
{
  "data": {
    "id": "7c1e…",
    "locked": false,
    "name": "work contact",
    "sentiment": "negative",
    "impact": "low",
    "urgent": true,
    "status": "detected",
    "description": "Contact from work, a call or a message about a deadline, keeps landing as a knot in your stomach. …",
    "feelings": [{"id": "…", "name": "anxious"}],
    "documents_count": 4,
    "last_detected_at": "2026-09-26T22:00:03.000000Z",
    "closed_at": null,
    "created_at": "2026-09-24T22:00:01.000000Z",
    "documents": [{"id": "9d2f…", "status": "processed", "occurred_at": "2026-09-26T16:10:00.000000Z"}, …],
    "correlations": [
      {"id": "…", "tag": {"id": "…", "type": "person", "name": "boss"}, "impact": "moderate", "amount": 3, "status": "detected"}
    ],
    "flows": [
      {"id": "…", "segment_id": "b41c…", "trigger": "boss calling about the report", "feeling": "anxious", "behaviour": "scrolling instead of working"}
    ]
  }
}

Correlaties

Een correlatie is een persoon, locatie of activiteit waarmee een patroon vaker voorkomt. Hij draagt de tag, een impact, het aantal keren dat ze samen gezien zijn, en een status. De lijst is de top per type, elke run ververst, dus een die uit de top valt verdwijnt tenzij je hem geaccepteerd hebt.

Flows

Een flow is één segment in volgorde verteld: trigger, gevoel, gedrag. Wat er gebeurde, wat je voelde, wat je deed. Flows worden alleen gekoppeld, nooit verzonnen: elk van de drie is een tag die uit dat segment gehaald is.

Tijdlijn

De tijdlijn is één regel per kalenderdag in jouw tijdzone, lege dagen inbegrepen, tussen from en to, hoogstens 92 dagen uit elkaar. Elke dag noemt zijn documenten als id, status en occurred_at, en de patronen waar die documenten bij horen.

GET /timeline
curl "https://api.undrstand.com/timeline?from=2026-09-01&to=2026-09-30" \
  -H "Authorization: Bearer $TOKEN" -H "Accept: application/json"

# {"data": [
#   {"date": "2026-09-01", "documents": [], "patterns": []},
#   …
#   {"date": "2026-09-26",
#    "documents": [{"id": "9d2f…", "status": "processed", "occurred_at": "…"}],
#    "patterns": [{"id": "7c1e…", "locked": false, "name": "work contact", "sentiment": "negative", "impact": "low"}]}
# ]}

Zoeken

Zoeken vindt situaties op betekenis, niet op exacte woorden: de andere keren dat dit gebeurde, ruzies over geld, toen ik me buitengesloten voelde. Vraag het in de woorden en de taal van de gebruiker met q, en beperk het desgewenst tot de dagen tussen from en to. Het heeft documents:read nodig.

GET /search
curl -G "https://api.undrstand.com/search" \
  --data-urlencode "q=arguments about money" -d "from=2026-07-01" -d "limit=5" \
  -H "Authorization: Bearer $TOKEN" -H "Accept: application/json"

# {"data": [
#   {"similarity": 0.83,
#    "segment": {"id": "b41c…", "position": 2, "text": "…", "tags": [ … ]},
#    "document": {"id": "9d2f…", "status": "processed", "occurred_at": "…"},
#    "patterns": [{"id": "7c1e…", "locked": false, "name": "…", "sentiment": "negative", "impact": "low"}],
#    "flows": [{"id": "…", "segment_id": "b41c…", "trigger": "…", "feeling": "…", "behaviour": "…"}]}
# ]}

Elke treffer is een segment met zijn tags, het document waar het uit komt, een similarity tussen 0 en 1, de patronen waarin het gezien is en de flows waarin het verteld is. Tien treffers, tenzij je een andere limit vraagt, hoogstens vijftig.

Metingen

Een gebruiker kan in de webapp een wearable koppelen: WHOOP, Oura, of Fitbit en Pixel Watch via Google Health. Metingen zijn wat die mat tussen from en to, hoogstens 92 dagen uit elkaar: één waarde per metriek, dag en wearable, met eenheid en aanbieder. Het heeft health:read nodig, een eigen scope, omdat dit gezondheidsgegevens zijn.

GET /measurements
curl -G "https://api.undrstand.com/measurements" \
  -d "from=2026-09-20" -d "to=2026-09-26" -d "metrics[]=sleep_duration" -d "metrics[]=hrv" \
  -H "Authorization: Bearer $TOKEN" -H "Accept: application/json"

# {"data": [
#   {"date": "2026-09-26", "metric": "sleep_duration", "value": 412, "unit": "minutes", "provider": "oura"},
#   {"date": "2026-09-26", "metric": "hrv",            "value": 48,  "unit": "ms",      "provider": "oura"},
#   …
# ]}

De metrieken zijn sleep_duration, sleep_efficiency, hrv, resting_heart_rate, readiness, strain en steps. Geef metrics mee om er maar een paar te lezen. Niet elke wearable meet ze allemaal, en een gebruiker zonder wearable heeft er geen: een lege lijst is een gewoon antwoord.

Observaties

De Observer is de eigen stem van undrstand in de webapp: hij leest mee en vertelt de gebruiker wat hij ziet. Een observatie is iets wat hij uit zichzelf zei. notice is de regel die verstuurd is, body het geheel, kind waar het over ging, en subjects de id's van de patronen en documenten die hij noemt.

GET /observations/{id}
{
  "data": {
    "id": "5e77…",
    "kind": "pattern",
    "notice": "Calls from work after hours keep coming back.",
    "body": "…",
    "subjects": {"patterns": ["7c1e…"], "documents": ["9d2f…"]},
    "trigger": "…",
    "conversation_id": null,
    "reaction": null,
    "created_at": "2026-09-27T07:30:00.000000Z"
  }
}

Observaties zijn voor apps alleen te lezen, nieuwste eerst, en hebben observations:read nodig. Lees ze voordat je app zelf iets aanwijst, zodat niemand hetzelfde twee keer te horen krijgt. Praten met de Observer hoort bij de eigen app van undrstand en staat niet open voor anderen.

Review

Je kunt undrstand vertellen dat een patroon of correlatie van jou is, of niet. Accepteren houdt het in de lijst en buiten de nachtelijke opruiming. Een patroon afwijzen sluit het, laat zijn flows en correlaties vallen, en leert de extractie dat onderwerp voortaan met rust te laten in alles wat je daarna inlevert. Een afgewezen patroon is nog leesbaar op id, nooit in de lijst.

PATCH /patterns/{id}
curl -X PATCH https://api.undrstand.com/patterns/7c1e… \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" -H "Accept: application/json" \
  -d '{"status": "accepted"}'      # or "rejected"; same shape on /correlations/{id}

Review alleen op het woord van de gebruiker. Een app die op eigen initiatief afwijst leert de analyse dingen te negeren die de gebruiker nooit gezien heeft.

Instellingen

Twee instellingen doen er hier toe: timezone, die de dagen afsnijdt en de nachtelijke verversing om jouw lokale middernacht draait, en app_locale, de taal van de patroonbeschrijvingen. Lees ze allemaal, schrijf er een op sleutel, of schrijf er meerdere tegelijk.

GET https://api.undrstand.com/settings/me
# {"data": [{"key": "timezone", "value": "Europe/Amsterdam"}, {"key": "app_locale", "value": "nl"}, …]}

PUT https://api.undrstand.com/settings/me/app_locale   {"value": "nl"}
PUT https://api.undrstand.com/settings/me              {"timezone": "Europe/Amsterdam", "app_locale": "nl"}

Fouten

CodeWanneer
401Geen token, een verlopen token, een ingetrokken token, of een token dat zijn tweestapscode nog schuldig is.
402Het abonnement van het account leest dit niet. Het antwoord noemt de functie en het abonnement dat het wel doet.
403Het token mist de scope; het bericht noemt hem.
404Het record bestaat niet of is van iemand anders. De twee worden niet onderscheiden.
422Validatie mislukt: message plus errors per veld, elk een lijst zinnen.
429Te veel aanvragen op de route.
HTTP/1.1 422 Unprocessable Content
{
  "message": "The to field must be a date after or equal to from.",
  "errors": {"to": ["The to field must be a date after or equal to from."]}
}

Waar nu heen

  • /docs/api — De gegenereerde referentie op het API-domein, met elk veld.
  • Apps en OAuth — Apps en OAuth, voor een frontend waar anderen op inloggen.