Skip to content

Lobbie Partner API (2.0)

Partner API Overview

Authentication

The Partner API uses OAuth 2.0 with AWS Cognito for secure machine-to-machine (M2M) authentication.

Prerequisites

Before making API requests, you must complete the partner onboarding process:

  1. Partner Registration: Lobbie creates a partner integrator record with your unique client_id
  2. Cognito Credentials: Lobbie provides OAuth 2.0 client credentials (client ID and client secret)
  3. API Gateway Key: Lobbie provides an x-api-key value that identifies your integration for rate limiting (see Rate Limits & Quotas)
  4. Account Grants: Lobbie grants your integration access to specific accounts

All three credentials (client_id, client_secret, and x-api-key) are shown only once at onboarding — store them securely. If any are lost or compromised, contact Lobbie support immediately.

Obtaining an Access Token

Request an access token using the OAuth 2.0 client credentials by sending an HTTPS form POST. Include the x-api-key header — the token endpoint is gated by the same API key as the rest of the Partner API:

POST https://api.lobbie.com/oauth2/token
Content-Type: application/x-www-form-urlencoded
x-api-key: <your_api_key>

grant_type=client_credentials&
scope=prod-lobbie-api/partner-api&
client_id=<your_client_id>&
client_secret=<your_client_secret>

The scope value is environment-prefixed. Use prod-lobbie-api/partner-api for production; Lobbie will provide the appropriate value for any non-production environment at onboarding.

The response contains a JWT access token:

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 3600
}

Cache this token. Tokens are valid for 60 minutes and the token endpoint has a much tighter rate limit than the main API (see Rate Limits & Quotas). A well-behaved integration fetches a token once and reuses it until shortly before it expires.

Making Authenticated Requests

Every API request must include both headers: the OAuth Bearer token (which authenticates you) and the API key (which identifies you to the gateway for rate limiting):

Authorization: Bearer <access_token>
x-api-key: <your_api_key>

Requests missing the x-api-key header are rejected at the API Gateway edge with 403 Forbidden before reaching the application. Requests with an invalid or revoked key are similarly rejected.

Token Management

  • Access tokens expire after the duration specified in expires_in (default: 60 minutes)
  • Request a new token before the current one expires
  • Store credentials securely—they grant access to protected health information (PHI)
  • If credentials are compromised, contact Lobbie support immediately to revoke and regenerate

Authorization

Your partner integration must have an active grant to access each account. The API validates:

  1. The JWT token is valid and not expired
  2. Your client_id corresponds to an active partner integrator
  3. Your integration has an active grant to the requested account
  4. The requested location belongs to the specified account

Rate Limits & Quotas

Limits are enforced per x-api-key. Two separate limits apply depending on which endpoint you're calling:

