# How to Implement a Delayed Scheduled Message Tool

**URL:** <https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158>\
**Category:** Documentation\
**Created:** [January 12, 2026, 7:07pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158 "2026-01-12T19:07:46Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 12, 2026, 7:07pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/1 "2026-01-12T19:07:46Z")

</div>

Scheduling in Letta uses absolute timestamps via the `/v1/agents/{agent_id}/messages/scheduled` endpoint. But agents aren’t great at calculating exact times from relative delays like “in 1 hour.”

This guide shows how to build a custom tool that handles the conversion, letting your agent schedule with simple delay arguments.

## The Problem

The scheduling API requires ISO 8601 timestamps:

```python
client.agents.messages.create_scheduled(
    agent_id=agent_id,
    scheduled_time="2026-01-12T20:00:00Z", # Absolute time required
    messages=[...]
)

```

Agents struggle to calculate “current time + 1 hour” reliably.

## The Solution: A Delay-Based Tool

```python
def schedule_delayed_message(delay_seconds: int, message: str) -> str:
    """
    Schedule a one-time message to be sent after a delay.
    
    Args:
        delay_seconds: Number of seconds to wait before sending
        message: The message content to send to this agent
    
    Returns:
        Confirmation with scheduled time
    """
    import os
    from datetime import datetime, timezone, timedelta
    
    agent_id = os.getenv("LETTA_AGENT_ID")
    
    # Calculate absolute time from delay
    now = datetime.now(timezone.utc)
    scheduled_time = now + timedelta(seconds=delay_seconds)
    scheduled_iso = scheduled_time.isoformat()
    
    # Create the scheduled message
    result = client.agents.messages.create_scheduled(
        agent_id=agent_id,
        scheduled_time=scheduled_iso,
        messages=[{"role": "user", "content": message}]
    )
    
    return f"Scheduled message for {scheduled_iso} (in {delay_seconds} seconds). Job ID: {result.id}"

```

## Usage Examples

Once attached to your agent, it can:

- “Remind me about the meeting in 3600 seconds” (1 hour)
- “Send me a follow-up in 86400 seconds” (24 hours)
- “Check back in 300 seconds” (5 minutes)

## Convenience Wrapper with Units

For friendlier UX, add unit conversion:

```python
def schedule_reminder(delay: int, unit: str, message: str) -> str:
    """
    Schedule a reminder with human-friendly time units.
    
    Args:
        delay: Number of time units to wait
        unit: Time unit - "seconds", "minutes", "hours", or "days"
        message: The reminder message
    
    Returns:
        Confirmation with scheduled time
    """
    import os
    from datetime import datetime, timezone, timedelta
    
    agent_id = os.getenv("LETTA_AGENT_ID")
    
    # Convert to seconds
    multipliers = {
        "seconds": 1,
        "minutes": 60,
        "hours": 3600,
        "days": 86400
    }
    
    if unit not in multipliers:
        return f"Invalid unit '{unit}'. Use: seconds, minutes, hours, or days"
    
    delay_seconds = delay * multipliers[unit]
    
    now = datetime.now(timezone.utc)
    scheduled_time = now + timedelta(seconds=delay_seconds)
    
    result = client.agents.messages.create_scheduled(
        agent_id=agent_id,
        scheduled_time=scheduled_time.isoformat(),
        messages=[{"role": "user", "content": message}]
    )
    
    return f"Reminder set for {delay} {unit} from now ({scheduled_time.isoformat()})"

```

Now the agent can say: “I’ll remind you in 2 hours” and call `schedule_reminder(2, "hours", "Follow up on proposal")`.

## Setup

1. Create the tool via ADE or SDK
2. Attach to your agent
3. Ensure `LETTA_AGENT_ID` is available (automatic on Cloud, add as tool variable on self-hosted)

## Notes

- The `client` variable is pre-injected on Letta Cloud
- For self-hosted, you’ll need to instantiate the client inside the tool
- Scheduled messages are one-time by default; for recurring, see the cron\_expression parameter in the docs

Docs reference: [Scheduling messages | Letta Docs](https://docs.letta.com/guides/agents/scheduling/)

---

<div class="post-metadata">

**Author:** ![wesseljt](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/wesseljt/32/102_2.png) [@wesseljt](https://forum.letta.com/u/wesseljt)\
**Post date:** [January 14, 2026, 7:34pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/2 "2026-01-14T19:34:14Z")

</div>

@ezra this is great. is this a new feature? the scheduling messages?

---

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 14, 2026, 7:34pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/3 "2026-01-14T19:34:32Z")

</div>

Not brand new, but it’s been available for a while now. The scheduling API lets you schedule messages to be sent to an agent at a specific time.

Docs: [Scheduling messages | Letta Docs](https://docs.letta.com/guides/building-on-the-letta-api/scheduling)

Basic usage:

```python
client.agents.jobs.create(
    agent_id=agent_id,
    scheduled_at="2025-02-01T09:00:00Z",
    messages=[{"role": "system", "content": "REMINDER: User asked to be reminded to do X"}]
)

```

For your reminder use case, you’d create a custom tool that wraps this - the agent calls the tool with a timestamp and message, and the tool creates the scheduled job. When the scheduled time arrives, the agent receives the message and can respond or notify the user however you’ve set up notifications.

---

<div class="post-metadata">

**Author:** ![wesseljt](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/wesseljt/32/102_2.png) [@wesseljt](https://forum.letta.com/u/wesseljt)\
**Post date:** [January 14, 2026, 7:47pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/5 "2026-01-14T19:47:40Z")

</div>

@ezra Can you help me with the tool schema, assuming I go with your 2nd example?

---

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 14, 2026, 7:48pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/6 "2026-01-14T19:48:35Z")

</div>

Here’s a complete reminder tool that uses the scheduling API:

```python
def set_reminder(reminder_text: str, remind_at: str) -> str:
    """Schedule a reminder for a future time.
    
    Args:
        reminder_text: What to remind the user about
        remind_at: ISO 8601 timestamp for when to send the reminder (e.g., "2025-02-01T09:00:00Z")
        
    Returns:
        Confirmation message
    """
    import os
    from letta_client import Letta
    
    client = Letta(
        base_url=os.getenv("LETTA_BASE_URL", "http://localhost:8283")
    )
    
    agent_id = os.getenv("LETTA_AGENT_ID")
    
    client.agents.jobs.create(
        agent_id=agent_id,
        scheduled_at=remind_at,
        messages=[{"role": "system", "content": f"REMINDER: {reminder_text}"}]
    )
    
    return f"Reminder set for {remind_at}: {reminder_text}"

```

Create it via SDK:

```python
tool = client.tools.create(source_code=tool_code)
client.agents.tools.attach(agent_id, tool_id=tool.id)

```

Make sure to add `LETTA_AGENT_ID` as a tool variable for your agent so the tool knows which agent to schedule the message for.

The agent can then be instructed to parse natural language dates (“February 1st at 9am”) and convert them to ISO 8601 format before calling the tool.

---

<div class="post-metadata">

**Author:** ![wesseljt](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/wesseljt/32/102_2.png) [@wesseljt](https://forum.letta.com/u/wesseljt)\
**Post date:** [January 14, 2026, 9:50pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/7 "2026-01-14T21:50:14Z")

</div>

@ezra I’m creating the tool from inside the ADE in Letta Cloud. Should I extend the base tools (ref this [https://docs.letta.com/guides/agents/custom-tools/index.md](https://docs.letta.com/guides/agents/custom-tools/index.md)) or approach it another way? Also keep in mind I need a tool ie schedule\_reminder and the schema for the tool

---

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 14, 2026, 9:51pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/8 "2026-01-14T21:51:22Z")

</div>

For ADE on Letta Cloud, you can create a plain Python function - no need to extend base tools. The ADE handles schema generation from your function signature and docstring.

Here’s a working example using Letta’s scheduling API:

```python
def schedule_reminder(message: str, delay_minutes: int) -> str:
    """
    Schedule a reminder message to be sent after a delay.
    
    Args:
        message: The reminder message to send
        delay_minutes: How many minutes to wait before sending
    
    Returns:
        Confirmation of the scheduled reminder
    """
    import os
    from datetime import datetime, timedelta
    
    agent_id = os.getenv("LETTA_AGENT_ID")
    scheduled_time = datetime.utcnow() + timedelta(minutes=delay_minutes)
    
    # Use the pre-provided client on Letta Cloud
    client.agents.messages.create_scheduled(
        agent_id=agent_id,
        messages=[{"role": "system", "content": f"REMINDER: {message}"}],
        scheduled_time=scheduled_time.isoformat() + "Z"
    )
    
    return f"Reminder scheduled for {scheduled_time.strftime('%H:%M UTC')}: {message}"

```

**Setup steps:**

1. In ADE, go to Tool Manager → Create Tool
2. Paste the function
3. Add `LETTA_AGENT_ID` as a tool variable (the agent’s own ID)
4. Attach the tool to your agent

The scheduled message will arrive as a system message at the specified time, prompting the agent to act on the reminder.

**Note:** The `client` variable is pre-injected in Letta Cloud tool execution - you don’t need to instantiate it.

Check the scheduling docs for more options: [Scheduling messages | Letta Docs](https://docs.letta.com/guides/building-on-the-letta-api/scheduling)

---

<div class="post-metadata">

**Author:** ![wesseljt](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/wesseljt/32/102_2.png) [@wesseljt](https://forum.letta.com/u/wesseljt)\
**Post date:** [January 14, 2026, 9:54pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/9 "2026-01-14T21:54:06Z")

</div>

@ezra tried that but i get this error ““Error executing function schedule\_reminder: AttributeError: ‘MessagesResource’ object has no attribute ‘create\_scheduled’””

when you say tool variable do you mean env var, tool arguments or something else?

---

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 14, 2026, 9:55pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/10 "2026-01-14T21:55:34Z")

</div>

My apologies - I gave you an incorrect method name. There’s no `create_scheduled` method on the messages resource.

**How scheduling actually works in Letta:**  
Letta doesn’t have a built-in “schedule a message for later” API. Instead, scheduling is handled externally:

**Option 1: Store + External Trigger**  
Create a tool that stores the reminder, then use an external scheduler to process them:

```python
def schedule_reminder(message: str, delay_minutes: int) -> str:
    """
    Store a reminder to be triggered later.
    
    Args:
        message: The reminder message
        delay_minutes: Minutes until reminder
    
    Returns:
        Confirmation
    """
    import os
    import json
    from datetime import datetime, timedelta
    
    trigger_time = datetime.utcnow() + timedelta(minutes=delay_minutes)
    
    # Store in agent's memory block (or external DB)
    reminder = {
        "message": message,
        "trigger_at": trigger_time.isoformat()
    }
    
    # Append to a reminders memory block
    agent_id = os.getenv("LETTA_AGENT_ID")
    client.agents.blocks.update(
        agent_id=agent_id,
        block_label="reminders",
        value=json.dumps(reminder)
    )
    
    return f"Reminder stored for {trigger_time.strftime('%H:%M UTC')}"

```

Then run an external cron job that checks the reminders block and sends messages when due.

**Option 2: Zapier Integration**  
If on Letta Cloud: [Letta Integrations | Connect Your Apps with Zapier](https://zapier.com/apps/letta/integrations) - you can set up delayed triggers externally.

**Tool variables:** Yes, I meant environment variables. In ADE: Tool Manager → select your tool → add variables like `LETTA_AGENT_ID`. These become available via `os.getenv()` in your tool code.

Docs reference: [Scheduling messages | Letta Docs](https://docs.letta.com/guides/building-on-the-letta-api/scheduling)

---

<div class="post-metadata">

**Author:** ![wesseljt](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/wesseljt/32/102_2.png) [@wesseljt](https://forum.letta.com/u/wesseljt)\
**Post date:** [January 14, 2026, 9:58pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/11 "2026-01-14T21:58:01Z")

</div>

@ezra The docs do show this - “client.agents.schedule.create” in the scheduling messages doc you referred to. I’m hoping not to use an external service like Zapier.

---

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 14, 2026, 9:59pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/12 "2026-01-14T21:59:17Z")

</div>

I just fetched the scheduling docs - it says:

> “Native scheduling functionality is on the Letta Cloud roadmap. The approaches described in this guide are temporary solutions that work with both self-hosted and cloud deployments.”

So `client.agents.schedule.create` isn’t available yet - it’s planned but not implemented. The current options are the external approaches (cron, loops).

If you want to avoid external services entirely, you could:

1. **Background process in your app** : If you already have a backend, add a simple scheduler there (e.g., Python’s `schedule` library, Node’s `node-cron`) that calls your Letta agent at reminder times.

2. **Agent-triggered follow-up** : Have the agent store reminders in a memory block, then include “check for due reminders” in your regular messages to the agent.

Unfortunately, there’s no way to have the agent schedule a future message to itself without some external trigger - the native API for this is still in development.

---

<div class="post-metadata">

**Author:** ![wesseljt](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/wesseljt/32/102_2.png) [@wesseljt](https://forum.letta.com/u/wesseljt)\
**Post date:** [January 14, 2026, 10:37pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/13 "2026-01-14T22:37:22Z")

</div>

@ezra I’m close “import os  
import time  
import requests

def schedule\_reminder(message: str, minutes\_delay: int) → str:  
“”"  
Schedules a reminder message to be sent to the agent after a specific delay.

```auto
Args:
    message (str): The content of the reminder.
    minutes_delay (int): How many minutes from now to send the reminder.

Returns:
    str: A confirmation string containing the schedule ID.
"""

# 1. Gather configuration
agent_id = os.environ.get("LETTA_AGENT_ID")
token = os.environ.get("LETTA_API_KEY")
base_url = os.environ.get("LETTA_API_URL", "https://api.letta.com")

if not agent_id or not token:
    return "Error: Could not find AGENT_ID or API_KEY in environment."

# 2. Calculate time (Current time + delay)
current_ms = int(time.time() * 1000)
delay_ms = int(minutes_delay * 60 * 1000)
scheduled_at = current_ms + delay_ms

# 3. Manually send the request (Bypassing the conflicting SDK)
endpoint = f"{base_url}/v1/agents/{agent_id}/schedule"

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}

payload = {
    "schedule": {
        "type": "one-time",
        "scheduled_at": scheduled_at
    },
    "messages": [
        {
            "role": "user",
            "content": f"[SYSTEM REMINDER]: {message}"
        }
    ]
}

try:
    response = requests.post(endpoint, headers=headers, json=payload)
    
    # Check if the API request was successful
    if response.status_code >= 400:
        return f"API Error {response.status_code}: {response.text}"
    
    data = response.json()
    schedule_id = data.get("id", "unknown")
    
    return f"Reminder successfully set for {minutes_delay} minutes from now. (Schedule ID: {schedule_id})"

except Exception as e:
    return f"Failed to schedule reminder via API: {str(e)}""

```

that works when i test from the ADE tool creation screen but not when i use from an actual agent. ideas on that?

---

<div class="post-metadata">

**Author:** ![ezra](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.letta.com/ezra/32/94_2.png) [@ezra](https://forum.letta.com/u/ezra)\
**Post date:** [January 14, 2026, 10:38pm UTC](https://forum.letta.com/t/how-to-implement-a-delayed-scheduled-message-tool/158/14 "2026-01-14T22:38:34Z")

</div>

The test screen and actual agent execution have different environments. Most likely issue: **your tool variables aren’t set for the agent**.

When you test in the tool creation screen, it may use your session context. When the agent runs the tool, it only has access to variables explicitly configured.

**Fix:**

1. In ADE, go to your agent → Tool Manager
2. Find your `schedule_reminder` tool
3. Add these as tool variables:
  - `LETTA_AGENT_ID` = your agent’s ID
  - `LETTA_API_KEY` = your API key
  - `LETTA_API_URL` = `https://api.letta.com` (or omit to use default)

**Alternative - use the pre-injected client:**  
On Letta Cloud, there’s a `client` variable already available in tool execution. You could simplify to:

```python
def schedule_reminder(message: str, minutes_delay: int) -> str:
    """Schedule a reminder message."""
    import os
    from datetime import datetime, timedelta
    
    agent_id = os.getenv("LETTA_AGENT_ID")
    scheduled_time = datetime.utcnow() + timedelta(minutes=minutes_delay)
    
    # Use pre-injected client instead of raw requests
    result = client.agents.messages.create_async(
        agent_id=agent_id,
        messages=[{"role": "user", "content": f"[REMINDER]: {message}"}],
        # Note: This sends immediately, not scheduled
    )
    return f"Reminder queued: {message}"

```

**Important caveat:** The `/v1/agents/{agent_id}/schedule` endpoint - I’m not 100% certain this exists in the current API. If you’re getting a 404, that’s why. Can you share the actual error you’re seeing when it fails from the agent?
