Connect your systems to Megvite.

Book visits, read charts and receive events from your EHR, hospital platform or partner app, with access your practice approves.

Three ways in

Every request runs as the clinic member who approved it, inside their clinic, with only the access they chose.

API keys

For server-to-server systems. A clinic owner or admin creates a key in Settings, under Megvite and partner access, and picks its scopes. The key is shown once.

OAuth 2.1

For apps used by many clinics. Authorization code with PKCE (S256). Register a client at /api/oauth/register, send members to /oauth/authorize, then exchange the code at /api/oauth/token.

MCP server

For connected assistants such as Claude and ChatGPT. Add https://megvite.com/api/mcp as a remote MCP server and sign in when asked.

Your first call
curl https://megvite.com/api/v1/appointments?limit=10 \
  -H "Authorization: Bearer $MEGVITE_API_KEY"

Scopes

A credential carries the scopes the member approved, narrowed on every call to what their current role allows.

read:schedule
See the schedule, availability and visit queue
write:schedule
Book and move appointments
read:patients
Search patients and read their contact details
read:clinical
Read chart summaries, care plans, lab and prescription orders
write:drafts
Draft visit notes, care plans and orders for a clinician to sign
read:messages
Read patient message threads
write:messages
Send replies in patient message threads
read:analytics
See clinic analytics

Endpoints

REST API v1. Open any endpoint for its parameters and a short example. The full contract is in the OpenAPI 3.1 document.

Writes take an Idempotency-Key
curl -X POST https://megvite.com/api/v1/patients \
  -H "Authorization: Bearer $MEGVITE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2d8e-intake-1042" \
  -d '{"firstName":"Casey","lastName":"Rivera","dob":"1988-04-12"}'

Patients

GET/api/v1/patientsList or search patientsread:patients

Newest first. Pass q to search by name, email, phone or MRN.

q: Search text. At least two characters.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "pat_8f2c41d0a7b94e1c55aa",
      "firstName": "Casey",
      "lastName": "Rivera",
      "dob": "1988-04-12",
      "sex": "F",
      "email": "casey@example.test",
      "phone": "+15555550100",
      "mrn": "MRN-1042",
      "preferredLanguage": "en",
      "status": "active",
      "createdAt": "2026-10-01T14:02:11.000Z"
    }
  ],
  "hasMore": false,
  ...
GET/api/v1/patients/{id}Get a patientread:patients
id (required): Patient id.
Response 200
{
  "data": {
    "id": "pat_8f2c41d0a7b94e1c55aa",
    "firstName": "Casey",
    "lastName": "Rivera",
    "dob": "1988-04-12",
    "sex": "F",
    "email": "casey@example.test",
    "phone": "+15555550100",
    "mrn": "MRN-1042",
    "preferredLanguage": "en",
    "status": "active",
    "createdAt": "2026-10-01T14:02:11.000Z"
  }
}
POST/api/v1/patientsRegister a patientwrite:schedule

Registers a patient so they can be booked. Requires write:schedule. Send an Idempotency-Key header.

firstName (required): Given name.lastName (required): Family name.dob: Date of birth, YYYY-MM-DD.sex: F, M, X or U.email: Email address.phone: Phone number in E.164.mrn: Your medical record number. Unique per clinic.preferredLanguage: BCP 47 language tag. Default en.
Request body
{
  "firstName": "Casey",
  "lastName": "Rivera",
  "dob": "1988-04-12",
  "email": "casey@example.test",
  "mrn": "MRN-1042"
}
Response 201
{
  "data": {
    "id": "pat_8f2c41d0a7b94e1c55aa",
    "firstName": "Casey",
    "lastName": "Rivera",
    "dob": "1988-04-12",
    "sex": "F",
    "email": "casey@example.test",
    "phone": "+15555550100",
    "mrn": "MRN-1042",
    "preferredLanguage": "en",
    "status": "active",
    "createdAt": "2026-10-01T14:02:11.000Z"
  }
}

Appointments

GET/api/v1/appointmentsList appointmentsread:schedule

Ordered by scheduled time, earliest first.

