The scheduling infrastructure for AI agents — Python SDK
Project description
orita-python
The scheduling infrastructure for AI agents — Python SDK
Orita is the scheduling layer purpose-built for AI agents. Connect your LLM to real calendar availability in minutes.
→ Docs & API keys: orita.online/developers
Installation
pip install orita-sdk
Quickstart
from orita import OritaClient
client = OritaClient(api_key="orita_your_key_here")
slots = client.slots(event_type_id="evt_abc123", date="2026-08-01")
booking = client.book(
event_type_id="evt_abc123", date="2026-08-01", time=slots[0]["value"],
client_name="Ana", client_lastname="López", client_email="ana@example.com",
)
print(booking["id"]) # book_xyz789
Authentication
All requests require an API key obtained from orita.online/developers.
from orita import OritaClient
client = OritaClient(api_key="orita_your_key_here")
API keys must start with orita_. Pass a custom base_url to point to a self-hosted or staging instance.
API Reference
client.professionals(language, modality, specialty, profession, location) → list
List professionals on the platform, with optional filters.
| Parameter | Type | Description |
|---|---|---|
language |
str |
Filter by spoken language (e.g. "es", "en") |
modality |
str |
Filter by service modality (e.g. "online", "presencial") (new in v0.2) |
specialty |
str |
Filter by specialty (e.g. "fisioterapia") |
profession |
str |
Filter by profession |
location |
str |
Filter by location |
professionals = client.professionals(language="es", modality="online")
for pro in professionals:
print(pro["id"], pro["name"])
client.slots(event_type_id, date, provider_id) → list
Get available time slots for a given event type on a specific date. Each slot includes a slotId field you can pass directly to book().
| Parameter | Type | Description |
|---|---|---|
event_type_id |
str |
Event type ID from event_types() |
date |
str |
Date in YYYY-MM-DD format |
provider_id |
str |
(Optional) Platform provider ID |
slots = client.slots(event_type_id="evt_abc123", date="2026-08-01")
# [{"label": "09:00 AM", "value": "09:00", "slotId": "slot_a1b2"}, ...]
client.book(...) → dict
Book an appointment. Returns the created booking object. All fields are keyword-optional; supply either classic date/time/client_* fields, or pass slot_id + customer dict.
| Parameter | Type | Description |
|---|---|---|
event_type_id |
str |
Event type ID |
date |
str |
Date in YYYY-MM-DD |
time |
str |
Time in HH:MM 24h |
client_name |
str |
Client first name |
client_lastname |
str |
Client last name |
client_email |
str |
Client email |
provider_id |
str |
Platform provider ID |
slot_id |
str |
Slot ID from slots() or solve_scheduling() (new in v0.2) |
customer |
dict |
Dict with keys name, lastname, email, optionally timezone (new in v0.2) |
notes |
str |
Additional notes for the professional |
# Classic booking
booking = client.book(
event_type_id="evt_abc123",
date="2026-08-01",
time="10:00",
client_name="Carlos",
client_lastname="García",
client_email="carlos@example.com",
notes="First appointment — prefers video call",
)
# Slot-first booking (using slotId from slots())
booking = client.book(
event_type_id="evt_abc123",
slot_id="slot_a1b2",
customer={"name": "Ana", "lastname": "López", "email": "ana@example.com"},
)
# {"id": "book_xyz789", "status": "confirmed", "date": "2026-08-01", ...}
client.bookings(page, limit, status, provider_id) → list
List bookings with optional filtering.
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int |
1 |
Page number |
limit |
int |
20 |
Results per page |
status |
str |
None |
Filter: pending, confirmed, cancelled, completed |
provider_id |
str |
None |
Scope to a platform provider |
confirmed = client.bookings(status="confirmed")
all_bookings = client.bookings(page=2, limit=50)
client.get_booking(booking_id) → dict
Retrieve a single booking by ID.
booking = client.get_booking("book_xyz789")
print(booking["status"]) # "confirmed"
client.cancel(booking_id) → dict
Cancel a booking by ID.
result = client.cancel("book_xyz789")
print(result["status"]) # "cancelled"
client.reschedule(booking_id, date, time) → dict (new in v0.2)
Reschedule an existing booking to a new date and time.
| Parameter | Type | Description |
|---|---|---|
booking_id |
str |
Booking ID to reschedule |
date |
str |
New date in YYYY-MM-DD format |
time |
str |
New time in HH:MM 24h format |
result = client.reschedule("bk_18382", date="2026-08-05", time="10:00")
print(result["date"]) # "2026-08-05"
client.complete(booking_id) → dict (new in v0.2)
Mark a booking as completed.
result = client.complete("book_xyz789")
print(result["status"]) # "completed"
client.solve_scheduling(event_type_id, date_range_from, date_range_to, provider_id, preference) → dict (new in v0.2)
Find the best available slot across a date range (AI-agent optimized). Returns a recommendation with alternatives.
| Parameter | Type | Description |
|---|---|---|
event_type_id |
str |
Event type to schedule |
date_range_from |
str |
Start date in YYYY-MM-DD |
date_range_to |
str |
End date in YYYY-MM-DD |
provider_id |
str |
(Optional) Platform provider ID |
preference |
str |
(Optional) "morning", "afternoon", or "evening" |
result = client.solve_scheduling(
event_type_id="evt_abc123",
date_range_from="2026-08-01",
date_range_to="2026-08-07",
preference="morning",
)
# {"recommended": {...}, "alternatives": [...], "totalAvailableSlots": 12, "reason": "..."}
client.resolve_scheduling(date_range_from, date_range_to, constraints, service, preference, organization_id) → list (new in v0.2, platform key only)
Resolve the best available providers and slots for a scheduling request when you don't yet know a specific provider or event type.
| Parameter | Type | Description |
|---|---|---|
date_range_from |
str |
Start date in YYYY-MM-DD |
date_range_to |
str |
End date in YYYY-MM-DD |
constraints |
dict |
(Optional) Keys: language, modality, specialty, profession |
service |
str |
(Optional) Event type title or slug to narrow results |
preference |
str |
(Optional) "morning", "afternoon", or "evening" |
organization_id |
str |
(Optional) Organization ID |
options = client.resolve_scheduling(
date_range_from="2026-08-01",
date_range_to="2026-08-07",
constraints={"language": "es", "modality": "online"},
preference="morning",
)
# [{"providerId": "...", "providerName": "...", "eventTypeId": "...", "slotId": "...",
# "date": "2026-08-02", "time": "10:00", "label": "...", "modality": "online", "reason": "..."}, ...]
client.event_types(provider_id) → list
List all active event types for your account (or a platform provider).
event_types = client.event_types()
# [{"id": "evt_abc123", "title": "Initial Consultation", "duration": 30, ...}]
client.create_event_type(...) → dict
Create a new event type. See Platform Accounts for full parameter list.
event_type = client.create_event_type(
title="Consulta inicial",
duration=30,
location="Online",
provider_id="pro_abc123",
)
print(event_type["id"]) # evt_new456
client.profile() → dict
Get your own Capability Manifest — the machine-readable description of your scheduling configuration that AI agents can read to understand how to book you.
manifest = client.profile()
print(manifest["username"])
print(manifest["eventTypes"])
client.update_profile(**fields) → dict
Update your profile fields.
updated = client.update_profile(bio="AI-native therapist", timezone="Europe/Madrid")
client.get_profile(username) → dict
Fetch the public Capability Manifest for any professional by username. No API key required internally — useful for cross-professional lookups.
manifest = client.get_profile("dra-martinez")
# {"username": "dra-martinez", "eventTypes": [...], ...}
Platform Accounts
If you are building a scheduling platform that hosts multiple professionals, use the provider_id parameter to scope API calls to a specific provider on your account.
List professionals
# List all professionals on your platform
professionals = client.professionals()
# Filter by specialty, language, modality, or location
pros = client.professionals(specialty="fisioterapia", language="es", modality="online")
for pro in pros:
print(pro["id"], pro["name"])
Create an event type for a provider
event_type = client.create_event_type(
title="Consulta inicial",
duration=30,
location="Online",
description="Primera visita con el profesional",
provider_id="pro_abc123",
buffer_time=15,
)
print(event_type["id"]) # evt_new456
Scope bookings to a specific provider
# Get event types for a specific provider
event_types = client.event_types(provider_id="pro_abc123")
# Get slots for a provider's event type
slots = client.slots(
event_type_id="evt_new456",
date="2026-08-01",
provider_id="pro_abc123",
)
# Book under a specific provider
booking = client.book(
event_type_id="evt_new456",
date="2026-08-01",
time=slots[0]["value"],
client_name="María",
client_lastname="Torres",
client_email="maria@example.com",
provider_id="pro_abc123",
)
print(booking["id"]) # book_xyz789
# List bookings for a provider
provider_bookings = client.bookings(provider_id="pro_abc123")
Full platform flow example
from orita import OritaClient
from datetime import date, timedelta
client = OritaClient(api_key="orita_your_platform_key")
# 1. List all professionals on the platform
professionals = client.professionals(specialty="psicología")
provider_id = professionals[0]["id"]
# 2. Create an event type for this provider
event_type = client.create_event_type(
title="Consulta psicológica",
duration=50,
location="Online",
provider_id=provider_id,
)
# 3. Get available slots for tomorrow
tomorrow = (date.today() + timedelta(days=1)).isoformat()
slots = client.slots(
event_type_id=event_type["id"],
date=tomorrow,
provider_id=provider_id,
)
# 4. Book with the provider
if slots:
booking = client.book(
event_type_id=event_type["id"],
date=tomorrow,
time=slots[0]["value"],
client_name="Juan",
client_lastname="Pérez",
client_email="juan@example.com",
provider_id=provider_id,
)
print(f"✅ Booked with provider {provider_id}: {booking['id']}")
Error Handling
from orita import OritaClient
from orita import OritaAuthError, OritaNotFoundError, OritaSlotUnavailableError, OritaError
client = OritaClient(api_key="orita_your_key")
try:
booking = client.book(
event_type_id="evt_abc123",
date="2026-08-01",
time="10:00",
client_name="Ana",
client_lastname="López",
client_email="ana@example.com",
)
except OritaAuthError:
print("Invalid API key")
except OritaSlotUnavailableError:
print("That slot was just taken — fetch slots again")
except OritaNotFoundError:
print("Event type not found")
except OritaError as e:
print(f"API error: {e}")
| Exception | HTTP Status | When |
|---|---|---|
OritaAuthError |
401 | Invalid or missing API key |
OritaNotFoundError |
404 | Resource not found |
OritaSlotUnavailableError |
409 | Slot already taken |
OritaError |
Other 4xx/5xx | Generic API error |
Framework Integrations
OpenAI Agents SDK
Give your OpenAI agent the ability to book appointments in real time:
from openai import OpenAI
from orita import OritaClient
import json
orita = OritaClient(api_key="orita_your_key")
client = OpenAI()
tools = [
{
"type": "function",
"function": {
"name": "get_available_slots",
"description": "Get available appointment slots for a given date",
"parameters": {
"type": "object",
"properties": {
"event_type_id": {"type": "string"},
"date": {"type": "string", "description": "YYYY-MM-DD"},
},
"required": ["event_type_id", "date"],
},
},
},
]
def handle_tool_call(name, args):
if name == "get_available_slots":
return json.dumps(orita.slots(args["event_type_id"], args["date"]))
→ Full example: examples/openai_agent.py
LangChain
Wrap Orita methods as LangChain @tool functions:
from langchain.tools import tool
from orita import OritaClient
orita = OritaClient(api_key="orita_your_key")
@tool
def get_available_slots(date_str: str) -> str:
"""Get available appointment slots for a date (YYYY-MM-DD)."""
slots = orita.slots(event_type_id="evt_abc123", date=date_str)
return "\n".join([f"- {s['label']}" for s in slots])
@tool
def book_appointment(date_str: str, time_str: str, name: str, lastname: str, email: str) -> str:
"""Book an appointment for a client."""
booking = orita.book(
event_type_id="evt_abc123", date=date_str, time=time_str,
client_name=name, client_lastname=lastname, client_email=email,
)
return f"Confirmed! Booking ID: {booking['id']}"
→ Full example: examples/langchain_tool.py
LangGraph
Build a full scheduling agent as a LangGraph StateGraph — with nodes for understanding the request, querying availability, and confirming the booking:
from langgraph.graph import END, StateGraph
from langgraph.graph.message import add_messages
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from orita import OritaClient
from typing import Annotated, TypedDict
import json, os
orita = OritaClient(api_key=os.environ["ORITA_API_KEY"])
@tool
def check_slots(event_type_id: str, date_str: str) -> str:
"""Get available appointment slots for a given date (YYYY-MM-DD)."""
slots = orita.slots(event_type_id=event_type_id, date=date_str)
return json.dumps({"slots": [{"label": s["label"], "value": s["value"]} for s in slots]})
@tool
def confirm_booking(event_type_id: str, date_str: str, time_str: str,
client_name: str, client_lastname: str, client_email: str) -> str:
"""Confirm and create an appointment booking."""
booking = orita.book(
event_type_id=event_type_id, date=date_str, time=time_str,
client_name=client_name, client_lastname=client_lastname, client_email=client_email,
)
return json.dumps({"booking_id": booking["id"], "status": booking["status"]})
class AgentState(TypedDict):
messages: Annotated[list, add_messages]
orita_tools = [check_slots, confirm_booking]
tool_map = {t.name: t for t in orita_tools}
llm = ChatOpenAI(model="gpt-4o", temperature=0).bind_tools(orita_tools)
def understand_and_plan(state):
from langchain_core.messages import SystemMessage
messages = [SystemMessage(content="You are a scheduling assistant. Use tools to check slots and book appointments.")]
return {"messages": [llm.invoke(messages + state["messages"])]}
def execute_tool(state):
from langchain_core.messages import ToolMessage
last = state["messages"][-1]
results = []
for call in last.tool_calls:
result = tool_map[call["name"]].invoke(call["args"])
results.append(ToolMessage(content=result, tool_call_id=call["id"], name=call["name"]))
return {"messages": results}
def should_continue(state):
last = state["messages"][-1]
return "execute_tool" if getattr(last, "tool_calls", None) else END
graph = StateGraph(AgentState)
graph.add_node("understand", understand_and_plan)
graph.add_node("execute_tool", execute_tool)
graph.set_entry_point("understand")
graph.add_conditional_edges("understand", should_continue, {"execute_tool": "execute_tool", END: END})
graph.add_edge("execute_tool", "understand")
app = graph.compile()
# Run
from langchain_core.messages import HumanMessage
result = app.invoke({"messages": [HumanMessage(
content="Book me a slot next Monday at 10am. I'm Ana López, ana@example.com"
)]})
print(result["messages"][-1].content)
→ Full example with find_providers, retry logic, and multi-turn support: examples/langgraph_orita.py
CrewAI
from crewai.tools import tool
from orita import OritaClient
orita = OritaClient(api_key="orita_your_key")
@tool("Get Available Slots")
def get_slots(event_type_id: str, date: str) -> str:
"""Get available appointment slots. Input: event_type_id and date (YYYY-MM-DD)."""
slots = orita.slots(event_type_id=event_type_id, date=date)
return str([{"label": s["label"], "value": s["value"]} for s in slots])
@tool("Book Appointment")
def book(event_type_id: str, date: str, time: str,
client_name: str, client_lastname: str, client_email: str) -> str:
"""Book an appointment for a client."""
booking = orita.book(
event_type_id=event_type_id, date=date, time=time,
client_name=client_name, client_lastname=client_lastname, client_email=client_email,
)
return f"Booking {booking['id']} confirmed for {date} at {time}"
Full Example: Book from Available Slots
from orita import OritaClient
from datetime import date, timedelta
client = OritaClient(api_key="orita_your_key_here")
# 1. Get event types
event_types = client.event_types()
event_type_id = event_types[0]["id"]
# 2. Get tomorrow's slots
tomorrow = (date.today() + timedelta(days=1)).isoformat()
slots = client.slots(event_type_id=event_type_id, date=tomorrow)
# 3. Book the first available
if slots:
booking = client.book(
event_type_id=event_type_id,
date=tomorrow,
time=slots[0]["value"],
client_name="Juan",
client_lastname="García",
client_email="juan@example.com",
)
print(f"✅ Booked: {booking['id']}")
else:
print("No availability tomorrow")
Requirements
- Python 3.8+
requests >= 2.28
Node.js / TypeScript
Looking for the JavaScript / TypeScript SDK?
npm install orita-sdk
import { OritaClient } from 'orita-sdk';
const orita = new OritaClient({ apiKey: process.env.ORITA_API_KEY });
const { slots } = await orita.getSlots('evt_abc123', '2026-08-01');
const booking = await orita.book({
eventTypeId: 'evt_abc123', date: '2026-08-01', time: slots[0].value,
clientName: 'Ana', clientLastname: 'López', clientEmail: 'ana@example.com',
});
→ npm: npmjs.com/package/orita-sdk
→ GitHub: github.com/Alkilo-do/orita-node
Links
- 🌐 Website: orita.online
- 📚 Developer docs: orita.online/developers
- 🟨 Node.js / TypeScript SDK: github.com/Alkilo-do/orita-node —
npm install orita-sdk - 🐛 Issues: github.com/Alkilo-do/orita-python/issues
License
MIT © Alkilo-do
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file orita_sdk-0.2.0.tar.gz.
File metadata
- Download URL: orita_sdk-0.2.0.tar.gz
- Upload date:
- Size: 14.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
526b1e93317f5b5831a3e495b13a7bc62cb440864cb64d334773e10018ea99c5
|
|
| MD5 |
465df5ef963a7e5dc7d21028509335e4
|
|
| BLAKE2b-256 |
e6aae985de86688dc2bdccdaa1bf5d1432185d5a8e9febc4f0033ae3a0c9562b
|
File details
Details for the file orita_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: orita_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6da2222a9469f716e3ddda854e2ea386b9bc334758b088661de50111953a91cd
|
|
| MD5 |
76b5a73ec2b06f245f9660b5309337d2
|
|
| BLAKE2b-256 |
621c491ce0e360e26c06f40111a0db66fcea69e96b11440c3311f63fc2c01f83
|