Your records, on your terms.
This REST API returns evaluation results and synced records for the account that owns the API key. A Read and write key can also add, change, and delete entries, and add and change sites, supervisors, and activities.
Authentication
Create and revoke keys in the web app at Settings > Account > API keys. When you create a key you choose Read only or Read and write. The full value is shown once. Keep it private and send it only in the Authorization header. Keys are hashed at rest, expire in 30, 90, or 365 days, and can be revoked in settings. A key with only progress:read cannot read record lists, and a Read only key cannot change anything.
curl 'https://getaccrue.app/api/v1/progress?timeZone=America%2FLos_Angeles' \
-H 'Authorization: Bearer accrue_live_REPLACE_WITH_YOUR_KEY'
Never place a key in a URL, query parameter, or request body. Do not include keys in logs, source code, or shared prompts. Anyone who holds a Read and write key can add, change, and delete your entries, and add and change your sites, supervisors, and activities, so store it like a password and revoke it when the tool no longer needs it.
Scopes and key types
progress:readAllows /me, /progress, /ledgers, and /ledgers/{id}. Every key has it.
records:readAllows /entries, /sites, /supervisors, /tasks, /activities, /exports/elc, and /exports/hours.
records:writeAllows creating, changing, and deleting entries, sites, and supervisors, and creating and changing activities. Requires records:read.
The web app offers two choices. Read only is progress:read and records:read. Read and write is those two plus records:write. Keys made before version 1.1 keep the scopes they were created with, and a key with only progress:read is listed as Progress only. A call that needs a scope the key lacks receives 403 insufficient_scope.
Available routes
Progress (progress:read)
GET /meReturn the authenticated UID, this key's scopes, and the timeZone and firstWeekday saved on the key (null for keys made before version 1.1); no email or data freshness metadata is returned because this identity-only response does not read a record snapshot.
GET /progressEvaluate all ledgers and report sync freshness.
GET /ledgersList evaluated ledgers with bounded pagination.
GET /ledgers/{id}Read one ledger result.
Records (records:read)
GET /entriesRead entries with optional inclusive from and to dates. Each entry includes activityId, siteId, supervisorId, startTime (HH:MM or null), and recorded (see Entered elsewhere). Add recorded=false to list only what still needs entering. Session notes are returned as a string (empty when none).
GET /sitesRead the signed-in user's sites.
GET /supervisorsRead the signed-in user's supervisors, with role and siteIds. Contact details are never returned.
GET /activitiesRead the activity menu: id, name, kind, isEnabled, and sortOrder. Includes stock activities the account has not edited.
GET /tasksRead the signed-in user's tasks. Tasks are read only.
GET /exports/elcExport an ELC timesheet as text. See Exports.
GET /exports/hoursExport the plain hours spreadsheet as CSV. See Exports.
Writes (records:write)
POST /entriesAdd an entry. Returns 201.
PATCH /entries/{id}Change an entry. Returns 200.
DELETE /entries/{id}Delete an entry. Returns 204.
PUT /entries/{id}/recordedMark an entry as entered in another system. Returns 200.
DELETE /entries/{id}/recordedClear that mark. Returns 204.
POST /sitesAdd a site. Returns 201.
PATCH /sites/{id}Change a site. Returns 200.
POST /supervisorsAdd a supervisor. Returns 201.
PATCH /supervisors/{id}Change a supervisor. Returns 200.
POST /activitiesAdd an activity at the end of the menu, enabled. Returns 201.
PATCH /activities/{id}Rename an activity, switch it on or off, or reorder it. Returns 200.
Write records
Write routes need a Read and write key. Send JSON with Content-Type: application/json, up to 8 KB. Unknown fields are rejected with 400 invalid_body. A write returns the same shape as the matching read, and the change reaches the iPhone, Android and web apps through sync like any other edit. Session notes can be read and changed through the entry routes. They are your own reminders; never include client names or clinical content. Do not put client names in site, supervisor, or activity names.
curl -X POST 'https://getaccrue.app/api/v1/entries' \
-H 'Authorization: Bearer accrue_live_REPLACE_WITH_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"date":"2026-09-25","minutes":60,"activityId":"ACTIVITY_ID","siteId":"SITE_ID","clientUnit":"individual","modality":"inPerson","startTime":"09:30"}'
entriesdate (YYYY-MM-DD), minutes (1 to 1440), and activityId are required. Optional: siteId, supervisorId, clientUnit (individual, couple, family, group, or none), clientAge (adult or minor), modality (inPerson, video, phone, or none), and startTime (HH:MM). Defaults are none, adult, and none. A change accepts any subset of these fields, and siteId, supervisorId, and startTime accept null to clear.
sitesname is required. Optional: kind (nonprofit, government, school, university, hospital, privatePractice, or other; default other), employment (employee, volunteer, student, or contractor; default student), startedOn, and endedOn (YYYY-MM-DD). Sites are not deleted through the API, as in the app; set endedOn when one no longer applies.
supervisorsname is required. Optional: role (primary, secondary, substitute, or faculty; default primary), siteIds, startedOn, and endedOn. Supervisors are not deleted through the API; set endedOn when one no longer applies.
activitiesCreate with name and kind. Change with any of name, isEnabled, and sortOrder. Activities are not deleted through the API; switch one off with isEnabled set to false.
An unknown id returns 404 not_found. A write returns 409 conflict when the record changed between the read and the commit; read it again and retry. While account deletion is pending, writes return 409 account_unavailable.
Not writable through the API: ledgers and your path (they change together in the app), tasks, weekly logs and signatures, and per-device preferences such as rounding, week start, menus, reminders, and appearance, which each device keeps for itself.
Session notes (v1.3)
Every entry returns notes, including entry write responses. A Read only key can read notes; a Read and write key can set them when creating an entry with POST /entries or changing one with PATCH /entries/{id}. Omit notes on create to start empty, or on an edit to keep the existing notes. Send {"notes":""} to clear them.
curl -X PATCH 'https://getaccrue.app/api/v1/entries/ENTRY_ID' \
-H 'Authorization: Bearer accrue_live_REPLACE_WITH_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"notes":"Review training goals.\nBring the worksheet."}'
Notes must be a string. Multiline text, Unicode and whitespace are preserved; null and other types return 400 invalid_body. The complete JSON request body is limited to 8 KB. A notes-only edit keeps the entered-elsewhere mark current. Notes sync to the same session details on iPhone, Android and the web.
Entered elsewhere
An assistant that copies logged sessions into a school's system (ELC, Time2Track, Tevera) can tell Accrue which entries it has entered. The app then shows a small check beside that entry's duration. The mark is the trainee's own record of where an entry was entered. It does not show that the school accepted the entry or that a supervisor signed it.
curl -X PUT 'https://getaccrue.app/api/v1/entries/ENTRY_ID/recorded' \
-H 'Authorization: Bearer accrue_live_REPLACE_WITH_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"system":"ELC","reference":"E-1042","copied":{"date":"2026-09-25","minutes":60,"activityId":"ACTIVITY_ID","siteId":null}}'
PUTsystem is required: one line, 1 to 40 characters, such as ELC. reference is optional, 1 to 120 characters: the entry's id in that system. copied is required: the date, minutes, activityId and siteId (null for no site) of the entry exactly as GET /entries returned them, which is what you entered. If the entry has changed since, nothing is written and the answer is 409 entry_changed: read it again, enter the change, then mark it. Otherwise the entry is snapshotted as stored now. Marking again replaces the snapshot.
recordedOn every entry: null, or { system, at, reference, current }. at is when it was marked (ISO 8601 UTC). current is true until the entry's date, length, activity or site changes; then it is false and the app shows the mark in amber, because the other system is out of date. Notes, supervisor and client details do not change it.
recorded=Query on GET /entries and GET /exports/elc. false returns entries with no mark or a changed one, which is what still needs entering. true returns entries whose mark is current. It combines with from and to.
Changing an entry with PATCH keeps its mark, so the change shows. DELETE clears the mark and also answers 204 when there is none.
Exports
GET /exports/elc returns, as text/plain, exactly what the app's Export > Spreadsheet > Copy button copies for an ELC timesheet: the instructions, then CSV. Add ?format=csv to receive only the CSV as text/csv, the same as the downloaded timesheet file. GET /exports/hours returns the plain hours spreadsheet, one row per entry, as text/csv. It is the file the app copies or downloads when ELC columns are off. Its Notes column is kept but always empty; read session notes through GET /entries.
Both routes accept from and to (inclusive YYYY-MM-DD dates; omitting both exports all entries), rounding (minutes: 0, 5, 6, 15, 30, or 60), direction (down or up), timeZone, and firstWeekday. GET /exports/elc also accepts recorded (see Entered elsewhere). When rounding is omitted, the app's default applies: 15 minutes rounded down for a Palo Alto University activity set, and exact minutes otherwise. Reporting rounding is a per-device preference the server cannot see, so pass rounding to match what a device shows. An export is a recordkeeping aid. It does not show that a supervisor, school, or board has accepted the hours.
Read progress and time remaining
For a “how much time is left?” question, read each ledger's headline.remainingMinutes or display-ready headline.remainingDisplay. Bucket-specific figures live under buckets[]. A null target or remaining value means the preset has no verified target figure. Ledgers are independent; the same logged activity may credit more than one, so do not add ledger totals together.
Shortened response excerpt
{
"data": {
"ledgers": [{
"id": "example-ledger",
"headline": {
"creditedMinutes": 120,
"targetMinutes": 300,
"remainingMinutes": 180,
"creditedDisplay": "2:00",
"targetDisplay": "5:00",
"remainingDisplay": "3:00"
},
"buckets": []
}],
"freshness": { "lastSyncedAt": "2026-09-25T18:01:00Z", "allDevicesSynced": null }
},
"meta": {
"apiVersion": "1",
"asOf": "2026-09-25T18:00:00Z",
"timeZone": "America/Los_Angeles",
"firstWeekday": 1,
"source": "synced_records"
}
}
Am I on track?
Use standing.title and standing.detail for the evaluator's current summary. When pace is present, compare pace.completion with deadline; deadlineName labels that window. A projected completion after the deadline signals a timing concern. If either value is null, the API cannot make that comparison. Pace is based on credited weekly history and is only a projection; it does not establish eligibility or predict board approval.
Evaluation dates and calendars
Pass asOf as an ISO 8601 UTC timestamp to reproduce an evaluation date. Future times are rejected. Pass an IANA timeZone such as America/Los_Angeles, and firstWeekday as 1 for Sunday through 7 for Saturday. When a request omits them, the time zone and first weekday saved on the key apply: the web app saves the creating browser's time zone and the trainee's week start preference when the key is made. Only when the key has none saved, as with keys made before version 1.1, do UTC and 1 apply. Entries are filed by civil day in that zone. Metadata echoes the settings used.
Pagination and limits
Lists return up to 100 records by default and accept limit up to 200. Follow meta.nextCursor exactly; keep the same asOf, timeZone, and firstWeekday values returned in that page's metadata. Cursors are scoped to the same account, list, filters, evaluation calendar, and sync snapshot. Entry date filters are inclusive ISO civil dates. Unknown query parameters are rejected. The API evaluates full history and refuses more than 20,000 rows or 16 MiB of decoded row bodies rather than returning partial figures. Request bodies can be up to 8 KB.
Response freshness and boundaries
Each data response has meta.asOf, meta.timeZone, meta.firstWeekday, and meta.lastSyncedAt. The sync time is the latest remote Firestore document write time. It cannot prove that every device has synced. Independent ledger totals can credit the same activity and must not be added together.
Responses are not cached. Error bodies contain a stable error code and request ID but no row contents, credential values, or account profile. Rate limit is 60 API requests per key per minute, with an additional coarse cap of 600 requests per service instance per minute. An account can hold five active keys and create five new keys an hour.
Errors and retries
For 400, correct the query or request before retrying; a write body with an invalid value or an unknown field returns invalid_body. For 401, confirm the key is current or refresh the Firebase sign-in in settings. For 403 insufficient_scope, create a key with the needed scope; a Read only key cannot write. For 404 not_found, check the id. For 409 conflict, read the record again and retry the write. For 409 account_unavailable, wait: account deletion is pending. For 409 newer_app_data, a newer version of the app saved the record; change it in the app. For 409 entry_changed on the recorded mark, the entry changed after it was read; read it again, enter the change, then mark it. For 409 key_time_zone_missing, make a new Read and write key in the web app. On 429, wait at least a minute before retrying; key issuance may remain limited for up to an hour. A 413 means the complete synced dataset is over the evaluation bound and will not succeed by retrying. For a temporary 503, wait and retry with backoff; repeated failures may require syncing the app or service recovery.
Connection integrations
These docs describe ordinary REST access using an Accrue API key. A Muse connector OAuth/account-linking integration is not part of this API. See Meta's connector product page for the separate integration context.