Luna SaludAPI ReferenceLuna Salud

Create an appointment

POST/appointments

Books an in-person appointment for an existing patient in your organization with one provider and one service. The end time is set from the service's duration. The start time must be in the future, inside the provider's availability, and free; use GET /availability to find open slots. Retrying an identical request returns the appointment already created instead of a duplicate. The appointment is created as CONFIRMED and no confirmation or reminders are sent to the patient. Requires an API key with the write scope.

Code samples

Node.js

const fetch = require('node-fetch');

async function callApi() {
  const apiKey = 'YOUR_API_KEY';
  const url = `https://account.lunahealth.app/api/appointments`;
  const requestBody = {
    // Add your request body data here
  };

  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(requestBody)
    });
    
    if (!response.ok) {
      throw new Error(`API error: ${response.status}`);
    }
    
    const data = await response.json();
    console.log(data);
    return data;
  } catch (error) {
    console.error('Error calling API:', error);
    throw error;
  }
}

callApi();

Python

import requests

def call_api():
    api_key = 'YOUR_API_KEY'
    
    url = 'https://account.lunahealth.app/api/appointments'
    
    headers = {
        'Authorization': f'Bearer {api_key}',
        'Content-Type': 'application/json'
    }
    
    params = {

    }
    
    # Add your request body data here
    request_body = {}
        try:
        response = requests.post(
            url,
            headers=headers,
            params=params,
            json=request_body
        )
        response.raise_for_status()
        
        data = response.json()
        print(data)
        return data
    except requests.exceptions.RequestException as e:
        print(f'Error calling API: {e}')
        raise

call_api()

Request body

Required

Request fields

NameTypeRequiredDescription
patientIdstringYesID of an existing patient in your organization
staffIdstringYesID of the provider (staff member) who will see the patient
serviceIdstringYesID of the service; its duration sets the end time
startTimestring (date-time)YesStart time in ISO 8601 with a UTC offset, e.g. a start_time from GET /availability
locationIdstringNoID of the location where the appointment takes place
reasonForVisitstringNoReason for the visit, shown to staff

Example request

{
  "patientId": "string",
  "staffId": "string",
  "serviceId": "string",
  "startTime": "2025-01-01T00:00:00Z",
  "locationId": "string",
  "reasonForVisit": "string"
}

Responses

StatusDescription
200Successful response
400Invalid input data
401Authorization not provided
403Insufficient access
500Internal server error

200 — Successful response

Response fields

NameTypeRequiredDescription
idstringYes—
statusstringYes—
typestringYes—
titlestringnullYes—
descriptionstringnullYes—
start_timestringYes—
end_timestringYes—
telemedicinebooleanYes—
created_atstringYes—
updated_atstringYes—
patientobject | nullYes—
staffsarray<object>Yes—
serviceobject | nullYes—
locationobject | nullYes—

Example response

{
  "id": "string",
  "status": "NEW",
  "type": "APPOINTMENT",
  "title": null,
  "description": null,
  "start_time": "string",
  "end_time": "string",
  "telemedicine": true,
  "created_at": "string",
  "updated_at": "string",
  "patient": {
    "id": "string",
    "first_name": null,
    "last_name": null,
    "email": null
  },
  "staffs": [
    {
      "id": "string",
      "first_name": null,
      "last_name": null
    }
  ],
  "service": {
    "id": "string",
    "name": "string"
  },
  "location": {
    "id": "string",
    "name": null
  }
}

400 — Invalid input data

Response fields

NameTypeRequiredDescription
messagestringYesThe error message
codestringYesThe error code
issuesarray<object>NoAn array of issues that were responsible for the error

Example response

{
  "code": "BAD_REQUEST",
  "message": "Invalid input data",
  "issues": []
}

401 — Authorization not provided

Response fields

NameTypeRequiredDescription
messagestringYesThe error message
codestringYesThe error code
issuesarray<object>NoAn array of issues that were responsible for the error

Example response

{
  "code": "UNAUTHORIZED",
  "message": "Authorization not provided",
  "issues": []
}

403 — Insufficient access

Response fields

NameTypeRequiredDescription
messagestringYesThe error message
codestringYesThe error code
issuesarray<object>NoAn array of issues that were responsible for the error

Example response

{
  "code": "FORBIDDEN",
  "message": "Insufficient access",
  "issues": []
}

500 — Internal server error

Response fields

NameTypeRequiredDescription
messagestringYesThe error message
codestringYesThe error code
issuesarray<object>NoAn array of issues that were responsible for the error

Example response

{
  "code": "INTERNAL_SERVER_ERROR",
  "message": "Internal server error",
  "issues": []
}