When an AI application books a therapist, assigns a specialist, or routes a patient to a provider, the application is making a consequential decision on behalf of a real person.
That decision needs to be explainable.
Not just auditable after the fact — but explainable in real time, to the user, in plain language, so they can trust what's happening or correct it before the booking is confirmed.
Orita's resolution engine is designed with this constraint in mind. Every option returned by a resolution includes structured reasoning: which constraints were matched, which ranking factors contributed to the score, and a human-readable explanation of why this option was selected.
Why Explanations Matter for AI Applications
User trust
An AI agent that says "I found Dr. Ana García for your Thursday afternoon session" is less trustworthy than one that says "I found Dr. García because she speaks Spanish, offers video sessions, and has an afternoon slot on Thursday — which matches your preferences."
The second version gives the user something to verify and agree with. The first requires blind trust.
Audit trails
In regulated industries — healthcare, legal services, financial advisory — you may be required to explain why a specific provider was selected for a specific client. Orita's reasonCodes and matchedConstraints can be stored alongside the booking record to satisfy audit requirements.
AI agent debugging
When an AI agent selects an unexpected provider, or no providers are returned at all, you need to understand why. Structured reason codes are machine-readable — your application logic can inspect them, log them, and route to fallback behavior based on them.
The Full Resolution Response
Here's what a complete resolution response looks like, including the ranking and reasoning fields:
{
"resolutionId": "res_4k8m2p",
"resolvedAt": "2026-07-29T14:23:01Z",
"options": [
{
"optionId": "opt_7x2c",
"providerId": "prov_9a21b",
"score": 94,
"slot": {
"start": "2026-08-06T15:00:00Z",
"end": "2026-08-06T16:00:00Z"
},
"matchedConstraints": [
"service_supported",
"language_matched",
"modality_supported",
"accepts_new_clients"
],
"rankingFactors": [
{ "code": "PREFERRED_DAYPART", "points": 15 },
{ "code": "EARLIEST_VALID_OPTION", "points": 30 },
{ "code": "CONTINUITY_PROVIDER", "points": 20 }
],
"reason": "Matches all required conditions and is the earliest available afternoon appointment.",
"reasonCodes": [
"ALL_REQUIRED_RULES_PASSED",
"PREFERRED_DAYPART",
"EARLIEST_ELIGIBLE_OPTION"
]
}
],
"exclusions": {
"MODALITY_NOT_SUPPORTED": 8,
"LANGUAGE_NOT_SUPPORTED": 6,
"NO_AVAILABLE_SLOTS": 22,
"NOT_ACCEPTING_NEW_CLIENTS": 4
}
}
Understanding Each Field
matchedConstraints
A list of constraint codes that this option satisfied. These are the eligibility conditions — every option in the response has passed all of them.
"matchedConstraints": [
"service_supported",
"language_matched",
"modality_supported",
"accepts_new_clients"
]
If any constraint were not met, the option wouldn't appear at all — it would appear in the exclusions summary instead.
rankingFactors
A list of preference signals and their point contribution to the score. These explain why this option ranked where it did among all qualifying options.
"rankingFactors": [
{ "code": "PREFERRED_DAYPART", "points": 15 },
{ "code": "EARLIEST_VALID_OPTION", "points": 30 },
{ "code": "CONTINUITY_PROVIDER", "points": 20 }
]
The score field (0–100) is derived from these factor points normalized across the candidate set. An option with a score of 94 matched constraints and ranked highly on multiple preferences.
reason
A human-readable string explaining why this option was selected. This field is designed to be shown directly to users or included in agent responses.
"reason": "Matches all required conditions and is the earliest available afternoon appointment."
reasonCodes
Machine-readable codes that correspond to the human-readable reason. These are the codes your application logic should use for routing, logging, and fallback decisions.
"reasonCodes": [
"ALL_REQUIRED_RULES_PASSED",
"PREFERRED_DAYPART",
"EARLIEST_ELIGIBLE_OPTION"
]
exclusions
The summary of providers that were evaluated but excluded, and why:
"exclusions": {
"MODALITY_NOT_SUPPORTED": 8,
"LANGUAGE_NOT_SUPPORTED": 6,
"NO_AVAILABLE_SLOTS": 22,
"NOT_ACCEPTING_NEW_CLIENTS": 4
}
This tells you how many providers existed in the search pool, why they were excluded, and which exclusion reason was most common. If your results are unexpectedly thin, the exclusions summary tells you where to look.
Using Reason Codes in Your AI Application
Reason codes are designed for programmatic consumption. Here's how an AI agent might use them:
import { OritaClient } from "orita-sdk";
const orita = new OritaClient({ apiKey: process.env.ORITA_API_KEY });
const resolution = await orita.resolutions.create({
serviceId: "svc_therapy_60min",
windowStart: "2026-08-04T00:00:00Z",
windowEnd: "2026-08-08T23:59:59Z",
constraints: {
languageCodes: { anyOf: ["es"] },
modalityCodes: { anyOf: ["video"] },
acceptsNewClients: true,
},
preferences: {
dayParts: ["afternoon"],
continuityProviderId: "prov_9a21b",
},
});
if (resolution.options.length === 0) {
const { exclusions } = resolution;
// Differentiate between supply problems and data problems
if (exclusions.NO_AVAILABLE_SLOTS > 10) {
return "There are no available slots this week. Try a wider date range.";
}
if (exclusions.LANGUAGE_NOT_SUPPORTED > 5) {
return "No Spanish-speaking providers are available. Contact support to add more.";
}
return "No providers match your criteria right now.";
}
const top = resolution.options[0];
// Show users why this provider was selected
const explanation = buildUserMessage(top);
function buildUserMessage(option) {
const hasContinuity = option.reasonCodes.includes("CONTINUITY_PROVIDER");
const hasAfternoon = option.reasonCodes.includes("PREFERRED_DAYPART");
if (hasContinuity && hasAfternoon) {
return `I found your usual provider with an afternoon slot — ${option.reason}`;
}
if (hasContinuity) {
return `I found your usual provider. ${option.reason}`;
}
return option.reason;
}
console.log(explanation);
// "I found your usual provider with an afternoon slot — Matches all required
// conditions and is the earliest available afternoon appointment."
Python: Logging Reason Codes for Audit
import os
import json
from orita import OritaClient
orita = OritaClient(api_key=os.environ["ORITA_API_KEY"])
def resolve_and_audit(service_id, constraints, preferences, window_start, window_end):
resolution = orita.resolutions.create(
service_id=service_id,
window_start=window_start,
window_end=window_end,
constraints=constraints,
preferences=preferences,
)
audit_record = {
"resolutionId": resolution.resolution_id,
"resolvedAt": resolution.resolved_at,
"optionCount": len(resolution.options),
"exclusions": resolution.exclusions,
}
if resolution.options:
top = resolution.options[0]
audit_record.update({
"selectedOptionId": top.option_id,
"selectedProviderId": top.provider_id,
"score": top.score,
"matchedConstraints": top.matched_constraints,
"rankingFactors": [rf.__dict__ for rf in top.ranking_factors],
"reasonCodes": top.reason_codes,
"reason": top.reason,
})
# Store this record alongside your booking for audit purposes
print(json.dumps(audit_record, indent=2))
return resolution
resolve_and_audit(
service_id="svc_therapy_60min",
window_start="2026-08-04T00:00:00Z",
window_end="2026-08-08T23:59:59Z",
constraints={
"languageCodes": {"anyOf": ["es"]},
"modalityCodes": {"anyOf": ["video"]},
"acceptsNewClients": True,
},
preferences={"dayParts": ["afternoon"]},
)
Reason Codes Reference
| Code | Type | Meaning |
|---|---|---|
| ALL_REQUIRED_RULES_PASSED | Summary | All constraints were satisfied |
| PREFERRED_DAYPART | Ranking | Slot falls in a requested day part |
| EARLIEST_ELIGIBLE_OPTION | Ranking | Chronologically first valid slot |
| CONTINUITY_PROVIDER | Ranking | Provider has seen this client before |
| HIGH_AVAILABILITY_DENSITY | Ranking | Provider has multiple available slots in the window |
Exclusion codes (appear in exclusions only):
| Code | Meaning |
|---|---|
| LANGUAGE_NOT_SUPPORTED | Provider doesn't offer requested languages |
| MODALITY_NOT_SUPPORTED | Provider doesn't support requested modality |
| NOT_ACCEPTING_NEW_CLIENTS | Provider marked as not accepting new clients |
| SPECIALTY_NOT_MATCHED | Provider doesn't list required specialties |
| PROFESSION_MISMATCH | Provider's profession doesn't match constraint |
| NO_AVAILABLE_SLOTS | Provider qualified but had no open slots |
| DATA_MISSING_LANGUAGE | Provider's language data not configured |
| DATA_MISSING_MODALITY | Provider's modality data not configured |
The Broader Point: Transparency as Infrastructure
Explainability isn't a nice-to-have feature you bolt on after your scheduling logic works. It's part of how your application earns and maintains user trust — especially when an AI agent is making consequential decisions.
By returning structured reasoning on every option, Orita makes explainability something you get for free. You don't need to build the logic that explains why Dr. García was selected over Dr. Martinez. The resolution engine does it, and your application surfaces it.
That's the difference between a scheduling API and scheduling infrastructure.
Read the full API reference → · See the resolution engine live →