General API (/lobbie/api/partner/v2/*) — sustained rate limit 25 requests/second with a daily quota of 250,000 requests. We recommend targeting around 20 requests/second in steady-state to absorb natural timing variability.

Token endpoint (/oauth2/token) — enforced at a much tighter per-partner rate than the rest of the API. A correctly-implemented integration fetches a token once per hour and caches it until shortly before it expires; with that behavior you'll never approach the limit. If you're seeing 429s on /oauth2/token, your client is refreshing tokens far more often than needed — add caching rather than asking for a higher limit. Token calls count against the same daily quota as the rest of the API.

The daily quota resets at 00:00 UTC. Exceeding either limit returns 429 Too Many Requests with a JSON body and a Retry-After header. The two causes are distinguished by the machine-readable code field — switch on code, don't parse the message prose:

codeCauseRetry-AfterResponse bodyExpected back-off
THROTTLEDRate too high1{"code":"THROTTLED","message":"API rate limit exceeded. Retry after a short delay; throttle capacity refills within seconds."}Wait the second in Retry-After, then retry. Throttle capacity refills continuously.
QUOTA_EXCEEDEDDaily quota exhausted3600{"code":"QUOTA_EXCEEDED","message":"Daily request quota exhausted. The quota resets at 00:00 UTC."}Stop until the quota resets at 00:00 UTC. Retry-After is an hourly re-check hint, not the exact reset — retrying before 00:00 UTC keeps returning QUOTA_EXCEEDED.

Retry-After is expressed in seconds. Read code to decide how to react: THROTTLED clears within seconds, while QUOTA_EXCEEDED does not clear until the daily reset — treat them as short-wait and stop-until-reset respectively.

If your integration consistently approaches these limits, contact Lobbie.

Common Errors

StatusErrorDescription
401UnauthorizedInvalid, expired, or missing access token
403ForbiddenMissing/invalid x-api-key, or integration lacks access to the requested account or location
404Not FoundResource not found or does not belong to the authorized account
422Unprocessable EntityValidation failed — see error.fields for per-property details
429Too Many RequestsRate limit or daily quota exceeded (see Rate Limits & Quotas)

HIPAA & Compliance

  • All patient data is Protected Health Information (PHI)
  • Encrypt data at rest and in transit
  • Maintain audit logs of all data access
  • Sign Business Associate Agreement (BAA) before production access
  • Follow data retention policies per agreement

Webhooks

Lobbie can POST JSON event payloads to an HTTPS URL you configure. Managing webhook endpoints (create, list, update, delete, discover event types, send a test delivery) uses the Partner API with the same Bearer token and x-api-key as Making Authenticated Requests.

Registering and managing endpoints

  1. List subscribable event typesGET /lobbie/api/partner/v2/webhook/event-types returns the event type strings you may use in eventTypes when creating or updating an endpoint (alphabetical list; source of truth as new types are added).
  2. Create an endpointPOST /lobbie/api/partner/v2/webhook with a JSON body:
  • url — must be HTTPS with a public host (Lobbie validates the URL).
  • eventTypesnon-empty array; every value must appear in GET .../event-types.
  • name — optional label.
  1. Signing secret — On create only, the response includes signingSecret. Store it immediately; it is not returned on later GET/list responses.

Treat signingSecret like a password. You need it to verify Lobbie-Signature on inbound POSTs. If it is lost, delete the endpoint and create a new one.

Read, update, list, delete, and test-send are documented under the Webhooks tag in OpenAPI (paths under /lobbie/api/partner/v2/webhook).

Supported event types

When creating or updating an endpoint, eventTypes must contain one or more of the following subscribable event types. The same list is returned alphabetically by GET /lobbie/api/partner/v2/webhook/event-types (the source of truth as new types are added).

Event typeDescription
appointment.createdA new appointment was created
appointment.updatedAn existing appointment was updated
appointment.deletedAn appointment was deleted
patient.createdA new patient was created
patient.updatedAn existing patient was updated
patient.deletedA patient was deleted
form-packet.createdA new form packet was created
form-packet.updatedAn existing form packet was updated
payment.createdA successful charge was recorded (not emitted by all accounts — see Payment events)
payment-attempt.createdA payment attempt was first recorded (see Payment events)
payment-attempt.updatedA payment attempt's state changed (see Payment events)
subscription.createdA subscription was created (see Subscription events)
subscription.updatedA subscription changed, including cancellation (see Subscription events)

test.ping is used only for test deliveries (POST .../webhook/{webhookId}/test); it is not subscribable and does not appear in GET .../event-types.

Test delivery

POST /lobbie/api/partner/v2/webhook/{webhookId}/test triggers an immediate outbound POST to your configured URL so you can validate connectivity, timeouts, and signature verification. The event type for this delivery is test.ping; it is not included in GET .../event-types and is not something you subscribe to.

The request body requires an accountId you've been granted access to. Webhook endpoints are integrator-scoped and serve every account you're granted, so there is no implicit account to test under — you name one explicitly. The value is published verbatim as the delivery envelope's accountId, exactly as it would be on a real event. A request naming an account you can't access returns 404.

Inbound delivery (your server)

Lobbie delivers events with:

AspectValue
MethodPOST
Content-Typeapplication/json
BodyUTF-8 JSON (see below)

Headers you should read:

HeaderPurpose
Lobbie-Signaturet=<unix_seconds>,v1=<hex_hmac_sha256> (see Verifying signatures)
Lobbie-Webhook-Event-IdUnique id for the event (e.g. evt_...); use for idempotency / deduplication
Lobbie-Webhook-Event-TypeFor the test endpoint: test.ping. Otherwise matches your subscription (e.g. appointment.created)

Request body shape

The JSON body is an envelope plus an event-specific data object:

FieldDescription
versionPayload format version (e.g. 1)
eventIdSame id as Lobbie-Webhook-Event-Id
eventTypeSame string as Lobbie-Webhook-Event-Type
accountIdLobbie account the event source belongs to. Stable for the lifetime of the event and present on every delivery — use it to route incoming events without joining on fields inside data. For test.ping there is no source entity, so this is the accountId you supplied in the test request.
environmentLobbie deployment identifier
occurredAtWhen the event occurred (ISO-8601 instant)
sentAtWhen this delivery was sent (ISO-8601 instant)
deliveryAttemptAttempt number for this delivery (starts at 1; increments if Lobbie retries)
dataEvent payload (always a JSON object); see below

Example (illustrative shape only):

{
  "version": "1",
  "eventId": "evt_550e8400-e29b-41d4-a716-446655440000",
  "eventType": "appointment.created",
  "accountId": 12345,
  "environment": "prod",
  "occurredAt": "2025-03-15T14:30:00Z",
  "sentAt": "2025-03-15T14:30:01Z",
  "deliveryAttempt": 1,
  "data": {}
}

The envelope above is published as the WebhookEnvelope schema under components.schemas in this OpenAPI document — generate it alongside the REST models to get typed inbound webhook handlers.

Event data and REST responses

For domain events, the data object uses the same JSON structure as the corresponding Partner API success response body—you can reuse the same models and OpenAPI schemas you already use for REST.

Example — appointment.created: data is an Appointment object with the same fields and types as the 200 OK body of:

GET /lobbie/api/partner/v2/account/{accountId}/location/{locationId}/appointment/{appointmentId}

Refer to the OpenAPI document for that operation’s response schema.

For test.ping (test send only), data is a small object with endpointId and message.

Payment events

Lobbie emits three payment-related event types. Pick subscriptions based on what you need to do.

Event typeWhen it firesdata shape
payment.createdOnce per successful charge — emitted only for accounts on Lobbie's current payments platform; some accounts never emit it. Where present, an authoritative signal that money moved.Payment (same as the GET .../payments/{paymentId} 200 OK body)
payment-attempt.createdWhen a payment attempt is first recorded, before submission. status is typically PENDING.PaymentAttempt (same as the GET .../payment-attempts/{paymentAttemptId} 200 OK body)
payment-attempt.updatedWhen a payment attempt's state changes, including the transition to a terminal status (SUCCEEDED, FAILED, CANCELED).PaymentAttempt (same shape as .created)

Subscription guidance:

  • For billing integrations (record-of-truth that a charge succeeded): subscribe to payment-attempt.updated and treat status == SUCCEEDED as the success signal. This is the only success signal emitted by every account, so it is the reliable choice for billing.
  • For failure handling (retry workflows, patient notifications, dunning): subscribe to payment-attempt.updated and filter on status == FAILED.
  • payment.created is an optional convenience for accounts that emit it (fires once per successful charge). Not all accounts do, so do not rely on it as a universal success signal. Do not use both it and payment-attempt.updated (SUCCEEDED) as billing triggers for the same account — that double-counts every successful charge. Pick one.

Every successful payment emits payment-attempt.created and payment-attempt.updated (with a terminal status); accounts on Lobbie's current payments platform additionally emit payment.created. These events may be observed in any order — dedupe retries by eventId, reconcile by occurredAt, and re-read the resource via the corresponding GET endpoint when you need an authoritative current state.

Subscription events

Lobbie emits two subscription event types, for every account regardless of payments platform.

Event typeWhen it firesdata shape
subscription.createdWhen a subscription is created.Subscription (same as the GET .../subscription/{subscriptionId} 200 OK body)
subscription.updatedWhen any field of a subscription changes — status, payment method, terms, or a next-billing-date advance.Subscription (same shape as .created)

Subscription guidance:

  • Cancellation is a status transition, not a delete. A cancelled subscription is delivered as a subscription.updated whose data.status is CANCELLED. There is no subscription.deleted event.
  • subscription.updated fires on any change, not only status transitions. To detect a transition (such as active → cancelled), compare data.status against the last value you recorded for that subscription — the same pattern used for payment-attempt.updated.
  • data.status uses the unified vocabulary documented on the Subscription resource (DRAFT, ACTIVE, PENDING, PAUSED, CANCELLED, COMPLETED, FAILED, VOID), identical to what the GET .../subscription endpoints return for the same account. On some accounts an overdue or failing-payment subscription is surfaced as ACTIVE until it is cancelled or completes — the webhook matches the GET endpoint in this respect.
  • These events may be observed in any order — dedupe retries by eventId, reconcile by occurredAt, and re-read the subscription via GET when you need an authoritative current state.

Verifying signatures

Each inbound POST is signed with HMAC-SHA256 using your endpoint's signingSecret (UTF-8 bytes of the string as the HMAC key).

Parse the Lobbie-Signature header. It uses the form t=<unix_seconds>,v1=<hex_hmac_sha256>.

Compute HMAC-SHA256 over the literal bytes: UTF-8 encoding of t as a decimal digit string, then ASCII . (0x2E), then the raw HTTP request body bytes.

Compare your digest to v1 using a constant-time equality check (compare the decoded digest bytes, not string shortcuts on secrets).

On retries, Lobbie may send a new JSON body: sentAt, deliveryAttempt, and the t value in Lobbie-Signature change to match that attempt. Verify each POST with that request's t and raw body bytes — do not reuse an HMAC you computed for an earlier delivery.

Acknowledging delivery

After you accept the payload, respond with any HTTP status in the 2xx range so Lobbie records a successful delivery.

Retries

Lobbie will re-send a failed or timed-out request with exponential backoff between attempts after each failure: approximately 2 minutes, 4 minutes, 8 minutes, then 15 minutes. After 5 total attempts (the first attempt plus four retries), the delivery is treated as failed and no further retries are made — total recovery window is roughly half an hour. The deliveryAttempt field in the JSON body indicates which attempt you are handling (1-indexed). Each retry is a new request with an updated body and signature (see Verifying signatures).

Delivery guarantees

Design your handler around these guarantees. They are intrinsic to how delivery works and will not change without a versioned, announced change.

  • At-least-once delivery once an event is accepted for delivery. Once an event has been accepted onto the delivery queue, it will be attempted at least once and may arrive more than once (e.g. a retry after your server accepted the request but the response was lost). Deduplicate by eventId (Lobbie-Webhook-Event-Id) and make your handler idempotent. eventId and occurredAt are stable across every retry of the same event; only sentAt, deliveryAttempt, and the signature t change per attempt. Note that acceptance onto the delivery queue happens after the originating database transaction commits and is best-effort; in the rare case the queue is unreachable at that moment the event may not be delivered. Lobbie alerts internally on those failures.
  • No ordering guarantee. Events are delivered over an unordered queue. Do not assume that delivery order matches the order changes occurred — even for the same entity. Order and reconcile on your side using occurredAt (and eventId to dedupe). For example, an appointment.updated may arrive before the appointment.created for the same appointment.
  • No backfill for endpoints registered after an event occurs. Subscriptions are evaluated at the moment the entity changes, not at delivery time. An endpoint created (or a newly added event-type subscription) after a change occurred will not receive that earlier event. There is no replay; only changes that happen after the subscription exists are delivered.
  • Delete events carry metadata only. For deletion events the entity no longer exists by delivery time, so the payload's data contains identity only — the entity type and its id — and no entity body. The envelope (eventId, occurredAt, eventType) still applies. Use the prior created/updated events (deduplicated by eventId) if you need the last-known state of a deleted entity.

Terminology

This glossary defines domain-specific terms used throughout the Lobbie Partner API.


Core Entities

Account

A healthcare practice or organization using Lobbie. Each account contains practice-wide settings and configurations, and can have multiple locations. All API access is scoped to a specific account via OAuth tokens.

Location

A physical practice site, clinic, or virtual care location within an account. Locations have their own addresses, staff assignments, schedules, and operational settings. Appointments, forms, and many operations are location-scoped. Each location has timezone information critical for accurate scheduling. Locations may have an optional storeId that partners can use to correlate Lobbie locations with their own systems.

Patient

An individual receiving healthcare services from a specific account. Contains demographic information (name, date of birth) and contact details (email, phone). Serves as the central entity linking appointments, forms, invoices, and clinical data. Subject to HIPAA privacy requirements.


Scheduling

Appointment

A scheduled visit between a patient and practitioner at a specific location and time. Appointments track the complete visit lifecycle from initial scheduling through check-in, the visit itself, and completion or cancellation. Each appointment links to an appointment type, patient, practitioner, and location.

Appointment Type

A template defining a schedulable service, including duration, telehealth settings, display color, and patient-facing description/instructions. Examples: "New Patient Consultation" (30 min), "Follow-up Visit" (15 min), "Telehealth Checkup" (20 min). Appointment types determine what services patients can book and how long they're scheduled.

Practitioner

A staff member designated as a clinical provider who can see patients and be scheduled for appointments. Practitioners have credentials (MD, DO, NP, PA, RN), NPI numbers, specialties, and license information. All practitioners are staff members, but not all staff are practitioners.

Self-Scheduling

Patient-initiated appointment booking through embeddable widgets or API integration. Self-scheduling respects practice availability rules, appointment type configurations, and booking windows. Patients can browse available times and complete bookings without staff intervention.

Self-Scheduling Attempt

A record of a patient's journey through the self-scheduling process, from initiation to completion or abandonment. Captures step-by-step progress for conversion analysis, identifying drop-off points, and triggering follow-up workflows for incomplete attempts.


Staff & Access

Staff Member

Any team member with system access, including administrative staff, clinical support, and practitioners. Staff have role assignments determining their permissions and location access.

Role Group

A permission set defining capabilities and access levels for staff members. Role groups control what actions staff can perform within the system, from standard user access to full administrative privileges. Staff members can have multiple role groups assigned, combining permissions as needed.


Forms & Documentation

Form Template

A reusable form design defining structure, fields, validation rules, and conditional logic. Templates are created once and used to generate form instances for patients. Form templates support versioning—when a template is modified, a new version is created while preserving previous versions for historical form submissions. Examples: "Patient Intake Form", "HIPAA Consent", "Medical History Questionnaire".

Form Group

A collection of one or more form instances assigned to a patient for completion. Form groups track overall completion status and can include multiple related forms. A form group is considered complete when all forms within it have been submitted, and can be archived when no longer needed.

Form

An individual form instance within a form group, based on a form template version. Each form tracks its own completion status and contains the patient's responses.

Form Element

A single field or component within a form template that captures patient input or displays content. Element types include: text inputs, text areas, dropdowns, checkboxes, radio buttons, date pickers, signatures, initials, file uploads, phone numbers, email addresses, addresses, and specialized types like payment fields and body diagrams. Elements can be configured as required or optional, and can have visibility rules controlling who can view or edit them (patient only, staff only, or both).

Form Answer

A patient's response to a specific form element. Answers are stored per element and can be text, selections, dates, signatures, or file uploads depending on the element type.

Form Template Group

A predefined collection of form templates commonly assigned together. Simplifies assigning multiple related forms in a single operation (e.g., "New Patient Packet" containing intake, consent, and history forms).


Billing & Payments

Invoice

An itemized billing statement for a patient detailing charges for services, products, taxes, and fees. Invoices progress through a lifecycle from creation to payment or cancellation. Invoices can be linked to appointments or created independently.

Invoice Line Item

A single charge entry within an invoice. Line items specify quantity, unit price, and description, and can represent services, products, adjustments, or taxes. May reference billing codes and associated care resources.

Payment Request

A trackable record of a payment’s lifecycle, from initiation to final settlement. Each request tracks its status from creation through payment or expiration, whether triggered as a remote request sent to a patient (via email or SMS) or entered directly by staff for immediate processing.

Recurring Payment

An automated payment plan with scheduled charges at defined intervals. Used for payment plans, memberships, and subscription services. Configured with a frequency (weekly, monthly, etc.), amount, linked payment method, and optional end date.


Labs & Clinical

Lab

A laboratory order containing one or more test panels with results. Labs track progress from order placement through result delivery. Labs can be in-house or from external vendors and link to patients and optionally appointments.

Test Panel

A grouping of related lab tests within a lab order. Examples: "Comprehensive Metabolic Panel", "Complete Blood Count", "Lipid Panel". Each panel contains multiple test components.

Test Component

An individual lab measurement within a test panel. Contains the test name, result value, unit of measurement, reference range, and an indicator of whether the result is normal or abnormal.

Health Profile

Structured patient health information including medical history, allergies, medications, and clinical data collected through intake forms and clinical encounters.


Patient Management

Category

A service category that can function as either a CRM-tracked sales pipeline or a simple organizational tag. When CRM-tracked, categories enable full pipeline tracking through status stages with dashboard visibility. When not CRM-tracked, categories function as simple groupings for billing, inventory, or reporting. Examples of CRM categories: "Men's Health - Testosterone", "Weight Loss - Semaglutide". Examples of simple categories: "Lab Supplies", "Office Visits".

Patient Category

A patient's enrollment in a specific service category with CRM status tracking. Represents the link between a patient and a category, tracking their progress through the associated CRM pipeline. Appears as an "Opportunity" in CRM dashboards. Tracks status transitions with a complete audit trail.

CRM Status Group

A reusable CRM workflow pipeline (sales/marketing funnel) that defines the customer journey stages. Think of it as the sales funnel template—the workflow (HOW you sell) is separated from the product (WHAT you sell). Multiple categories often share the same sales process. Examples: "Digital Marketing Funnel" with stages like Cold Lead → Engaged → Sales Qualified → Closed Won; "Patient Care Journey" with stages like Intake → Insurance Verified → In Treatment → Complete.

CRM Status

An individual stage within a CRM status group representing where a patient is in a workflow. Status progression is tracked through transitions, providing a complete audit trail. Examples: "Cold Lead", "Sales Qualified", "Proposal Sent", "Closed Won", "Closed Lost".


Communications

Notification

A system-generated message sent to a patient via email or SMS. Notifications are sent for various purposes including appointment reminders, form assignments, payment requests, and account recovery. Each notification tracks its delivery status.

Notification Group

Configuration defining how and when patients receive specific types of communications, customizable per location or appointment type.


Identity & Security

Identity Proof

A verification session for authenticating patient identity through email and/or SMS code verification. Used for patient portal authentication, self-scheduling verification, and secure access to patient data. Each session generates a secure token and tracks which contact methods have been verified.

Verification Method

The channel(s) required to prove identity, which can be email only, SMS only, or both. The verification method determines what must be verified before the identity proof is considered complete.

Download OpenAPI description
Overview
Lobbie API Team
Languages
Servers
Mock server
https://api-docs.lobbie.com/_mock/openapi
Production
https://api-prod.lobbie.com/lobbie/api