Autonomous Agents
Integration Examples
Integration Examples
Ready-to-use code examples for integrating Relay SMS into popular agent frameworks. Copy, paste, and customize for your use case.
Anthropic MCP (Model Context Protocol)
Build Relay SMS as an MCP tool for Claude and other Anthropic models.
Installation
Codenpm install @relay-works/sdk-js
MCP Server Implementation
Code// relay-mcp-server.ts import { Server } from '@modelcontextprotocol/sdk/server/index.js' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js' import { RelayClient } from '@relay-works/sdk-js' const relay = new RelayClient({ apiKey: process.env.RELAY_API_KEY! }) const server = new Server( { name: 'relay-sms', version: '1.0.0', }, { capabilities: { tools: {}, }, } ) // Register SMS tool server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'send_sms', description: 'Send SMS message via Relay API', inputSchema: { type: 'object', properties: { to: { type: 'string', description: 'Phone number in E.164 format (+1XXXXXXXXXX)', }, template: { type: 'string', enum: ['authentication', 'transactional', 'notifications'], description: 'Template category for compliance', }, variables: { type: 'object', description: 'Template variables (e.g., {code: "123456"})', }, }, required: ['to', 'template', 'variables'], }, }, ], } }) // Handle SMS sending server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === 'send_sms') { const { to, template, variables } = request.params.arguments as { to: string template: string variables: Record<string, string> } try { const message = await relay.messages.sendTypedTemplate(template, { to, data: variables, }) return { content: [ { type: 'text', text: `SMS sent successfully! Message ID: ${message.id}, Status: ${message.status}`, }, ], } } catch (error) { return { content: [ { type: 'text', text: `Failed to send SMS: ${error.message}`, }, ], isError: true, } } } throw new Error(`Unknown tool: ${request.params.name}`) }) // Start server async function main() { const transport = new StdioServerTransport() await server.connect(transport) console.error('Relay MCP server running on stdio') } main().catch(console.error)
Claude Desktop Configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
Code{ "mcpServers": { "relay-sms": { "command": "node", "args": ["/path/to/relay-mcp-server.js"], "env": { "RELAY_API_KEY": "rly_live_agt_your_key" } } } }
Example Usage with Claude
CodeUser: Send a 2FA code "789012" to +16175551234 Claude: I'll send that verification code via SMS. [Uses send_sms tool] SMS sent successfully! Message ID: msg_abc123, Status: sent
LangChain
Integrate Relay as a LangChain tool for any LLM.
Installation
Codepip install langchain @relay-works/sdk-python
Tool Implementation
Code# relay_sms_tool.py import os from langchain.tools import BaseTool from pydantic import BaseModel, Field from relay_sdk import RelayClient class SMSInput(BaseModel): """Input schema for SMS tool""" to: str = Field(description="Phone number in E.164 format") template: str = Field(description="Template category: authentication, transactional, or notifications") variables: dict = Field(description="Template variables (e.g., {'code': '123456'})") class RelaySMSTool(BaseTool): name = "send_sms" description = "Send SMS message via Relay API. Use for 2FA codes, notifications, and transactional messages." args_schema = SMSInput def __init__(self): super().__init__() self.relay = RelayClient(api_key=os.getenv('RELAY_API_KEY')) def _run(self, to: str, template: str, variables: dict) -> str: """Send SMS and return result""" try: message = self.relay.messages.send_template( template, to=to, data=variables ) return f"SMS sent! Message ID: {message['id']}, Status: {message['status']}" except Exception as e: return f"Failed to send SMS: {str(e)}" async def _arun(self, to: str, template: str, variables: dict) -> str: """Async version""" return self._run(to, template, variables)
Usage with LangChain Agent
Codefrom langchain.agents import initialize_agent, AgentType from langchain_openai import ChatOpenAI from relay_sms_tool import RelaySMSTool # Initialize LLM llm = ChatOpenAI(temperature=0) # Initialize tools tools = [RelaySMSTool()] # Create agent agent = initialize_agent( tools=tools, llm=llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=True ) # Run result = agent.run( "Send a 2FA code '456789' to +16175551234" ) print(result)
AutoGPT
Add Relay SMS as an AutoGPT plugin.
Plugin Structure
Codeautogpt_relay_sms/ ├── __init__.py ├── relay_sms.py └── README.md
Plugin Implementation
Code# relay_sms.py import os from typing import Dict, Any from auto_gpt_plugin_template import AutoGPTPluginTemplate from relay_sdk import RelayClient class RelaySMSPlugin(AutoGPTPluginTemplate): """AutoGPT plugin for Relay SMS""" def __init__(self): super().__init__() self._name = "relay_sms" self._version = "1.0.0" self._description = "Send SMS messages via Relay API" self.relay = RelayClient(api_key=os.getenv('RELAY_API_KEY')) def can_handle_post_prompt(self) -> bool: return True def post_prompt(self, prompt: str) -> str: return prompt def can_handle_on_planning(self) -> bool: return True def on_planning(self, prompt: str, messages: list) -> str: return prompt def can_handle_pre_instruction(self) -> bool: return False def can_handle_on_instruction(self) -> bool: return True def on_instruction(self, messages: list) -> str: return "" def can_handle_post_instruction(self) -> bool: return False def can_handle_pre_command(self) -> bool: return False def can_handle_post_command(self) -> bool: return False def can_handle_chat_completion( self, messages: list, model: str, temperature: float, max_tokens: int ) -> bool: return False def handle_chat_completion( self, messages: list, model: str, temperature: float, max_tokens: int ) -> str: return "" # Register SMS command def get_commands(self) -> Dict[str, Any]: return { "send_sms": { "description": "Send SMS via Relay API", "parameters": { "to": { "type": "string", "description": "Phone number in E.164 format", "required": True }, "template": { "type": "string", "description": "Template category", "enum": ["authentication", "transactional", "notifications"], "required": True }, "variables": { "type": "object", "description": "Template variables", "required": True } }, "function": self.send_sms } } def send_sms(self, to: str, template: str, variables: dict) -> str: """Send SMS message""" try: message = self.relay.messages.send_template( template, to=to, data=variables ) return f"SMS sent! ID: {message['id']}" except Exception as e: return f"Failed: {str(e)}"
Installation
Codecd plugins git clone https://github.com/your-org/autogpt_relay_sms.git cd autogpt_relay_sms pip install -e .
Configuration
Add to .env:
CodeRELAY_API_KEY=rly_live_agt_your_key
OpenHands (formerly OpenDevin)
Integrate Relay SMS into OpenHands actions.
Action Implementation
Code# relay_sms_action.py from openhands.controller.agent import Agent from openhands.controller.state.state import State from openhands.core.config import config from openhands.events.action import Action from openhands.runtime.plugins import PluginRequirement import os from relay_sdk import RelayClient class SendSMSAction(Action): """Action to send SMS via Relay API""" to: str template: str variables: dict def __init__(self, to: str, template: str, variables: dict): super().__init__() self.to = to self.template = template self.variables = variables @property def message(self) -> str: return f"Sending SMS to {self.to} using {self.template} template" class RelaySMSAgent(Agent): """Agent with Relay SMS capabilities""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.relay = RelayClient(api_key=os.getenv('RELAY_API_KEY')) def step(self, state: State) -> Action: """Process state and determine next action""" # Check if we need to send SMS if self._should_send_sms(state): return self._create_sms_action(state) return super().step(state) def _should_send_sms(self, state: State) -> bool: """Determine if SMS should be sent""" # Your logic here return False def _create_sms_action(self, state: State) -> SendSMSAction: """Create SMS action from state""" return SendSMSAction( to=state.context.get('phone_number'), template='authentication', variables={'code': state.context.get('verification_code')} ) def execute_action(self, action: Action) -> dict: """Execute the action""" if isinstance(action, SendSMSAction): return self._execute_sms(action) return super().execute_action(action) def _execute_sms(self, action: SendSMSAction) -> dict: """Send SMS via Relay""" try: message = self.relay.messages.send_template( template=action.template, to=action.to, data=action.variables ) return { 'success': True, 'message_id': message['id'], 'status': message['status'] } except Exception as e: return { 'success': False, 'error': str(e) }
Generic HTTP Integration
For frameworks without SDK support, use direct HTTP requests.
cURL Example
Code#!/bin/bash RELAY_API_KEY="rly_live_agt_your_key" send_sms() { local to=$1 local code=$2 curl -X POST https://api.relay.works/v1/messages/send-template \ -H "x-api-key: $RELAY_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"to\": \"$to\", \"template\": \"authentication\", \"data\": { \"code\": \"$code\" } }" } send_sms "+16175551234" "123456"
Node.js (Vanilla)
Codeconst fetch = require('node-fetch') async function sendSMS(to, code) { const response = await fetch('https://api.relay.works/v1/messages/send-template', { method: 'POST', headers: { 'x-api-key': process.env.RELAY_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ to, template: 'authentication', data: { code } }) }) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${await response.text()}`) } return response.json() } sendSMS('+16175551234', '123456') .then(msg => console.log('Sent:', msg.id)) .catch(err => console.error('Failed:', err))
Python (Vanilla)
Codeimport os import requests def send_sms(to: str, code: str) -> dict: response = requests.post( 'https://api.relay.works/v1/messages/send-template', headers={ 'x-api-key': os.getenv("RELAY_API_KEY"), 'Content-Type': 'application/json' }, json={ 'to': to, 'template': 'authentication', 'data': {'code': code} } ) response.raise_for_status() return response.json() message = send_sms('+16175551234', '123456') print(f'Sent: {message["id"]}')
Error Handling
All frameworks should handle common errors:
Codetry { await relay.messages.send(message) } catch (error) { switch (error.status) { case 401: // Invalid API key console.error('Authentication failed. Check API key.') break case 402: // Payment required console.error('Payment needed. Complete Stripe link.') break case 429: // Rate limited const retryAfter = error.headers['retry-after'] console.error(`Rate limited. Retry in ${retryAfter}s`) await sleep(retryAfter * 1000) break case 451: // Template required (new agents) console.error('Must use templates. Call sendTypedTemplate() instead.') break default: console.error('Unexpected error:', error.message) } }
Best Practices
1. Store API Keys Securely
Never hardcode API keys:
Code# ✅ Good - use environment variables export RELAY_API_KEY=rly_live_agt_your_key # ❌ Bad - hardcoded in code const apiKey = "rly_live_agt_your_key"
2. Implement Retry Logic
Handle transient failures:
Codeasync function sendWithRetry(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn() } catch (error) { if (i === maxRetries - 1) throw error await sleep(Math.pow(2, i) * 1000) } } }
3. Monitor Trust Level
Check status regularly:
Codeconst status = await relay.accounts.getStatus() if (status.trust_level === 'new_agent') { console.log('Limited to authentication templates') }
4. Validate Phone Numbers
Use E.164 format:
Codefunction validatePhone(phone: string): boolean { return /^\+1\d{10}$/.test(phone) }
Next Steps
- Trust Levels - Understand automatic upgrades
- Quick Start - Set up your first agent
- API Reference - Complete endpoint docs
Last modified on