New: Voice AI now handles 47+ calls daily per clinic. See how it works
API REFERENCE

Build on Relaya

RESTful APIs, real-time webhooks, and SDKs in Python and Node.js. Pull appointment data, sync patients, register webhook listeners, and automate clinical workflows. Sandbox included.

Base URL

api.relaya.one

Version

v1 (stable)

Format

JSON

Auth

Bearer token

Authentication

API keys and OAuth 2.0

Every request requires a Bearer token. Generate API keys from your dashboard or implement OAuth 2.0 for user-delegated access.

API Key (server-to-server)

For backend integrations. Generate in your Relaya dashboard under Settings > API Keys.

curl https://api.relaya.one/v1/appointments \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..."
  • Prefix: rlk_live_ (production) or rlk_test_ (sandbox)
  • Scopes: read, write, admin
  • Rotate keys without downtime via key pairs

OAuth 2.0 (user-delegated)

For apps acting on behalf of a clinic. Standard authorization code flow.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTH_CODE
&client_id=your_client_id
&client_secret=your_client_secret
&redirect_uri=https://your-app.com/callback
  • Access tokens expire in 1 hour
  • Refresh tokens valid for 30 days
  • PKCE supported for public clients

Key types and environments

PrefixEnvironmentRate limitData
rlk_test_SandboxUnlimitedTest data only
rlk_live_Production100 req/min (standard)Real patient data
rlk_live_Production (Enterprise)1,000 req/minReal patient data
Interactive

API Playground

Select an endpoint, hit Run, and see the response. All examples use the sandbox environment with test data.

API PlaygroundSandbox
Request
GET https://sandbox.api.relaya.one/v1/appointments?status=confirmed&limit=5
Authorization: Bearer rlk_test_sandbox123...
sandbox.api.relaya.one
Endpoints

Core API reference

50+ endpoints across appointments, patients, voice, scribe, and webhooks. Here are the ones you will use most.

POST/v1/appointmentsCreate appointment

Request

curl -X POST https://api.relaya.one/v1/appointments \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "patient_id": "pat_3kLm9",
    "provider_id": "doc_mK8n2",
    "datetime": "2026-07-28T14:00:00+05:30",
    "duration_minutes": 30,
    "type": "follow_up",
    "notes": "Post-procedure review"
  }'

Response

// 201 Created
{
  "id": "apt_9nR4xPq",
  "status": "confirmed",
  "patient_id": "pat_3kLm9",
  "provider_id": "doc_mK8n2",
  "datetime": "2026-07-28T14:00:00+05:30",
  "duration_minutes": 30,
  "type": "follow_up",
  "created_at": "2026-07-25T11:00:00Z"
}
GET/v1/appointmentsList appointments

Request

curl https://api.relaya.one/v1/appointments?status=confirmed&limit=20 \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..."

Response

// 200 OK
{
  "data": [
    {
      "id": "apt_8x7kL2m",
      "patient_id": "pat_3kLm9",
      "patient_name": "Anita Kumar",
      "provider": "Dr. Verma",
      "datetime": "2026-07-25T10:30:00+05:30",
      "duration_minutes": 30,
      "status": "confirmed",
      "source": "voice_ai",
      "created_at": "2026-07-24T14:22:00Z"
    }
  ],
  "meta": { "total": 142, "page": 1, "per_page": 20 }
}
GET/v1/patientsList patients

Request

curl https://api.relaya.one/v1/patients?limit=10&sort=last_visit \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..."

Response

// 200 OK
{
  "data": [
    {
      "id": "pat_3kLm9",
      "name": "Anita Kumar",
      "phone": "+919876543210",
      "email": "anita.kumar@email.com",
      "tags": ["vip", "orthodontics"],
      "last_visit": "2026-07-20T10:00:00+05:30",
      "total_visits": 8
    }
  ],
  "meta": { "total": 1240, "page": 1, "per_page": 10 }
}
POST/v1/patientsCreate patient

Request

curl -X POST https://api.relaya.one/v1/patients \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Priya Mehta",
    "phone": "+919988776655",
    "email": "priya.mehta@email.com",
    "date_of_birth": "1985-11-22",
    "gender": "female"
  }'

Response

// 201 Created
{
  "id": "pat_9xKr4Nw",
  "name": "Priya Mehta",
  "phone": "+919988776655",
  "email": "priya.mehta@email.com",
  "date_of_birth": "1985-11-22",
  "gender": "female",
  "total_visits": 0,
  "created_at": "2026-07-25T12:00:00Z"
}
POST/v1/voice/callsInitiate voice call

Request

curl -X POST https://api.relaya.one/v1/voice/calls \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+919876543210",
    "patient_id": "pat_3kLm9",
    "purpose": "appointment_reminder",
    "script_id": "scr_reminder_v2",
    "language": "hi"
  }'

Response

// 202 Accepted
{
  "id": "call_6xNm8Rp",
  "status": "initiating",
  "to": "+919876543210",
  "patient_id": "pat_3kLm9",
  "purpose": "appointment_reminder",
  "estimated_duration_seconds": 60,
  "started_at": "2026-07-25T11:05:00Z"
}
GET/v1/voice/calls/:idGet call details

