Riverd

Riverd API docs

The Riverd API lets a practice connect the apps it already uses: a spreadsheet that pulls in the week, a script, or an automation tool that adds new clients from a sign-up form. These docs are for whoever sets that up.

Base URL
https://api.riverd.app/v1
Authentication
Authorization: Bearer <API key>
OpenAPI document
https://api.riverd.app/v1/openapi.json
Plans
Every plan, Brook (free) included

Keys

The practice owner makes keys in Riverd under Settings, API keys. Each key is Read only or Read and make changes, and stops working on a date the owner picks: 7, 30 or 90 days, or 1 year. The owner can also choose Never, for a key with no end date; GET /key then answers "expires_at": null. A key that can make changes lasts 90 days at most, unless it is set to Never. A key with an end date is also turned off after 90 days without use. A key set to Never is not, and works until it is turned off. Riverd shows each key once, when it is made.

Treat a key like a password. Anyone who has it can see the practice's clients, sessions, session notes and intake answers until the owner turns it off, and a key that can make changes can also change the schedule, clients and notes.

Times

Times are objects like {"date_time": "2026-10-09T14:00:00-05:00", "timezone": "America/Chicago"}. A time sent without a zone is read in the provider's time zone, which GET /key returns along with today's date.

How changes work

  • A change applies right away. Its answer carries a change.id and an undo_until, and POST /changes/{changeId}/undo reverses it until then. The provider can undo it from their API keys page too.
  • Undo lasts 5 minutes for bookings, moves, cancellations, logged sessions, intake forms, new clients and confirmed contact details, and 24 hours for time off and session notes.
  • Emails and texts a change sends the client wait until undo_until, or until the session starts if that is sooner (client_messages_release_at), so an Undo before then stops them.
  • A booking or move that overlaps another session, a Google Calendar busy time or time off answers 409 with the code overlap and the clashes. Send "allow_overlap": true only after the provider says to book it anyway.
  • Riverd sends a new client nothing until their email address and phone number are confirmed. POST /clients and POST /bookings with a new client take "contact_confirmed": true: send it only after reading the details back to the provider and hearing they're right.
  • Blocking time off cancels nothing, and the answer lists the sessions inside the block in sessions_inside. Writing notes adds after the notes already there unless replace is true.
  • Check a change with "dry_run": true before you make it, and send an Idempotency-Key header so a retry within 24 hours answers with the first result instead of making the change twice.
  • Riverd emails the provider the first time each key makes a change.

Reference

Sending your key

Every request goes to https://api.riverd.app/v1 and carries your key in the Authorization header:

curl -H "Authorization: Bearer rvd_pat_..." https://api.riverd.app/v1/clients

Never put a key in the web address. A key sent that way is refused and turned off, because web addresses end up in logs.

Reading and making changes

Answers are JSON with a data field. Lists come 50 at a time (up to 100 with limit); pass the next_cursor you got back as cursor to get the next page. It is null on the last page.

A key with read and write access can make changes. A change happens right away, and the answer has a change with its id and undo_until. Send POST /changes/{changeId}/undo before then to reverse it. Emails and texts the change sends your client wait until then, or until the session starts if that is sooner (client_messages_release_at says when), so an Undo before they go stops them.

Add "dry_run": true to the body to see what a change would do without making it. A request that removes something, like removing time off, needs no body: add ?dry_run=true to its web address instead. Send an Idempotency-Key header with a new unique value on each change: if you send the same request again with the same value, Riverd answers with the first result instead of making the change twice.

Endpoints