from: Scheduled at or after this time.to: Scheduled before this time.status: Filter by status.patientId: Only this patient.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "ses_1c9e2f7a40b3d8e6f001",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "providerId": "mem_prov",
      "status": "scheduled",
      "modality": "video",
      "reason": "Follow-up review",
      "scheduledFor": "2026-10-14T15:00:00.000Z",
      "startedAt": null,
      "endedAt": null,
      "createdAt": "2026-10-11T09:30:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
GET/api/v1/appointments/{id}Get an appointmentread:schedule
id (required): Appointment id.
Response 200
{
  "data": {
    "id": "ses_1c9e2f7a40b3d8e6f001",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "providerId": "mem_prov",
    "status": "scheduled",
    "modality": "video",
    "reason": "Follow-up review",
    "scheduledFor": "2026-10-14T15:00:00.000Z",
    "startedAt": null,
    "endedAt": null,
    "createdAt": "2026-10-11T09:30:00.000Z"
  }
}
POST/api/v1/appointmentsBook an appointmentwrite:schedule

Books a video or audio visit for a registered patient. Pass slotId to take an open slot from /availability, or scheduledFor for a time you choose.

patientId (required): Registered patient id.slotId: Open slot from GET /api/v1/availability.scheduledFor: Start time when no slotId is given.providerId: Clinician id. Taken from the slot when slotId is given.modality: Visit type.reason: Reason for visit, up to 500 characters.
Request body
{
  "patientId": "pat_8f2c41d0a7b94e1c55aa",
  "slotId": "slot_5d1e0a9c7b3f2e4d6a80",
  "reason": "Follow-up review"
}
Response 201
{
  "data": {
    "id": "ses_1c9e2f7a40b3d8e6f001",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "providerId": "mem_prov",
    "status": "scheduled",
    "modality": "video",
    "reason": "Follow-up review",
    "scheduledFor": "2026-10-14T15:00:00.000Z",
    "startedAt": null,
    "endedAt": null,
    "createdAt": "2026-10-11T09:30:00.000Z"
  }
}
POST/api/v1/appointments/{id}/rescheduleReschedule an appointmentwrite:schedule
id (required): Appointment id.slotId: New open slot.scheduledFor: New start time when no slotId is given.
Request body
{
  "scheduledFor": "2026-10-15T16:00:00.000Z"
}
Response 200
{
  "data": {
    "id": "ses_1c9e2f7a40b3d8e6f001",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "providerId": "mem_prov",
    "status": "scheduled",
    "modality": "video",
    "reason": "Follow-up review",
    "scheduledFor": "2026-10-15T16:00:00.000Z",
    "startedAt": null,
    "endedAt": null,
    "createdAt": "2026-10-11T09:30:00.000Z"
  }
}
POST/api/v1/appointments/{id}/cancelCancel an appointmentwrite:schedule
id (required): Appointment id.reason: Why it was cancelled, up to 200 characters.
Request body
{
  "reason": "Patient asked to cancel"
}
Response 200
{
  "data": {
    "id": "ses_1c9e2f7a40b3d8e6f001",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "providerId": "mem_prov",
    "status": "cancelled",
    "modality": "video",
    "reason": "Follow-up review",
    "scheduledFor": "2026-10-14T15:00:00.000Z",
    "startedAt": null,
    "endedAt": null,
    "createdAt": "2026-10-11T09:30:00.000Z"
  }
}

Availability

GET/api/v1/availabilityOpen appointment slotsread:schedule
from: Slots starting at or after this time. Default now.to: Slots starting before this time. Default 14 days out.providerId: Only this clinician.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "slot_5d1e0a9c7b3f2e4d6a80",
      "providerId": "mem_prov",
      "startsAt": "2026-10-14T15:00:00.000Z",
      "endsAt": "2026-10-14T15:30:00.000Z",
      "modality": "video",
      "remaining": 1
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Messages

GET/api/v1/messages/threadsList message threadsread:messages

Most recently active first. Each thread carries its latest patient-visible message. Internal notes are never returned.

patientId: Only this patient.status: Thread status.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "thr_0b7c2e9d41a8f3e65c10",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "subject": "Question about my plan",
      "status": "open",
      "updatedAt": "2026-10-11T10:00:00.000Z",
      "lastMessage": {
        "id": "msg_3e1f",
        "from": "patient",
        "body": "Can I take it with food?",
        "createdAt": "2026-10-11T10:00:00.000Z"
      }
    }
  ],
  "hasMore": false,
  ...
