Skip to main content

The scheduling infrastructure for AI agents — Python SDK

Project description

orita-python

PyPI version Python 3.8+ License: MIT

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


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

orita_sdk-0.2.0.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

orita_sdk-0.2.0-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

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

Hashes for orita_sdk-0.2.0.tar.gz
Algorithm Hash digest
SHA256 526b1e93317f5b5831a3e495b13a7bc62cb440864cb64d334773e10018ea99c5
MD5 465df5ef963a7e5dc7d21028509335e4
BLAKE2b-256 e6aae985de86688dc2bdccdaa1bf5d1432185d5a8e9febc4f0033ae3a0c9562b

See more details on using hashes here.

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

Hashes for orita_sdk-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6da2222a9469f716e3ddda854e2ea386b9bc334758b088661de50111953a91cd
MD5 76b5a73ec2b06f245f9660b5309337d2
BLAKE2b-256 621c491ce0e360e26c06f40111a0db66fcea69e96b11440c3311f63fc2c01f83

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page