Request

curl https://api.relaya.one/v1/voice/calls/call_6xNm8Rp \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..."

Response

// 200 OK
{
  "id": "call_6xNm8Rp",
  "direction": "outbound",
  "to": "+919876543210",
  "patient_id": "pat_3kLm9",
  "purpose": "appointment_reminder",
  "status": "completed",
  "outcome": "confirmed",
  "duration_seconds": 47,
  "transcript_available": true,
  "recording_url": "https://storage.relaya.one/calls/call_6xNm8Rp.wav",
  "started_at": "2026-07-25T11:05:00Z",
  "ended_at": "2026-07-25T11:05:47Z"
}
POST/v1/scribe/transcribeSubmit audio for transcription

Request

curl -X POST https://api.relaya.one/v1/scribe/transcribe \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "appointment_id": "apt_8x7kL2m",
    "audio_url": "https://storage.relaya.one/recordings/rec_abc123.wav",
    "template": "soap",
    "language": "en"
  }'

Response

// 202 Accepted (async processing)
{
  "id": "note_5pQr8Wx",
  "status": "processing",
  "appointment_id": "apt_8x7kL2m",
  "template": "soap",
  "estimated_seconds": 45,
  "webhook_on_complete": true
}
GET/v1/analytics/dashboardGet analytics data

Request

curl https://api.relaya.one/v1/analytics/dashboard?period=7d \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..."

Response

// 200 OK
{
  "period": "7d",
  "appointments": {
    "total": 287,
    "confirmed": 241,
    "cancelled": 22,
    "no_show": 24
  },
  "calls": {
    "total": 412,
    "answered": 389,
    "average_duration_seconds": 87
  },
  "revenue": {
    "total": 485000,
    "currency": "INR",
    "average_per_appointment": 1690
  },
  "patients": { "new": 34, "returning": 253 }
}
POST/v1/webhooksRegister webhook

Request

curl -X POST https://api.relaya.one/v1/webhooks \
  -H "Authorization: Bearer rlk_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/hooks/relaya",
    "events": ["appointment.created", "call.completed"],
    "secret": "whsec_your_signing_secret"
  }'

Response

// 201 Created
{
  "id": "wh_7mNp3Kx",
  "url": "https://your-app.com/hooks/relaya",
  "events": ["appointment.created", "call.completed"],
  "status": "active",
  "created_at": "2026-07-25T11:05:00Z"
}
SDKs and Examples

Your language, your way

Official SDKs for Python and Node.js. Or use curl. Every endpoint works the same across all three.

Create an appointment
import relaya

client = relaya.Client(api_key="rlk_live_a1b2c3d4...")

appointment = client.appointments.create(
    patient_id="pat_3kLm9",
    provider_id="doc_mK8n2",
    datetime="2026-07-28T14:00:00+05:30",
    duration_minutes=30,
    type="consultation"
)

print(appointment.id)      # apt_9nR4xPq
print(appointment.status)  # confirmed
List patients with filters
import relaya

client = relaya.Client(api_key="rlk_live_a1b2c3d4...")

patients = client.patients.list(
    tag="vip",
    limit=10
)

for patient in patients.data:
    print(f"{patient.name} - {patient.total_visits} visits")
Register a webhook
import relaya

client = relaya.Client(api_key="rlk_live_a1b2c3d4...")

webhook = client.webhooks.create(
    url="https://your-app.com/hooks/relaya",
    events=["appointment.created", "call.completed"],
    secret="whsec_your_signing_secret"
)

print(webhook.id)      # wh_7mNp3Kx
print(webhook.status)  # active
Webhooks

Real-time event delivery

Register a URL endpoint and receive POST requests when events fire. All payloads are signed with your webhook secret using HMAC-SHA256.

EventDescription
appointment.createdNew appointment booked via any channel
appointment.cancelledAppointment cancelled by patient or provider
call.completedVoice AI call ended with outcome data
patient.createdNew patient record created in the system
patient.checked_inPatient marked as arrived at clinic
prescription.generatedAI-generated prescription ready for review
note.generatedClinical note finished processing
payment.receivedPayment collected from patient

Payload examples

appointment.created

POST https://your-app.com/hooks/relaya
Content-Type: application/json
X-Relaya-Signature: sha256=a1b2c3d4e5f6...
X-Relaya-Event: appointment.created

{
  "id": "evt_mN7pR2x",
  "event": "appointment.created",
  "created_at": "2026-07-25T10:30:00Z",
  "data": {
    "id": "apt_8x7kL2m",
    "patient_id": "pat_3kLm9",
    "provider_id": "doc_mK8n2",
    "datetime": "2026-07-28T14:00:00+05:30",
    "source": "voice_ai"
  }
}

call.completed

POST https://your-app.com/hooks/relaya
Content-Type: application/json
X-Relaya-Signature: sha256=f6e5d4c3b2a1...
X-Relaya-Event: call.completed

