Most scheduling APIs give you a list of providers and availability slots — then leave you to figure out the matching yourself. You end up writing custom logic to filter by language, check modality support, rank by preference, and handle edge cases like empty results or expired slots. It's a lot of glue code for something that should be solved infrastructure.
Orita's resolveScheduling call does all of that in one shot. You describe what the patient needs, and Orita returns a ranked list of bookable slots — across every provider in your network — with reasons for each recommendation.
This guide walks through the full flow for a mental health platform: from SDK setup to confirmed booking, plus curl equivalents if you prefer the raw REST API.
The problem with existing scheduling APIs
A typical scheduling integration looks like this:
- Fetch all providers
- Filter by language, modality, specialty
- For each matching provider, fetch their availability
- Merge and rank results
- Handle the case where no providers match
- Hope the slot you found is still available when the user clicks "Book"
That's five network requests and a non-trivial amount of stateful logic, just to answer "who can this patient see, and when?" Multiply that by every new constraint you add (timezone, insurance, session type) and it becomes a maintenance burden.
resolveScheduling collapses all of that into a single call.
How resolveScheduling works
Under the hood, Orita queries your provider network against the constraint set you provide, checks live availability within the date range, and returns a ranked options[] array. Each option includes the provider, the specific slot, the modality, and a human-readable reason explaining why it was matched.
You pass constraints (what the patient needs), an optional preference (what to optimize for), and a dateRange (max 14 days). Orita does the rest.
Step 1: Install and configure the SDK
npm install orita-sdk
import { OritaClient } from "orita-sdk";
const orita = new OritaClient({
apiKey: process.env.ORITA_API_KEY,
});
Your API key lives in the Orita dashboard under Settings → API Keys. Never commit it — use an environment variable.
Step 2: Call resolveScheduling
Here's a real call for a patient who needs a Spanish-speaking therapist available for online sessions:
const result = await orita.resolveScheduling({
constraints: {
language: "es",
modality: "online",
specialty: "anxiety",
},
dateRange: {
from: "2026-08-01",
to: "2026-08-14",
},
preference: "earliest",
});
const { options } = result;
Constraint fields (all optional — omit what you don't need):
| Field | Type | Description |
|--------------|--------|------------------------------------------|
| language | string | ISO 639-1 code ("es", "en", "fr") |
| modality | string | "online" or "in-person" |
| specialty | string | Clinical specialty or focus area |
| profession | string | Provider profession (e.g. "therapist") |
preference accepts "earliest" (default), "latest", or "random".
dateRange must span at most 14 days. For longer windows, paginate by shifting from/to.
Step 3: Present options to the user
Each item in options[] has everything you need to render a slot picker:
for (const option of options) {
console.log(`
Provider: ${option.providerName}
Date: ${option.date}
Time: ${option.time}
Modality: ${option.modality}
Why: ${option.reason}
Slot ID: ${option.slotId}
`);
}
A typical options[] item looks like:
{
"providerId": "prov_abc123",
"providerName": "Dra. Laura Méndez",
"eventTypeId": "evt_xyz789",
"slotId": "slot_q1w2e3r4",
"date": "2026-08-03",
"time": "10:00",
"label": "Sesión individual — 50 min",
"modality": "online",
"reason": "Spanish-speaking therapist specializing in anxiety, earliest available slot"
}
Render options as a list of cards in your UI. Show providerName, date, time, and reason — that last field builds patient trust by explaining why this provider was matched.
Step 4: Book with slotId
Once the patient picks a slot, book it:
const booking = await orita.book({
slotId: options[0].slotId,
customer: {
name: "Ana",
lastname: "García",
email: "ana.garcia@example.com",
},
});
console.log(booking.id); // "booking_..."
console.log(booking.status); // "pending"
book() returns { id, status } immediately. The initial status is always "pending" — it transitions to "confirmed" once the provider's system acknowledges the appointment (usually within seconds via webhook).
Status lifecycle:
pending → confirmed → completed
↘ cancelled
Store booking.id in your database so you can look up status later via GET /api/v1/bookings/:id.
Step 5: Handle edge cases
No options returned
If options is empty, no provider matched the constraints in the date range. Give the user an actionable message:
if (options.length === 0) {
// Widen the date range, relax a constraint, or show a waitlist CTA
return {
error: "no_availability",
message: "No hay disponibilidad con estos criterios. ¿Quieres buscar en las próximas dos semanas?",
};
}
Common causes: too narrow a date range, a combination of constraints with no matching providers, or all matching providers fully booked.
Expired slot (409)
Slots are not held between resolveScheduling and book. If another patient books the same slot first, book() throws a 409:
try {
const booking = await orita.book({ slotId, customer });
} catch (err) {
if (err.status === 409) {
// Slot was taken — re-run resolveScheduling and show fresh options
const fresh = await orita.resolveScheduling({ constraints, dateRange, preference });
return { retry: true, options: fresh.options };
}
throw err;
}
The fix is always the same: re-run resolveScheduling to get a fresh set of available slots.
Plan limits (429)
If you exceed your plan's request limit, you'll receive a 429 with a Retry-After header:
} catch (err) {
if (err.status === 429) {
const retryAfter = err.headers["retry-after"]; // seconds
await sleep(retryAfter * 1000);
// retry
}
}
For bulk operations, add explicit rate limiting (see the bulk onboarding guide).
Full working example
import { OritaClient } from "orita-sdk";
const orita = new OritaClient({ apiKey: process.env.ORITA_API_KEY });
async function findAndBookTherapist(patientEmail: string) {
// 1. Resolve available slots
let options;
try {
const result = await orita.resolveScheduling({
constraints: {
language: "es",
modality: "online",
specialty: "anxiety",
},
dateRange: {
from: "2026-08-01",
to: "2026-08-14",
},
preference: "earliest",
});
options = result.options;
} catch (err) {
console.error("resolveScheduling failed:", err.message);
throw err;
}
// 2. Handle no availability
if (options.length === 0) {
return { error: "no_availability" };
}
// 3. Pick the top option (or let the user choose)
const selected = options[0];
console.log(`Booking with ${selected.providerName} on ${selected.date} at ${selected.time}`);
// 4. Book the slot
try {
const booking = await orita.book({
slotId: selected.slotId,
customer: {
name: "Ana",
lastname: "García",
email: patientEmail,
},
});
console.log(`Booking created: ${booking.id} — status: ${booking.status}`);
return { booking, provider: selected };
} catch (err) {
if (err.status === 409) {
// Slot expired — return fresh options to the caller
const fresh = await orita.resolveScheduling({
constraints: { language: "es", modality: "online", specialty: "anxiety" },
dateRange: { from: "2026-08-01", to: "2026-08-14" },
preference: "earliest",
});
return { error: "slot_taken", freshOptions: fresh.options };
}
throw err;
}
}
findAndBookTherapist("ana.garcia@example.com").then(console.log);
REST API equivalent
Prefer to skip the SDK? Here's the same flow with curl.
Resolve scheduling:
curl -X POST https://orita.online/api/v1/resolve-scheduling \
-H "Authorization: Bearer $ORITA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"constraints": {
"language": "es",
"modality": "online",
"specialty": "anxiety"
},
"dateRange": {
"from": "2026-08-01",
"to": "2026-08-14"
},
"preference": "earliest"
}'
The response is a JSON object with an options array. Grab slotId from your chosen option.
Book the slot:
curl -X POST https://orita.online/api/v1/book \
-H "Authorization: Bearer $ORITA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"slotId": "slot_q1w2e3r4",
"customer": {
"name": "Ana",
"lastname": "García",
"email": "ana.garcia@example.com"
}
}'
Response:
{
"id": "booking_abc123",
"status": "pending"
}
What's next
- Webhooks: Listen to
booking.confirmedandbooking.cancelledto keep your own database in sync. - Onboarding providers: See Onboard Your Provider Network Programmatically to add therapists via API before you run
resolveScheduling. - Filtering by profession: Add
profession: "psychologist"to the constraints object to narrow results to a specific credential type.
resolveScheduling is designed to be the one call you make every time a patient needs an appointment — let Orita handle the matching, and focus your code on the patient experience.
