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
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
| Prefix | Environment | Rate limit | Data |
|---|---|---|---|
| rlk_test_ | Sandbox | Unlimited | Test data only |
| rlk_live_ | Production | 100 req/min (standard) | Real patient data |
| rlk_live_ | Production (Enterprise) | 1,000 req/min | Real patient data |
API Playground
Select an endpoint, hit Run, and see the response. All examples use the sandbox environment with test data.
GET https://sandbox.api.relaya.one/v1/appointments?status=confirmed&limit=5 Authorization: Bearer rlk_test_sandbox123...
Core API reference
50+ endpoints across appointments, patients, voice, scribe, and webhooks. Here are the ones you will use most.
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"
}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 }
}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 }
}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"
}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"
}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"
}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
}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 }
}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"
}Your language, your way
Official SDKs for Python and Node.js. Or use curl. Every endpoint works the same across all three.
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) # confirmedimport 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")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) # activeReal-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.
| Event | Description |
|---|---|
| appointment.created | New appointment booked via any channel |
| appointment.cancelled | Appointment cancelled by patient or provider |
| call.completed | Voice AI call ended with outcome data |
| patient.created | New patient record created in the system |
| patient.checked_in | Patient marked as arrived at clinic |
| prescription.generated | AI-generated prescription ready for review |
| note.generated | Clinical note finished processing |
| payment.received | Payment 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:
| Attempt | Delay | Total elapsed |
|---|---|---|
| 1st retry | 1 minute | ~1 min |
| 2nd retry | 5 minutes | ~6 min |
| 3rd retry | 30 minutes | ~36 min |
| 4th retry | 2 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).
Official SDKs
Type-safe clients with automatic retries, pagination helpers, and webhook signature verification built in.
Python
Coming Soonpip 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 Soonnpm 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
Availablehttps://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
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
429 responses include Retry-After header. SDK handles backoff automatically.
Versioning
Breaking changes only ship in new versions. Old versions supported for at least 12 months after deprecation notice.
Sandbox
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.