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.get_resolution(resolution_id) → dict (new in v0.3)

Retrieve a stored resolution by ID, including all ranked options and scores.

Parameter Type Description
resolution_id str Resolution ID returned by resolve_scheduling()
resolution = client.get_resolution("a1b2c3d4-...")
print(resolution['status'])         # "pending"
print(resolution['options'][0]['reason'])  # AI-generated explanation

client.hold_option(resolution_id, option_id, ttl_seconds) → dict (new in v0.3)

Temporarily hold a resolution option to prevent others from booking it while the user confirms.

Parameter Type Default Description
resolution_id str Resolution ID from resolve_scheduling()
option_id str Option ID to hold (from resolution options list)
ttl_seconds int 120 Hold duration in seconds (max 600)
hold = client.hold_option(
    resolution_id="a1b2c3d4-...",
    option_id="opt_xyz",
    ttl_seconds=180,
)
print(hold['holdId'])     # "hold_abc"
print(hold['expiresAt'])  # "2026-08-01T10:03:00Z"

client.release_option(resolution_id, option_id) → dict (new in v0.3)

Release a previously held resolution option (e.g. if the user chose a different slot).

Parameter Type Description
resolution_id str Resolution ID
option_id str Option ID of the hold to release
result = client.release_option(
    resolution_id="a1b2c3d4-...",
    option_id="opt_xyz",
)
print(result['status'])  # "released"

client.confirm_resolution(resolution_id, option_id, customer_name, customer_email, ...) → dict (new in v0.3)

Confirm a resolution option and atomically create a booking. This is the final step in the resolve_scheduling → confirm flow.

Parameter Type Default Description
resolution_id str Resolution ID from resolve_scheduling()
option_id str Option ID to confirm (from resolution options)
customer_name str Customer full name
customer_email str Customer email address
customer_lastname str "-" Customer last name
metadata dict None Optional metadata (e.g. {'source': 'ai_assistant'})
idempotency_key str None Optional key for safe retries
booking = client.confirm_resolution(
    resolution_id=options[0]['resolutionId'],
    option_id=options[0]['optionId'],
    customer_name="James Park",
    customer_email="james@email.com",
    customer_lastname="Park",
    metadata={"source": "ai_assistant"},
    idempotency_key="unique-request-id-123",
)
print(booking['data']['id'])      # "book_xyz789"
print(booking['data']['status'])  # "confirmed"

Full resolution flow example

from orita import OritaClient

client = OritaClient(api_key="orita_your_platform_key")

# 1. Resolve: find the best providers and slots
options = client.resolve_scheduling(
    date_range_from="2026-08-01",
    date_range_to="2026-08-07",
    constraints={"language": "es", "modality": "online"},
)

# 2. Inspect the full resolution with scores
resolution_id = options[0].get('resolutionId')
if resolution_id:
    resolution = client.get_resolution(resolution_id)
    top_option = resolution['options'][0]

    # 3. Hold the top option while user confirms
    hold = client.hold_option(
        resolution_id=resolution_id,
        option_id=top_option['optionId'],
        ttl_seconds=180,
    )
    print(f"Held until {hold['expiresAt']}")

    # 4. Confirm and create the booking
    booking = client.confirm_resolution(
        resolution_id=resolution_id,
        option_id=top_option['optionId'],
        customer_name="Ana López",
        customer_email="ana@example.com",
    )
    print(f"✅ Booked: {booking['data']['id']}")

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.3.0.tar.gz (17.4 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.3.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file orita_sdk-0.3.0.tar.gz.

File metadata

  • Download URL: orita_sdk-0.3.0.tar.gz
  • Upload date:
  • Size: 17.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for orita_sdk-0.3.0.tar.gz
Algorithm Hash digest
SHA256 13d2efbdd9aa323e9617c8a786c2bce71ccd3d46edd66bd4f565e74883c44fe9
MD5 5e087f7e3296ff4e56dabaa9f083d589
BLAKE2b-256 34a81b34a2ad56d0811cbc3f8ef6e914fb60ad1e200e5d6cba3bc6ddb3ae8c7f

See more details on using hashes here.

File details

Details for the file orita_sdk-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: orita_sdk-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for orita_sdk-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17168e8828f813e2fa0caebd7aa049c69fd64815ef4966c9374d5fd630465821
MD5 92bceed573bd0e4f55991804bf5662d8
BLAKE2b-256 7b2e0b15c1310034cfcc989a236412a5a9dcbbb16b121168007114b7cb346cb5

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