GET/api/v1/text-messagesList text messagesread:messages

Texts Megvite sent or received for the clinic, newest first: purpose, status and a masked number. Message text is never returned, and texts cannot be sent through the API.

appointmentId: Only texts about this appointment.limit: How many, 1 to 200. Default 50.
Response 200
{
  "data": [
    {
      "id": "sms_4c1e9a7b20d35f8e61a0",
      "direction": "outbound",
      "purpose": "visit_link",
      "status": "delivered",
      "line": "megvite",
      "phoneHint": "ending 0100",
      "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "createdAt": "2026-10-14T14:50:00.000Z",
      "updatedAt": "2026-10-14T14:50:04.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
POST/api/v1/messagesSend a message to a patientwrite:messages

Posts a provider message in a thread. Pass threadId to reply, or patientId to open a new thread.

threadId: Existing thread to reply in.patientId: Patient to start a new thread with.subject: Subject for a new thread.body (required): Message text, 1 to 4000 characters.
Request body
{
  "threadId": "thr_0b7c2e9d41a8f3e65c10",
  "body": "Yes, take it with breakfast."
}
Response 201
{
  "data": {
    "id": "msg_91c0e7a2b4d5f6a8c3e1",
    "threadId": "thr_0b7c2e9d41a8f3e65c10",
    "from": "care_team",
    "body": "Yes, take it with breakfast.",
    "createdAt": "2026-10-11T10:05:00.000Z"
  }
}

Visit notes

GET/api/v1/visit-notesList signed visit notesread:clinical

Signed notes only, newest first. Drafts, psychotherapy notes and 42 CFR Part 2 records are never returned.

patientId: Only this patient.appointmentId: Only this appointment.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "sig_a17be0c4d2f9e81b3c55",
      "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "version": 3,
      "body": "S: ...\nO: ...\nA: ...\nP: ...",
      "billingCode": "99213",
      "signedBy": "mem_prov",
      "signedAt": "2026-10-14T15:40:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
GET/api/v1/visit-notes/{id}Get a signed visit noteread:clinical
id (required): Signed note id.
Response 200
{
  "data": {
    "id": "sig_a17be0c4d2f9e81b3c55",
    "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "version": 3,
    "body": "S: ...\nO: ...\nA: ...\nP: ...",
    "billingCode": "99213",
    "signedBy": "mem_prov",
    "signedAt": "2026-10-14T15:40:00.000Z"
  }
}
POST/api/v1/visit-notes/draftsCreate a draft visit notewrite:drafts

Adds a draft version to an appointment. A clinician reviews and signs it in Megvite. Signing is never available by API.

appointmentId (required): Appointment the note belongs to.body (required): Draft note text, 1 to 20000 characters.
Request body
{
  "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
  "body": "S: Patient reports...\nA/P: ..."
}
Response 201
{
  "data": {
    "id": "cnv_6b0e1d2c3f4a5b6c7d8e",
    "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
    "version": 4,
    "status": "draft",
    "createdAt": "2026-10-14T15:45:00.000Z"
  }
}

Care plans

GET/api/v1/care-plansList published care plansread:clinical
patientId: Only this patient.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "cpl_2a9d8c7b6e5f4a3b2c1d",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
      "version": 2,
      "body": "Walk 20 minutes daily. Recheck in 6 weeks.",
      "publishedAt": "2026-10-14T16:00:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
GET/api/v1/care-plans/{id}Get a published care planread:clinical
id (required): Care plan id.
Response 200
{
  "data": {
    "id": "cpl_2a9d8c7b6e5f4a3b2c1d",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
    "version": 2,
    "body": "Walk 20 minutes daily. Recheck in 6 weeks.",
    "publishedAt": "2026-10-14T16:00:00.000Z"
  }
}

Orders

GET/api/v1/ordersList lab and prescription ordersread:clinical
patientId: Only this patient.kind: Order kind.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "ord_7e6d5c4b3a2f1e0d9c8b",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
      "kind": "lab",
      "detail": "Lipid panel",
      "status": "drafted",
      "createdAt": "2026-10-14T15:50:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
POST/api/v1/ordersDraft a lab or prescription orderwrite:drafts

Creates a draft only. A clinician approves it in Megvite. Sending a prescription is never available by API.

patientId (required): Patient the order is for.kind (required): Order kind.detail (required): What to order, 1 to 2000 characters.appointmentId: Appointment the order came from.
Request body
{
  "patientId": "pat_8f2c41d0a7b94e1c55aa",
  "kind": "lab",
  "detail": "Lipid panel"
}
Response 201
{
  "data": {
    "id": "ord_7e6d5c4b3a2f1e0d9c8b",
    "patientId": "pat_8f2c41d0a7b94e1c55aa",
    "appointmentId": null,
    "kind": "lab",
    "detail": "Lipid panel",
    "status": "drafted",
    "createdAt": "2026-10-14T15:50:00.000Z"
  }
}

Queue

GET/api/v1/queueThe walk-in and waiting room queueread:schedule

Patients waiting now, oldest first.

status: Queue status.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "fdq_4c3b2a1f0e9d8c7b6a5f",
      "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "status": "waiting",
      "urgency": "routine",
      "assignedProviderId": null,
      "joinedAt": "2026-10-14T14:58:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Invoices

GET/api/v1/invoicesList patient invoicesread:analytics

Read only. Taking a payment is never available by API.

patientId: Only this patient.status: Invoice status.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "inv_9a8b7c6d5e4f3a2b1c0d",
      "number": "INV-1042",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "description": "Follow-up visit",
      "amountCents": 12000,
      "paidCents": 0,
      "status": "open",
      "dueAt": "2026-11-01",
      "createdAt": "2026-10-14T16:10:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Analytics

GET/api/v1/analytics/summaryClinic analytics summaryread:analytics
days: Window in days, 1 to 365. Default 30.
Response 200
{
  "data": {
    "windowDays": 30,
    "from": "2026-09-11T00:00:00.000Z",
    "to": "2026-10-11T00:00:00.000Z",
    "patients": {
      "total": 412,
      "new": 37
    },
    "appointments": {
      "scheduled": 58,
      "completed": 211,
      "cancelled": 9
    },
    "notes": {
      "signed": 198
    },
  ...

eConsults

GET/api/v1/econsultsList eConsultsread:clinical

Read only: status and timing of written eConsults for a work queue. The question, files and reply stay in Megvite, and replying is never available by API.

patientId: Only this patient.status: eConsult status.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "ec_4c1d9e7a2b8f3e6d0a11",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "subject": "Rash on forearm",
      "status": "answered",
      "files": 2,
      "createdAt": "2026-10-11T09:12:00.000Z",
      "repliedAt": "2026-10-11T13:40:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Tasks

GET/api/v1/tasksList visit tasksread:clinical

Tasks from visits, newest change first. Default status is active (drafts and open tasks). Each task drafted by Megvite carries the exact words from the visit it came from; a due date appears only when one was stated.

status: Task status.patientId: Only this patient.appointmentId: Only tasks from this visit.limit: Items per page, 1 to 100. Default 25.cursor: The nextCursor value from the previous page.
Response 200
{
  "data": [
    {
      "id": "vtk_3b9f1c0d7e2a4f6b8c1d",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "sessionId": "ses_1c9e2f7a40b3d8e6f001",
      "visitAt": "2026-10-14T15:00:00.000Z",
      "text": "Send the lipid panel order",
      "ownerRole": "nurse",
      "assigneeMemberId": null,
      "assigneeName": null,
      "dueDate": "2026-10-21",
      "priority": "normal",
      "status": "open",
      "origin": "agent",
      "source": {
        "segmentId": "art_7d2e9c1b0a4f",
  ...
POST/api/v1/tasks/{id}/completeComplete a taskwrite:drafts

Marks one open task done as the credential's member. A Megvite draft can be completed only by a clinician. Send an Idempotency-Key header.

id (required): Task id.
Response 200
{
  "data": {
    "changed": [
      "vtk_3b9f1c0d7e2a4f6b8c1d"
    ],
    "skipped": []
  }
}
POST/api/v1/tasks/completeComplete up to 50 taskswrite:drafts

Marks up to 50 open tasks done. The response lists which changed and which were skipped, with the reason. Send an Idempotency-Key header.

taskIds (required): 1 to 50 task ids.
Request body
{
  "taskIds": [
    "vtk_3b9f1c0d7e2a4f6b8c1d"
  ]
}
Response 200
{
  "data": {
    "changed": [
      "vtk_3b9f1c0d7e2a4f6b8c1d"
    ],
    "skipped": []
  }
}

Search

GET/api/v1/searchSearch the visit recordread:clinical

Full-text search over saved visit transcripts, notes and call summaries, best match first, up to 50 passages. Scoped to the credential's clinic and the member's current access.

q (required): Words to find.patientId: Only this patient.tagId: Only visits with this clinic tag.kinds: Comma-separated sources: transcript, note, note_draft, summary.limit: Passages to return, 1 to 50. Default 25.
Response 200
{
  "data": [
    {
      "id": "transcript:trn_9a1c",
      "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
      "patientId": "pat_8f2c41d0a7b94e1c55aa",
      "source": "transcript",
      "sourceId": "trn_9a1c",
      "speaker": "Patient",
      "stamp": "04:12",
      "passage": "The tightness comes on after I climb the stairs",
      "visitAt": "2026-10-14T15:00:00.000Z",
      "imported": false
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
GET/api/v1/visit-tagsList clinic visit tagsread:clinical

The clinic's visit tags, active and retired, with how many visits carry each one.

Response 200
{
  "data": [
    {
      "id": "tag_000001",
      "label": "Medication review",
      "status": "active",
      "visitCount": 12
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
POST/api/v1/appointments/{id}/tagsTag or untag a visitwrite:drafts

Adds a clinic tag to a visit or takes it off, as the credential's member (owners, admins and clinicians). A visit keeps up to 7 tags; a retired tag cannot be added. Tagging never signs, orders or sends anything. Send an Idempotency-Key header.

id (required): Appointment id.tagId (required): Clinic tag id from GET /api/v1/visit-tags.action: add (default) or remove.
Request body
{
  "tagId": "tag_000001",
  "action": "add"
}
Response 200
{
  "data": {
    "appointmentId": "ses_1c9e2f7a40b3d8e6f001",
    "tags": [
      {
        "id": "tag_000001",
        "label": "Medication review",
        "source": "clinician",
        "addedAt": "2026-10-26T14:00:00.000Z"
      }
    ],
    "limit": 7
  }
}

Webhooks

Register an HTTPS endpoint in Settings and choose its events. Megvite posts each event when the change commits, signs it, and retries failures with backoff for about a day. The delivery log shows every attempt and lets you send one again.

appointment.created
An appointment was booked.
appointment.updated
An appointment changed time or status.
appointment.cancelled
An appointment was cancelled.
visit.started
A visit went live.
visit.ended
A visit ended.
note.signed
A clinician signed a visit note.
message.received
A patient sent a message.
patient.created
A patient was registered.
queue.joined
A patient joined the waiting room queue.
rpm.alert
A remote monitoring reading crossed a threshold.
Event body: identifiers only, read the record through the API
{
  "id": "evt_a558377f8227406da1ca",
  "type": "appointment.created",
  "createdAt": "2026-10-11T20:05:46.522Z",
  "clinicId": "org_cua",
  "data": {
    "entity": { "type": "session", "id": "ses_40ecd91de160438aba98" },
    "ids": { "patientId": "pat_6779b52e98824077a246" },
    "state": "scheduled",
    "counts": {}
  }
}
Verify Megvite-Signature: t=<seconds>,v1=<HMAC-SHA256>
import crypto from 'node:crypto';

// rawBody: the request body exactly as received, before JSON.parse.
export function verifyMegvite(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ''));
}

How every call behaves

Pagination

Lists return data, hasMore and nextCursor. Pass nextCursor back as cursor for the next page. limit runs from 1 to 100.

Errors

Every error is { "error": { "code", "message" } } with a matching HTTP status: 400, 401, 403, 404, 409 or 429.

Idempotency

Send an Idempotency-Key on every POST. A retry with the same key and body returns the first response with Idempotent-Replayed: true. The same key with a new body returns 409.

Rate limits

Each key or connection gets 120 requests a minute. Past that, calls return 429 with Retry-After.

Audit

Every call, allowed or refused, is written to the clinic audit log with the key, route and record.

Privacy

Psychotherapy notes and records flagged under 42 CFR Part 2 are never returned. Signing notes, sending prescriptions and taking payments stay inside Megvite.

Get an API key

A clinic owner or admin creates keys and webhook endpoints in Settings.