RequestWhat it doesQueryKeys
GET /clientsList your clients by name, or find them by name, email or phone.status, search, include_archived, limit, cursorAny
GET /clients/{clientId}One client.noneAny
GET /bookingsList bookings by start time, optionally starting from one moment and before another, or for one client.from, to, client_id, limit, cursorAny
GET /bookings/{bookingId}One booking.noneAny
GET /scheduleYour sessions starting from one moment and before another, with client and service names.from, to, limit, cursorAny
GET /servicesYour services. Inactive ones only when asked.include_inactiveAny
GET /availabilityYour weekly booking hours.noneAny
GET /time-offDays and times you blocked off, optionally ending on or after a date.from, limit, cursorAny
GET /bookings/{bookingId}/notesThe session notes for one booking.noneAny
GET /session-notesSession notes, oldest change first, optionally changed at or after a moment.updated_since, limit, cursorAny
GET /intake-answersFilled intake forms, oldest first, optionally filled at or after a moment. The questions are on each answer's own page.client_id, since, limit, cursorAny
GET /intake-answers/{submissionId}One filled intake form, with the questions it was answered against.noneAny
GET /open-timesWhen you are free: on one date, or over up to 14 dates with from and to. Without service_id, the free stretches of each day (your weekly hours minus sessions, Google Calendar busy times and time off). With service_id, the start times a client can book that service at on your booking page.date, from, to, service_idAny
POST /bookingsBook a session for an existing client (client_id) or for someone new (client), starting at most 24 months ahead. Refused with 409 overlap when the time clashes with another session, a Google Calendar busy time or time off, unless allow_overlap is true.noneRead and write
POST /bookings/pastLog a session that already happened, for an existing client. Its start must be in the past; it is not checked for overlaps. Riverd sends the client nothing about it: no notice and no intake form.noneRead and write
POST /bookings/{bookingId}/moveMove a session to a new time, at most 24 months ahead. Without end or duration_minutes it keeps its length. Refused with 409 overlap when the new time clashes with another session, a Google Calendar busy time or time off, unless allow_overlap is true. The client gets the usual notice.noneRead and write
POST /bookings/{bookingId}/cancelCancel a session, or decline a client's request that is still waiting (the client is told, with the reason). A session that has started, or that has money collected, is refused. The client gets the usual notice.noneRead and write
POST /clientsAdd a client.noneRead and write
POST /clients/{clientId}/confirm-contactConfirm a client's email or phone number on file, after the provider says it is right. Until then Riverd sends that client nothing at a detail added through the API. Undo puts it back to unconfirmed.noneRead and write
GET /intake-formsYour intake forms that can be sent, oldest first, each with its id and name only. Archived forms are left out. A form's id is the form_id that POST /bookings/{bookingId}/intake takes.limit, cursorAny
POST /bookings/{bookingId}/intakeSend an intake form to the session's client. The email with the form's link waits until the change can no longer be undone, so an Undo stops it.noneRead and write
POST /time-offBlock time off: whole days, or the same hours on each of several days. Like the Schedule page, it cancels nothing; the answer lists the sessions inside the blocked time so you can ask about moving them.noneRead and write
DELETE /time-off/{timeOffId}Remove a block of time off, by the id GET /time-off gives. Those times open again on your booking page.noneRead and write
PUT /bookings/{bookingId}/notesWrite a session's notes. Adds your text after the notes already there, unless replace is true. Nothing is sent to the client, and no AI credits are used.noneRead and write
GET /keyThe key you are calling with (its name, access level, expiry, or none for a key that never expires, and whether it may start AI on notes), your practice's time zone, and today's date in it. Every time the API reads or sends is on that clock.noneAny
POST /changes/{changeId}/undoUndo a change made through the API, using the change id its response gave. Works while the change can still be undone; client messages it caused that have not gone out are stopped.noneRead and write
POST /ai/soap-draftDraft a SOAP note from one session's notes with Reed · AI. Only for a key made with 'Can start Reed · AI on notes' switched on. Uses AI credits. Nothing is saved.noneAny

The full description, with every field, is at https://api.riverd.app/v1/openapi.json.

Limits

Per key, and again for all your keys together: 60 requests a minute and 1,000 an hour; 20 changes a minute and 300 a day (an Undo counts as a change, a dry run as a request).

For all your keys together, also: 60 changes that can message a client an hour (POST /bookings, /bookings/past, move, cancel, intake; /bookings/past counts although it sends nothing); 10 changes an hour and 30 a day that confirm a client's email or phone; 120 pages of session notes or intake answers an hour; 30 AI drafts an hour.

A change Riverd refuses for what it asks, like one that overlaps, still counts. Check a change with "dry_run": true first, then send it once, so a mistake and its retry do not use up the changes or the contact confirmations.

Errors

An error answer has error.code, error.message and a request_id.

400
A parameter, the body or the Idempotency-Key header is not valid, or the key was sent in the web address (it is turned off).
401
The key is missing, not valid, expired or turned off.
402
The practice has used this month's AI credits (ai_credits_exhausted), so Reed can't draft the SOAP note.
403
Your plan or this key does not allow it (for example, a read-only key making a change).
404
No such endpoint, or nothing with that id in your practice.
409
The time overlaps another session, a Google Calendar busy time or time off (overlap: error.details.clashes lists what is in the way, and allow_overlap: true books it anyway). Or something changed since (the change was already undone or is being undone, or it was edited in Riverd), or a request with the same Idempotency-Key is still running.
410
It is too late to undo that change.
413 / 415
The body is too large, or not JSON.
422
The change can't be made as asked (error.code says why), your time zone is not set (timezone_unset), or the Idempotency-Key was used for a different request. A session booked or moved through the API starts at most 24 months ahead (start_too_far), and a SOAP draft takes notes of up to 10,000 characters (notes_too_long). An intake form is not sent while your practice's client emails are paused (client_email_paused) or have reached their daily limit (client_email_daily_cap).
429
Too many requests. Wait for the seconds in the Retry-After header.
500 / 503
Something went wrong, or the API is paused or could not answer right now. Try again shortly. When error.code is save_uncertain, the change may have been saved: check Riverd before you send it again.

For practices

API keys are on every plan, Brook (free) included. Read what they let you do on the API keys page, then start your practice free or see pricing.