{
  "id": "evt_pQ8rS3y",
  "event": "call.completed",
  "created_at": "2026-07-25T11:06:00Z",
  "data": {
    "id": "call_6xNm8Rp",
    "direction": "outbound",
    "patient_id": "pat_3kLm9",
    "duration_seconds": 47,
    "outcome": "confirmed",
    "transcript_available": true
  }
}

prescription.generated

POST https://your-app.com/hooks/relaya
Content-Type: application/json
X-Relaya-Signature: sha256=c3d4e5f6a1b2...
X-Relaya-Event: prescription.generated

{
  "id": "evt_xY9zW4v",
  "event": "prescription.generated",
  "created_at": "2026-07-25T11:30:00Z",
  "data": {
    "id": "rx_2mNp7Kx",
    "appointment_id": "apt_8x7kL2m",
    "patient_id": "pat_3kLm9",
    "provider_id": "doc_mK8n2",
    "status": "pending_review",
    "medications_count": 3
  }
}

Retry policy

If your endpoint returns a non-2xx status code or times out (30s), we retry with exponential backoff:

AttemptDelayTotal elapsed
1st retry1 minute~1 min
2nd retry5 minutes~6 min
3rd retry30 minutes~36 min
4th retry2 hours~2.5 hrs
5th retry (final)8 hours~10.5 hrs

After 5 failed attempts, the event is marked as failed. You can replay failed events from your dashboard or via the API (POST /v1/webhooks/:id/replay).

SDKs

Official SDKs

Type-safe clients with automatic retries, pagination helpers, and webhook signature verification built in.

Python

Coming Soon

pip install relaya

from relaya import Client

client = Client(api_key="rlk_live_...")

# List today's appointments
appointments = client.appointments.list(
    date="2026-07-25",
    status="confirmed"
)

for apt in appointments:
    print(f"{apt.patient_name} at {apt.time}")

# Create a patient
patient = client.patients.create(
    name="Priya Mehta",
    phone="+919988776655"
)

# Listen to webhooks
@client.webhook_handler("appointment.created")
def on_appointment(event):
    print(f"New: {event.data.id}")
  • Python 3.8+
  • Async support (asyncio)
  • Type hints throughout
  • Automatic pagination

Node.js

Coming Soon

npm install @relaya/sdk

import Relaya from '@relaya/sdk';

const relaya = new Relaya({
  apiKey: 'rlk_live_...'
});

// List today's appointments
const appointments = await relaya.appointments
  .list({ date: '2026-07-25', status: 'confirmed' });

appointments.data.forEach(apt => {
  console.log(`${apt.patientName} at ${apt.time}`);
});

// Verify webhook signatures
const isValid = relaya.webhooks.verify(
  payload,
  signature,
  secret
);
  • Node.js 18+
  • Full TypeScript definitions
  • ESM and CJS support
  • Auto-retry with backoff

REST API

Available

https://api.relaya.one/v1/

# Works with any HTTP client
curl https://api.relaya.one/v1/appointments \
  -H "Authorization: Bearer rlk_live_..."

# All responses are JSON
# Pagination via ?page=&per_page=
# Filtering via query parameters
# Sorting via ?sort=field&order=asc

# Error responses follow RFC 7807
{
  "error": {
    "code": "invalid_request",
    "message": "patient_id is required",
    "param": "patient_id"
  }
}
  • No dependencies
  • Any language, any platform
  • OpenAPI 3.0 spec available
  • Postman collection included
Use Cases

What developers build with Relaya

Custom booking widget

Embed appointment booking on your own website. Use GET /v1/providers to show availability, POST /v1/appointments to book. Style it however you want.

GET /v1/providers/availability, POST /v1/appointments

Sync with your internal EHR

Pull patient records and appointment data into your existing EHR system. Bidirectional sync keeps both systems current without manual data entry.

GET /v1/patients, webhooks: patient.*, appointment.*

Automate patient workflows

Trigger follow-up sequences when events fire. Patient completes visit? Auto-send feedback form. Payment received? Generate receipt. No manual steps.

webhooks: patient.checked_in, payment.received, call.completed

Custom analytics dashboard

Build reports on call volumes, booking rates, revenue per provider, no-show patterns. Pull raw data via the API and visualize in your BI tool.

GET /v1/voice/calls, GET /v1/analytics/dashboard

Platform details

Rate limits

Standard100 req/min
Enterprise1,000 req/min
Burst50 req/sec

429 responses include Retry-After header. SDK handles backoff automatically.

Versioning

Currentv1
Prefix/v1/resource
Deprecation12 months

Breaking changes only ship in new versions. Old versions supported for at least 12 months after deprecation notice.

Sandbox

Base URLsandbox.api.relaya.one
Test data50 patients
Rate limitNone

Full API surface with pre-populated test data. Webhooks fire on mutations. No rate limits.

Start building

API keys in 2 minutes. First successful call in 5. Free sandbox access included with every account.

Chat with us on WhatsApp