Connect with RecordKeeper

RecordKeeper is a personal health record. With a person's permission, your app or AI assistant can read the parts of their record they choose, and write to the parts they allow. It works like asking for Apple Health access: the person sees your app's name, picks sections, and can disconnect at any time.

Before you start

Apps are approved one at a time. RecordKeeper registers your app and gives you a client ID, plus a client secret if your app runs on a server. Send:

Connecting outside apps is part of RecordKeeper Plus. A person without Plus is offered an upgrade on the consent screen instead of an Allow button.

1. Send the person to RecordKeeper

Make a random code_verifier (43 to 128 characters), and its code_challenge = base64url(SHA-256(verifier)). Then open:

https://app.recordkeeperapp.com/v1/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.example/callback
  &scope=medications.read blood_pressure.write
  &state=RANDOM_VALUE_YOU_CHECK_LATER
  &code_challenge=YOUR_CODE_CHALLENGE
  &code_challenge_method=S256

The person signs in if they need to, sees your app's name and the sections you asked for, and chooses. A mobile app should open this in the system browser, never an embedded web view.

2. Get the code back

They return to your redirect_uri with ?code=…&state=…. Check state matches. If they said no, you get ?error=access_denied instead. Codes last 10 minutes and work once.

3. Trade the code for tokens

POST https://app.recordkeeperapp.com/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=THE_CODE
&redirect_uri=https://yourapp.example/callback
&client_id=YOUR_CLIENT_ID
&code_verifier=YOUR_CODE_VERIFIER

A server app also sends client_secret (in the body, or as HTTP Basic). The answer:

{
  "access_token": "rka_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rkr_…",
  "scope": "blood_pressure.write medications.read"
}

Read scope: it is what the person actually allowed, which may be less than you asked for.

4. Call the API

GET https://app.recordkeeperapp.com/v1/profiles
Authorization: Bearer rka_…

Every account has one or more profiles (the person, and anyone they manage, such as a child). Most records belong to a profile; pass profileId when you read or write. Then, for example:

GET https://app.recordkeeperapp.com/v1/medications?profileId=PROFILE_ID
Authorization: Bearer rka_…

POST https://app.recordkeeperapp.com/v1/blood-pressure
Authorization: Bearer rka_…
Content-Type: application/json

{ "profileId": "PROFILE_ID", "systolicMmhg": 118, "diastolicMmhg": 76, "measuredAt": "2026-10-15T08:30:00Z" }

Lists take ?since= (an ISO date) and ?limit= (the most recent N, up to 1000). Every path, field, and required value is in the OpenAPI reference.

5. Keep the connection alive

Access tokens last one hour. Refresh before then:

POST https://app.recordkeeperapp.com/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=rkr_…&client_id=YOUR_CLIENT_ID

You get a new pair, and the old refresh token stops working. Use each refresh token once. If an old one is ever used again, RecordKeeper assumes it was stolen and ends every token on that connection; the person has to connect your app again. Refresh tokens last 90 days.

To disconnect from your side, send the token to POST https://app.recordkeeperapp.com/v1/oauth/revoke with your client_id.

Connect an AI assistant (MCP)

Chatbots and always-on assistants that speak the Model Context Protocol connect to one address:

https://app.recordkeeperapp.com/v1/mcp

The assistant finds the sign-in on its own: an unauthenticated request answers 401 with a WWW-Authenticate header pointing at https://app.recordkeeperapp.com/.well-known/oauth-protected-resource, which names this server's OAuth endpoints. If it asks for no particular sections, the person is offered every section read-only and turns off what they don't want.

Already approved, nothing to register: these assistants use a ready-made client ID with no secret. Enter it when the assistant asks for one.

Any other assistant needs its own client ID from RecordKeeper first (there is no automatic registration), entered in its connector settings.

The tools: list_profiles, list_record_types, query_records, get_record, and get_vitals. All of them read; none of them change anything. They see exactly what the person allowed, and every read appears under Connected Apps.

Errors

Every refusal is JSON with a machine-readable error:

Sections

A scope is a section name plus .read or .write (write includes read). These sections are stable: their fields will not change without a new API version.

Every other section in the reference is experimental (x-stability in the OpenAPI document): usable, but its fields may change.

Never available to apps

Whatever you ask for, these are not offered and cannot be granted: visit transcripts, the safety plan, ID cards (transcripts, safety_plan, ids), the person's password vault, and anything they've marked Private. Asking for one of these sections returns invalid_scope.

Your responsibilities

The person can see every app they've connected, what it may do, what it read in the last 30 days, and a Disconnect button. Once your app has their data, it is governed by your privacy policy, and RecordKeeper tells them so on the consent screen. Ask only for what your app needs.