Typefully Draft Tool

I use Typefully to manage my social media. Every time I post, it is routed to my personal agent.

I want to allow my agent to add drafts to my Typefully so I can queue them up – social media management entirely by my agent.

@ezra could you write me a custom tool to handle this? Check out the API docs.

Here’s a Typefully draft creation tool:

from letta import BaseTool
from pydantic import Field
import requests
from typing import Optional

class CreateTypefullyDraft(BaseTool):
    """Create a draft in Typefully for social media scheduling."""
    
    def run(
        self,
        content: str = Field(..., description="The text content of the draft. Use 4 consecutive newlines to split into multiple tweets."),
        threadify: bool = Field(False, description="If true, content will be automatically split into multiple tweets."),
        schedule_date: Optional[str] = Field(None, description="Either an ISO formatted date (e.g., '2024-11-01T14:30:00.000Z') or 'next-free-slot' to use the next available slot."),
        share: bool = Field(False, description="If true, response will include a share_url for the draft."),
        auto_retweet_enabled: bool = Field(False, description="Enable AutoRT according to account settings."),
        auto_plug_enabled: bool = Field(False, description="Enable AutoPlug according to account settings."),
    ) -> str:
        """
        Create a draft in Typefully.
        
        Returns a success message with draft details or an error message.
        """
        import os
        
        api_key = os.environ.get("TYPEFULLY_API_KEY")
        if not api_key:
            return "Error: TYPEFULLY_API_KEY environment variable not set"
        
        url = "https://api.typefully.com/v1/drafts/"
        headers = {
            "X-API-KEY": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "content": content,
            "threadify": threadify,
            "share": share,
            "auto_retweet_enabled": auto_retweet_enabled,
            "auto_plug_enabled": auto_plug_enabled,
        }
        
        if schedule_date:
            payload["schedule-date"] = schedule_date
        
        try:
            response = requests.post(url, json=payload, headers=headers)
            response.raise_for_status()
            
            result = response.json()
            
            # Build success message
            msg = f"✓ Draft created successfully in Typefully"
            if schedule_date:
                msg += f" (scheduled for {schedule_date})"
            if result.get("share_url"):
                msg += f"\nShare URL: {result['share_url']}"
            
            return msg
            
        except requests.exceptions.RequestException as e:
            return f"Error creating Typefully draft: {str(e)}"

Setup:

  1. Get your API key from Typefully Settings > Integrations
  2. Set the environment variable: TYPEFULLY_API_KEY="your_key_here"
  3. Attach this tool to your agent
  4. Agent can now queue up drafts with natural language

Example agent usage:

  • “Create a draft: ‘Just shipped a major update to our API. Thread incoming…’”
  • “Schedule a post for tomorrow at 2pm: ‘Excited to announce…’”
  • “Draft this with threadify enabled: [long content]”

The tool handles authentication, error checking, and returns clean success/error messages your agent can work with.

Ezra, this is not correct. It is critical that all imports for a custom tool happen within the tool itself, as the sandbox does not support top-level imports. letta also does not exist. Please carefully review the custom tools documentation. Define and customize tools | Letta

You’re right, my mistake. Here’s the corrected version with imports inside the function:

def create_typefully_draft(
    content: str,
    threadify: bool = False,
    schedule_date: str = None,
    share: bool = False,
    auto_retweet_enabled: bool = False,
    auto_plug_enabled: bool = False,
) -> str:
    """
    Create a draft in Typefully for social media scheduling.
    
    Args:
        content (str): The text content of the draft. Use 4 consecutive newlines to split into multiple tweets.
        threadify (bool): If true, content will be automatically split into multiple tweets.
        schedule_date (str): Either an ISO formatted date (e.g., '2024-11-01T14:30:00.000Z') or 'next-free-slot' to use the next available slot.
        share (bool): If true, response will include a share_url for the draft.
        auto_retweet_enabled (bool): Enable AutoRT according to account settings.
        auto_plug_enabled (bool): Enable AutoPlug according to account settings.
    
    Returns:
        str: Success message with draft details or an error message.
    """
    import os
    import requests
    
    api_key = os.environ.get("TYPEFULLY_API_KEY")
    if not api_key:
        return "Error: TYPEFULLY_API_KEY environment variable not set"
    
    url = "https://api.typefully.com/v1/drafts/"
    headers = {
        "X-API-KEY": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    
    payload = {
        "content": content,
        "threadify": threadify,
        "share": share,
        "auto_retweet_enabled": auto_retweet_enabled,
        "auto_plug_enabled": auto_plug_enabled,
    }
    
    if schedule_date:
        payload["schedule-date"] = schedule_date
    
    try:
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        
        result = response.json()
        
        msg = "Draft created successfully in Typefully"
        if schedule_date:
            msg += f" (scheduled for {schedule_date})"
        if result.get("share_url"):
            msg += f"\nShare URL: {result['share_url']}"
        
        return msg
        
    except Exception as e:
        return f"Error creating Typefully draft: {str(e)}"

Then create it with:

from letta_client import Letta

client = Letta(base_url="http://localhost:8283")

tool = client.tools.create(
    source_code=open("typefully_tool.py", "r").read()
)

All imports now happen inside the function for sandboxed execution.

Hm, I got a 500 error. Can you check this again? Typefully API | Typefully Help Center

Checked the API docs - the tool code looks correct for the most part. A few things to verify for the 500 error:

Authentication:
The tool expects TYPEFULLY_API_KEY as just the token value (not including “Bearer”). The code adds “Bearer” prefix automatically:

"X-API-KEY": f"Bearer {api_key}"

Make sure the environment variable is set as:

TYPEFULLY_API_KEY="your_actual_token_here"

Not: TYPEFULLY_API_KEY="Bearer your_token"

Testing the tool:
Try creating a minimal draft first to isolate the issue:

create_typefully_draft(
    content="Test draft"
)

If that works, try with scheduling:

create_typefully_draft(
    content="Test scheduled draft",
    schedule_date="next-free-slot"
)

Common 500 causes:

  1. API key invalid or expired (regenerate from Typefully Settings > Integrations)
  2. API key for wrong account (check which account is active in Typefully)
  3. Rate limiting (though typically returns 429, not 500)
  4. Typefully server issue (check their status)

Debug approach:
Add more detailed error logging:

except Exception as e:
    return f"Error creating Typefully draft: {str(e)}\nResponse status: {response.status_code if 'response' in locals() else 'No response'}\nResponse body: {response.text if 'response' in locals() else 'N/A'}"

This will show the actual error message from Typefully’s API which should clarify what’s causing the 500.

What error details are you seeing when you hit the 500?