Most scheduling APIs answer one question: is this time slot available?
That's useful. But it's not the hard part.
The hard part is figuring out which provider to book in the first place — someone who speaks the right language, has the right specialty, and actually has a slot open in the next two weeks. That's the logic most teams end up writing themselves, buried in a service class that nobody wants to touch.
resolveScheduling is the endpoint that replaces all of that.
The Problem With Calendar APIs
Calendar and availability APIs are fundamentally slot-first. You query availability for a specific provider on a specific date, and you get back open times. The workflow looks like:
- You already know which provider you want
- You ask the API when they're free
- You book a slot
That's a clean model — when you know who you need. But many scheduling flows don't start with a provider. They start with a requirement: "I need a Spanish-speaking therapist with a background in cognitive behavioral therapy, available sometime this week."
Now you have a matching problem, and calendar APIs don't solve matching problems. You do.
What Developers Build Manually
Here's the pseudocode that lives in most scheduling backends that bolt onto a calendar API:
// The code nobody wants to maintain
async function findAvailableProvider(requirements, dateRange) {
// Step 1: get all providers
const allProviders = await calendarApi.getProviders();
// Step 2: filter by constraints manually
const matched = allProviders.filter(p =>
p.languages.includes(requirements.language) &&
p.specialties.includes(requirements.specialty) &&
p.modality === requirements.modality
);
if (matched.length === 0) throw new Error("No matching providers");
// Step 3: iterate dates in the range
const results = [];
for (const date of eachDayOfInterval(dateRange)) {
// Step 4: call availability for each matching provider — sequentially
for (const provider of matched) {
const slots = await calendarApi.getAvailability(provider.id, date);
if (slots.length > 0) {
results.push({ provider, date, slots });
}
}
}
// Step 5: pick "best" slot by some heuristic you made up
return results.sort(byEarliestDate)[0];
}
This is 20+ lines of logic that does no real business work — it's just plumbing. It runs availability checks sequentially (slow), encodes your matching heuristics in application code (fragile), and makes no guarantees about the slot still being available by the time the user books it.
And every team rewrites this from scratch.
What resolveScheduling Does
One API call replaces the entire block above:
const { options } = await orita.resolveScheduling({
service: "therapy-session",
constraints: {
language: "es",
modality: "video",
specialty: "cognitive-behavioral-therapy",
profession: "psychologist"
},
dateRange: {
start: "2026-08-01",
end: "2026-08-14"
},
preference: "earliest"
});
// options[0] is ready to book — no extra work needed
console.log(options[0]);
// {
// slotId: "c2xvdC10MDAxfDIwMjYtMDgtMDR8MDk6MDA",
// providerId: "prov_abc123",
// providerName: "Dra. Ana Martínez",
// date: "2026-08-04",
// time: "09:00",
// reason: "Earliest available slot matching all constraints"
// }
The same call in Python:
response = orita.resolve_scheduling(
service="therapy-session",
constraints={
"language": "es",
"modality": "video",
"specialty": "cognitive-behavioral-therapy",
"profession": "psychologist"
},
date_range={
"start": "2026-08-01",
"end": "2026-08-14"
},
preference="earliest"
)
option = response["options"][0]
print(option["providerName"]) # Dra. Ana Martínez
You get back a ranked list of options, each with a slotId you can pass directly to book(). No filtering, no iteration, no heuristics to maintain.
How It Works Internally
When you call resolveScheduling, Orita does the following on the server side:
- Filters providers by your constraints — language, modality, specialty, profession. Only providers that satisfy all constraints proceed.
- Resolves availability in parallel across all matching providers and all dates in the range. This is the part that kills sequential implementations — Orita fans out the queries concurrently.
- Ranks results according to your
preferencefield —"earliest"returns the soonest slot; future options may include"least-loaded"or"highest-rated". - Returns slotIds — not raw date/time strings, but validated slot identifiers that can be passed atomically to
book().
The key word is parallel. A sequential loop over 8 providers × 14 days = 112 sequential API calls. resolveScheduling makes those concurrently, which is why it consistently returns in under a second even for wide date ranges.
The Constraint Model
Each constraint is optional but additive — every constraint you add narrows the provider pool:
| Field | What it means | Example values |
|---|---|---|
| language | Provider must offer sessions in this language | "es", "en", "fr" |
| modality | How the session is delivered | "video", "in-person", "phone" |
| specialty | Clinical or professional specialty | "cognitive-behavioral-therapy", "sports-medicine" |
| profession | Provider credential type | "psychologist", "psychiatrist", "coach" |
All constraints are AND-ed together. If you pass language: "es" and specialty: "cbt", you only get providers who match both. If no providers match all constraints, the endpoint returns an empty options array rather than silently degrading the match quality.
The constraint model is deliberately coarse-grained. It's not a query engine — it's a filter that encodes your platform's service rules, not arbitrary SQL predicates.
resolveScheduling vs. solveScheduling
Both endpoints deal with scheduling, but they solve different problems:
-
solveScheduling— you know which provider you want. You're asking Orita to find the best available time for that specific provider given a set of time preferences or constraints. Provider is fixed; slot is variable. -
resolveScheduling— you know what kind of provider you need. You're asking Orita to find the right provider and the right slot. Both are variable.
Use solveScheduling for rebooking flows where the patient already has a relationship with a specific provider. Use resolveScheduling for new patient onboarding, intake flows, or any case where provider selection is part of the scheduling decision.
Before/After: A Real Comparison
Before (manual matching against a calendar API):
// ~25 lines, sequential, fragile, yours to maintain
const providers = await externalApi.listProviders({ specialty: "therapy" });
const spanish = providers.filter(p => p.languages.includes("es"));
const videoOnly = spanish.filter(p => p.modalities.includes("video"));
let best = null;
for (const date of next14Days()) {
for (const p of videoOnly) {
const avail = await externalApi.getAvailability(p.id, date);
if (avail.length && !best) {
best = { provider: p, date, slot: avail[0] };
}
}
if (best) break;
}
if (!best) throw new Error("No availability found");
await externalApi.createBooking({
providerId: best.provider.id,
date: best.date,
time: best.slot.startTime
});
After (with resolveScheduling):
// 15 lines total, including the booking
const { options } = await orita.resolveScheduling({
service: "therapy-session",
constraints: { language: "es", modality: "video" },
dateRange: { start: today(), end: in14Days() },
preference: "earliest"
});
if (options.length === 0) {
return { error: "No availability matching your requirements" };
}
await orita.book({ slotId: options[0].slotId });
The logic didn't get simpler because we wrote less code. It got simpler because the decision — who to book and when — moved to the right layer.
Summary
resolveScheduling is infrastructure, not convenience. It's the answer to "which provider should I book?" — a question that every scheduling product has to answer, and that most teams answer badly by hand.
If your platform matches patients to providers based on any combination of language, specialty, modality, or profession, resolveScheduling should be your first call in the booking flow.
The slotId it returns goes directly into book(). No extra lookup, no race conditions. That's the next piece — and we cover it in Why slotId Prevents Double-Bookings.
