How a Multi-Provider Scheduling API Works
A multi-provider scheduling API searches across many professionals simultaneously β applying eligibility filters, checking real-time availability, and returning ranked options β in a single API call. The caller provides what the customer needs; the API figures out who can handle it and when they are available. This is the essential difference between scheduling infrastructure built for one professional and infrastructure built for a network.
Two Fundamentally Different Scheduling Paths
When you are building scheduling into an application, you will encounter two distinct scenarios. They look similar on the surface β both result in a booked appointment β but they require different infrastructure.
Path 1 β Known Provider
You already know which professional should handle the request. You check their calendar and book a slot.
import Orita from "orita-sdk";
const orita = new Orita({ platformKey: process.env.ORITA_PLATFORM_KEY });
// You know the provider (e.g., the user selected them from a profile)
const { slots } = await orita.getSlots(eventTypeId, date, providerId);
// Book directly
const booking = await orita.book({
slotId: slots[0].slotId,
customer: {
name: "Laura MΓ©ndez",
email: "laura@example.com",
timezone: "Europe/Madrid",
},
});
This path uses POST /api/v1/bookings and requires exactly two inputs: a slot you already identified, and a customer to attach to it. It is fast, simple, and correct β when you know the provider.
Path 2 β Unknown Provider (Multi-Provider Resolution)
You know what the customer needs but not who should handle it. You need to search the network.
// You don't know which provider. The customer gave you a need, not a name.
const resolution = await orita.resolveScheduling({
constraints: {
specialtyCodes: { anyOf: ["CBT", "DBT"] },
languageCodes: { anyOf: ["es"] },
modalityCodes: { anyOf: ["virtual"] },
acceptingNewClients: true,
},
dateRange: {
start: "2026-08-04T00:00:00Z",
end: "2026-08-08T23:59:59Z",
},
timezone: "America/New_York",
idempotencyKey: "intake-xyz789",
});
// Hold the best option while the customer reviews (prevents concurrent bookings)
await orita.holdOption(
resolution.resolutionId,
resolution.options[0].optionId,
{ ttlSeconds: 300 }
);
// Confirm once the customer selects
const booking = await orita.confirmResolution(resolution.resolutionId, {
optionId: resolution.options[0].optionId,
customer: {
name: "Carlos Reyes",
email: "carlos@example.com",
timezone: "America/New_York",
},
});
This path is multi-step by design. Resolution β Hold β Confirmation is the atomic pattern that prevents double-bookings when multiple customers are being matched to the same pool of providers concurrently.
What Happens Inside a Multi-Provider Resolution
When you call POST /api/v1/resolutions, the API executes in parallel across your provider network:
POST /api/v1/resolutions
Authorization: Bearer <platform-key>
Idempotency-Key: intake-xyz789
Content-Type: application/json
{
"constraints": {
"specialtyCodes": { "anyOf": ["CBT", "DBT"] },
"languageCodes": { "anyOf": ["es"] },
"modalityCodes": { "anyOf": ["virtual"] },
"acceptingNewClients": true
},
"dateRange": {
"start": "2026-08-04T00:00:00Z",
"end": "2026-08-08T23:59:59Z"
},
"timezone": "America/New_York"
}
Response:
{
"resolutionId": "res_01j2k3m4n5p6q7r8",
"status": "resolved",
"summary": {
"providersScanned": 200,
"eligibleProviders": 12,
"exclusionReasons": {
"missingSpecialty": 142,
"languageNotMatched": 31,
"notAcceptingClients": 9,
"noAvailability": 6
}
},
"options": [
{
"optionId": "opt_aabbcc112233",
"slotId": "slot_xxyyzz445566",
"provider": {
"providerId": "prov_88ff99ee00dd",
"name": "Dr. Marina Vidal",
"specialties": ["CBT", "trauma-focused"],
"languages": ["es", "en"],
"modalities": ["virtual"]
},
"slot": {
"start": "2026-08-05T14:00:00Z",
"end": "2026-08-05T15:00:00Z",
"timezone": "America/New_York"
},
"score": 0.94,
"reason": "Matches all constraints. CBT specialty confirmed. Spanish primary language.",
"matchedConstraints": ["specialtyCodes", "languageCodes", "modalityCodes", "acceptingNewClients"]
},
{
"optionId": "opt_ddeeff334455",
"slotId": "slot_aabbcc778899",
"provider": {
"providerId": "prov_11aa22bb33cc",
"name": "James Ortega, LCSW",
"specialties": ["DBT", "trauma-focused"],
"languages": ["en", "es"],
"modalities": ["virtual"]
},
"slot": {
"start": "2026-08-06T10:00:00Z",
"end": "2026-08-06T11:00:00Z",
"timezone": "America/New_York"
},
"score": 0.87,
"reason": "Matches all constraints. DBT specialty confirmed. Spanish available.",
"matchedConstraints": ["specialtyCodes", "languageCodes", "modalityCodes", "acceptingNewClients"]
}
]
}
Reading the Exclusion Summary
The summary.exclusionReasons field is not decorative. It tells you exactly why providers were excluded at each stage of the pipeline:
| Exclusion reason | Meaning |
|---|---|
| missingSpecialty | Provider does not have any of the requested specialty codes |
| languageNotMatched | Provider does not speak any of the requested languages |
| notAcceptingClients | Provider is marked as not accepting new clients |
| noAvailability | Provider passed all filters but has no open slots in the requested window |
In the example above: 200 providers were scanned, 142 were excluded for missing specialty, 31 for language, 9 for not accepting clients, and 6 passed all eligibility checks but had no available slots that week. 12 providers returned options.
This breakdown is useful for building transparent user-facing messages ("We searched 200 therapists and found 12 matches") and for debugging eligibility configuration when expected providers are not appearing.
Why You Need Multi-Provider for Real Networks
Consider the operational reality of a mental health platform:
- 200 licensed therapists across multiple specialties (CBT, DBT, EMDR, trauma-focused, couples, adolescent)
- 6 language groups spoken by clients
- 3 modalities (in-person, virtual, phone)
- Insurance acceptance varies by provider and state
- Provider capacity changes daily as they accept or close their books
If a customer requests a Spanish-speaking CBT therapist for virtual sessions next week, you cannot ask the customer to scroll through 200 profiles. You cannot query every provider's calendar sequentially β that would be too slow and would not apply eligibility logic. You need to search, filter, and rank in a single operation.
That is multi-provider scheduling.
The Hold β Confirm Pattern
When multiple customers are being matched concurrently, holds are critical. Without them, two customers could select the same slot and one would fail at booking time with no warning.
POST /api/v1/resolutions/res_01j2k3m4n5p6q7r8/options/opt_aabbcc112233/hold
Authorization: Bearer <platform-key>
Content-Type: application/json
{
"ttlSeconds": 300
}
The hold reserves the slot for 5 minutes. If the customer does not confirm within that window, the hold expires and the slot becomes available again. If the customer confirms, the hold is atomically converted to a confirmed booking.
POST /api/v1/resolutions/res_01j2k3m4n5p6q7r8/confirm
Authorization: Bearer <platform-key>
Content-Type: application/json
{
"optionId": "opt_aabbcc112233",
"customer": {
"name": "Carlos Reyes",
"email": "carlos@example.com",
"timezone": "America/New_York"
}
}
When Orita Is the Right Solution
- Your platform has multiple providers and customers need to be matched to the right one
- Eligibility logic spans attributes like specialty, language, modality, or insurance
- You need to prevent double-bookings in concurrent intake flows
- You want per-option explanation ("why this provider") in the API response
- Your AI assistant or intake workflow handles scheduling as part of a larger decision
When Orita Is Not the Right Solution
- Single provider or tiny fixed team: If you schedule for one person or a team of three, the resolution layer is unnecessary. Use
POST /api/v1/bookingsdirectly, or a simpler tool like Cal.com. - No constraint matching: If every provider in your network can serve every request equally, there is nothing to resolve. Any slot API works.
- Pre-selected provider: If your UI already shows provider profiles and the user selects one before scheduling, skip resolution and book directly.
- Simple consumer scheduling: If customers are booking time with a single known professional (a hairdresser, a personal trainer they already chose), a standard scheduling widget is a better fit.
Next Steps
- What Is a Provider Resolution API? β the foundational concept
- Known-Host Scheduling vs. Provider Resolution β choosing the right model
- Why AI Applications Need Provider-Aware Scheduling β AI + resolution
- Try it live in the interactive demo
