Python Examples
Complete Python code examples for using the Boring API.
Installation
Install required library:
pip install requests
Basic Setup
import requests
import os
# Configuration
API_URL = "https://boring.aiagent-me.com/v2/posts"
API_KEY = os.environ.get("BORING_API_KEY")
# Headers
HEADERS = {
"boring-api-key": API_KEY,
"Content-Type": "application/json"
}
Simple Publishing Function
def publish_post(account_id, platform, text, media_urls=None):
"""
Publish a post to social media
Args:
account_id (str): Account ID from dashboard
platform (str): "facebook", "instagram", or "threads"
text (str|list): Post text or list of strings for thread
media_urls (list): List of media URLs (optional)
Returns:
dict: API response
"""
if media_urls is None:
media_urls = []
data = {
"post": {
"accountId": account_id,
"content": {
"text": text,
"mediaUrls": media_urls,
"platform": platform
},
"target": {
"targetType": platform
}
}
}
response = requests.post(API_URL, headers=HEADERS, json=data)
return response.json()
Facebook Examples
Text-Only Post
result = publish_post(
account_id="your-facebook-account-id",
platform="facebook",
text="Hello from Boring API! π"
)
if result["success"]:
print(f"Published! Post ID: {result['data']['post_id']}")
else:
print(f"Error: {result['message']}")
Single Photo
result = publish_post(
account_id="your-facebook-account-id",
platform="facebook",
text="Check out our new product!",
media_urls=["https://example.com/product.jpg"]
)
Photo Album
result = publish_post(
account_id="your-facebook-account-id",
platform="facebook",
text="Our best moments from the event! πΈ",
media_urls=[
"https://example.com/event1.jpg",
"https://example.com/event2.jpg",
"https://example.com/event3.jpg",
"https://example.com/event4.jpg"
]
)
Video Post
result = publish_post(
account_id="your-facebook-account-id",
platform="facebook",
text="Watch our product demo! π₯",
media_urls=["https://example.com/demo.mp4"]
)
Instagram Examples
Single Photo
result = publish_post(
account_id="your-instagram-account-id",
platform="instagram",
text="Beautiful sunset π
\n\n#photography #nature #sunset",
media_urls=["https://example.com/sunset.jpg"]
)
Carousel
result = publish_post(
account_id="your-instagram-account-id",
platform="instagram",
text="Swipe to see our new collection! β‘οΈ\n\n#fashion #style #newcollection",
media_urls=[
"https://example.com/item1.jpg",
"https://example.com/item2.jpg",
"https://example.com/item3.jpg"
]
)
Reels (Video)
result = publish_post(
account_id="your-instagram-account-id",
platform="instagram",
text="Quick tutorial! π₯\n\n#tutorial #howto #tips",
media_urls=["https://example.com/tutorial.mp4"]
)
Threads Examples
Text-Only
result = publish_post(
account_id="your-threads-account-id",
platform="threads",
text="Just shipped a new feature! π"
)
Single Photo
result = publish_post(
account_id="your-threads-account-id",
platform="threads",
text="Morning vibes β",
media_urls=["https://example.com/morning.jpg"]
)
Carousel
result = publish_post(
account_id="your-threads-account-id",
platform="threads",
text="Our journey in photos πΈ",
media_urls=[
"https://example.com/photo1.jpg",
"https://example.com/photo2.jpg",
"https://example.com/photo3.jpg",
"https://example.com/photo4.jpg",
"https://example.com/photo5.jpg"
]
)
Long-Form Thread
# Note: text is an ARRAY of strings
thread_content = [
"π§΅ Let me tell you about building our API (thread)",
"It started with a simple idea: make social media publishing easier.",
"We researched all the pain points developers face.",
"Token management, platform differences, complex APIs - all frustrating.",
"So we built Boring: one unified API for all platforms.",
"Today we support Facebook, Instagram, and Threads!",
"What platform should we add next? Let me know! π"
]
result = publish_post(
account_id="your-threads-account-id",
platform="threads",
text=thread_content # Array creates a thread!
)
if result["success"]:
print(f"Thread published! {result['data']['thread_count']} posts")
print(f"Post IDs: {result['data']['post_ids']}")
Advanced Examples
Cross-Platform Publishing
def cross_platform_publish(accounts, text, media_urls):
"""
Publish to multiple platforms simultaneously
Args:
accounts (dict): Map of platform to account_id
text (str): Post text
media_urls (list): Media URLs
Returns:
dict: Results for each platform
"""
results = {}
for platform, account_id in accounts.items():
print(f"Publishing to {platform}...")
# Adapt content for each platform
adapted_text = adapt_content(text, platform)
adapted_media = adapt_media(media_urls, platform)
result = publish_post(
account_id=account_id,
platform=platform,
text=adapted_text,
media_urls=adapted_media
)
results[platform] = result
# Log result
if result["success"]:
print(f"β {platform}: Success")
else:
print(f"β {platform}: {result['message']}")
return results
# Usage
accounts = {
"facebook": "fb-account-id",
"instagram": "ig-account-id",
"threads": "threads-account-id"
}
results = cross_platform_publish(
accounts=accounts,
text="Check out our new product launch!",
media_urls=["https://example.com/product.jpg"]
)
Content Adaptation
def adapt_content(text, platform):
"""Adapt text content for each platform"""
if platform == "instagram":
# Add hashtags for Instagram
return f"{text}\n\n#product #launch #new"
elif platform == "threads":
# Keep it conversational for Threads
return f"{text} What do you think? π"
else: # facebook
# Keep original for Facebook
return text
def adapt_media(media_urls, platform):
"""Adapt media for each platform"""
if platform == "instagram":
# Instagram requires at least one media
if not media_urls:
raise ValueError("Instagram requires media")
# Threads supports up to 20 images
if platform == "threads":
return media_urls[:20]
# Facebook/Instagram support up to 10
return media_urls[:10]
Error Handling
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def publish_with_error_handling(account_id, platform, text, media_urls=None):
"""Publish with comprehensive error handling"""
try:
logger.info(f"Publishing to {platform} (account: {account_id})")
result = publish_post(account_id, platform, text, media_urls)
if result["success"]:
logger.info(f"Success! Post ID: {result['data']['post_id']}")
return result
# Handle specific errors
error_code = result.get("error")
if error_code == "TokenExpired":
logger.error("Token expired. Please reconnect account.")
notify_admin("Token expired", account_id)
elif error_code == "MediaDownloadFailed":
logger.error("Media download failed. Check URLs.")
# Try without media
logger.info("Retrying without media...")
return publish_post(account_id, platform, text, [])
elif error_code == "RateLimitExceeded":
retry_after = result.get("retry_after", 3600)
logger.warning(f"Rate limited. Retry in {retry_after}s")
else:
logger.error(f"Error: {result['message']}")
return result
except requests.exceptions.Timeout:
logger.error("Request timed out")
return {"success": False, "error": "Timeout"}
except requests.exceptions.RequestException as e:
logger.error(f"Request failed: {e}")
return {"success": False, "error": "NetworkError"}
except Exception as e:
logger.exception(f"Unexpected error: {e}")
return {"success": False, "error": "UnexpectedException"}
def notify_admin(subject, details):
"""Send notification to admin"""
# Implement your notification logic
print(f"ADMIN ALERT: {subject} - {details}")
Retry Logic
import time
def publish_with_retry(account_id, platform, text, media_urls=None, max_retries=3):
"""Publish with automatic retry on failure"""
retryable_errors = [
"RateLimitExceeded",
"ServiceUnavailable",
"Timeout",
"InternalServerError"
]
for attempt in range(max_retries):
try:
logger.info(f"Attempt {attempt + 1}/{max_retries}")
result = publish_post(account_id, platform, text, media_urls)
if result["success"]:
return result
error_code = result.get("error")
# Don't retry non-retryable errors
if error_code not in retryable_errors:
logger.warning(f"Non-retryable error: {error_code}")
return result
# Calculate wait time
if error_code == "RateLimitExceeded":
wait_time = result.get("retry_after", 3600)
else:
wait_time = 2 ** attempt # Exponential backoff
logger.info(f"Retrying in {wait_time}s...")
time.sleep(wait_time)
except Exception as e:
if attempt == max_retries - 1:
raise
logger.warning(f"Attempt failed: {e}")
time.sleep(2 ** attempt)
return {"success": False, "error": "MaxRetriesExceeded"}
Batch Publishing
def batch_publish(posts, delay=2):
"""
Publish multiple posts with rate limiting
Args:
posts (list): List of post dictionaries
delay (int): Seconds to wait between posts
Returns:
list: Results for each post
"""
results = []
for i, post in enumerate(posts):
logger.info(f"Publishing post {i+1}/{len(posts)}")
result = publish_with_retry(**post)
results.append({
"index": i,
"post": post,
"result": result
})
# Rate limiting
if i < len(posts) - 1:
time.sleep(delay)
# Summary
successes = sum(1 for r in results if r["result"]["success"])
failures = len(results) - successes
logger.info(f"Batch complete: {successes} succeeded, {failures} failed")
return results
# Usage
posts = [
{
"account_id": "fb-account-id",
"platform": "facebook",
"text": "Post 1",
"media_urls": []
},
{
"account_id": "ig-account-id",
"platform": "instagram",
"text": "Post 2",
"media_urls": ["https://example.com/image.jpg"]
},
{
"account_id": "threads-account-id",
"platform": "threads",
"text": "Post 3",
"media_urls": []
}
]
results = batch_publish(posts)
Thread Generator
def split_into_thread(long_text, max_chars=450):
"""
Split long text into thread posts
Args:
long_text (str): Long text to split
max_chars (int): Max characters per post (default 450)
Returns:
list: List of post strings
"""
sentences = long_text.split('. ')
posts = []
current_post = ""
for sentence in sentences:
# Check if adding sentence would exceed limit
if len(current_post) + len(sentence) + 2 <= max_chars:
current_post += sentence + '. '
else:
# Start new post
if current_post:
posts.append(current_post.strip())
current_post = sentence + '. '
# Add last post
if current_post:
posts.append(current_post.strip())
return posts
# Usage
article = """
This is a very long article about our product launch.
It contains multiple sentences and paragraphs.
We want to share it as a thread on Threads.
Each post should be under 450 characters.
This function will automatically split it for us.
"""
thread_posts = split_into_thread(article)
result = publish_post(
account_id="threads-account-id",
platform="threads",
text=thread_posts # Array creates thread
)
Configuration Management
import json
class BoringAPI:
"""Boring API client with configuration management"""
def __init__(self, api_key=None, accounts_config=None):
self.api_key = api_key or os.environ.get("BORING_API_KEY")
self.api_url = "https://boring.aiagent-me.com/v2/posts"
# Load accounts from config file
if accounts_config:
with open(accounts_config) as f:
self.accounts = json.load(f)
else:
self.accounts = {}
self.headers = {
"boring-api-key": self.api_key,
"Content-Type": "application/json"
}
def publish(self, account_name, text, media_urls=None):
"""
Publish using account name from config
Args:
account_name (str): Account name from config
text (str|list): Post text
media_urls (list): Media URLs
Returns:
dict: API response
"""
if account_name not in self.accounts:
raise ValueError(f"Account '{account_name}' not found in config")
account = self.accounts[account_name]
return publish_post(
account_id=account["id"],
platform=account["platform"],
text=text,
media_urls=media_urls or []
)
# accounts.json
{
"production_fb": {
"id": "fb-account-id",
"platform": "facebook"
},
"production_ig": {
"id": "ig-account-id",
"platform": "instagram"
},
"production_threads": {
"id": "threads-account-id",
"platform": "threads"
}
}
# Usage
api = BoringAPI(accounts_config="accounts.json")
api.publish(
account_name="production_fb",
text="Hello from Boring API!",
media_urls=[]
)
Complete Example
Full script with all features:
#!/usr/bin/env python3
"""
Boring API Publishing Script
"""
import requests
import os
import logging
import time
from typing import List, Dict, Optional
# Configuration
API_URL = "https://boring.aiagent-me.com/v2/posts"
API_KEY = os.environ.get("BORING_API_KEY")
# Logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def publish_post(
account_id: str,
platform: str,
text: str,
media_urls: Optional[List[str]] = None
) -> Dict:
"""Publish a post to social media"""
headers = {
"boring-api-key": API_KEY,
"Content-Type": "application/json"
}
data = {
"post": {
"accountId": account_id,
"content": {
"text": text,
"mediaUrls": media_urls or [],
"platform": platform
},
"target": {
"targetType": platform
}
}
}
response = requests.post(API_URL, headers=headers, json=data)
return response.json()
def main():
"""Main function"""
# Example: Publish to Facebook
logger.info("Publishing to Facebook...")
result = publish_post(
account_id=os.environ.get("FB_ACCOUNT_ID"),
platform="facebook",
text="Hello from Boring API! π",
media_urls=[]
)
if result["success"]:
logger.info(f"Success! Post ID: {result['data']['post_id']}")
else:
logger.error(f"Failed: {result['message']}")
if __name__ == "__main__":
main()
Next Steps
- JavaScript Examples - Node.js code examples
- cURL Examples - Command-line examples
- Use Cases - Real-world scenarios
- API Reference - Complete API docs