Python SDK for the Surf social platform API.
pip install surf-apifrom surf_api import SurfClient
client = SurfClient("surf_sk_live_your_token_here")
# Get feed metadata
feed = client.feeds.get("surf/topic/technology")
print(feed["title"])
# Get posts from a feed
data = client.feeds.get_posts("surf/topic/technology", limit=10)
for post in data["posts"]:
print(f"{post['title']} by {post['author']['displayName']}")
# Search for feeds
results = client.search.feeds("artificial intelligence")
# Natural language search (NLWeb)
results = client.search.ask("feeds about sustainable energy", k=5)
# Get trending posts
trending = client.feeds.get_posts("surf/trending/dynamic", limit=10)- Feeds: Read feeds, posts, trending content, topics
- Search: Search feeds, posts, accounts, Bluesky users, podcasts, RSS, publications
- Longform: standard.site / Leaflet documents & publications
- AI Search: Natural language queries via NLWeb
- Audio: Radio stations, daily briefings, transcripts, quizzes
- Custom Feeds: Create, update, delete, clone, publish custom feeds
- Account: User info, activity, notifications, preferences
- Media: Upload images
- Rate Limiting: Automatic rate limit tracking via
client.rate_limit - Pagination: Built-in cursor-based pagination
Get an API token from the Surf Developer Portal.
client = SurfClient("surf_sk_live_your_token_here")
# Check rate limit status after any request
print(client.rate_limit) # RateLimitInfo(remaining=59/60, reset=2026-01-01T00:01:00Z)# Create a custom feed
feed = client.custom_feeds.create(
title="AI News",
description="Latest AI and ML news",
operators=[
{"surfId": "surf/topic/artificial-intelligence", "operator": "source"},
{"surfId": "bluesky/user/@ai-news.bsky.social", "operator": "source"},
{"surfId": "surf/hashtag/machinelearning", "operator": "source"},
]
)
# Add a source
client.custom_feeds.add_operator(feed["id"], {
"surfId": "surf/search_keyword/machine learning", "operator": "source"
})
# Publish it
client.custom_feeds.publish(feed["id"])
# Create a themed feed
from surf_api.client import FeedTheme
theme = FeedTheme(
header_image="https://cdn.example.com/logo.png",
header_image_size={"width": 600, "height": 272},
surface="#EFEADD",
surface_header="#005F5F",
)
feed = client.custom_feeds.create("Branded Feed", theme=theme)Documents and publications are addressed by AT-URI — pass the raw URI, the SDK percent-encodes it for you.
# Fetch a document (HTML by default; format="blocks" for structured pages)
doc = client.longform.document("at://did:plc:x/site.standard.document/3k2a")
print(doc["title"], doc["content_html"])
# Fetch a publication
pub = client.longform.publication("at://did:plc:x/site.standard.publication/self")
# List a publication's documents (offset maps to the API's `from` param)
docs = client.longform.publication_documents(pub["uri"], tags=["essays"], count=50)
# Search publications (also available as client.search.publications)
pubs = client.longform.search_publications("climate")Posts in feed and search responses may include an optional document summary
(title, description, cover_image_url, tags, publication_uri) when they
link to a longform document.
# Create a radio station from a feed
station = client.audio.create_station(feed_surf_id="surf/topic/technology")
# Generate a program
program = client.audio.generate_program(station["id"])
# Get the audio manifest
manifest = client.audio.get_program(station["id"])
# Get today's briefing
briefing = client.audio.get_briefing()
# Get a transcript
transcript = client.audio.get_transcript("surf/post/abc123")from surf_api import SurfClient, SurfRateLimitError, SurfAuthError, SurfNotFoundError
client = SurfClient("surf_sk_live_your_token_here")
try:
feed = client.feeds.get("surf/topic/nonexistent")
except SurfNotFoundError:
print("Feed not found")
except SurfRateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after} seconds")
except SurfAuthError:
print("Invalid API token")client = SurfClient(
api_key="surf_sk_live_...",
base_url="https://api.surf.social", # default
timeout=30, # request timeout in seconds
)Build autonomous agents that interact with the social web. Requires claude-agent-sdk:
pip install claude-agent-sdkimport asyncio
from surf_api.agent import SurfAgent
async def main():
agent = SurfAgent(surf_api_key="surf_sk_live_your_token")
result = await agent.run(
"Find the top AI feeds on Surf and summarize the latest posts"
)
print(result.text)
asyncio.run(main())The agent connects to Surf via MCP with 20 read-only tools enabled by default. To also allow posting, favouriting, and feed creation (24 tools total), set allow_writes=True:
agent = SurfAgent(surf_api_key="surf_sk_live_your_token", allow_writes=True)All Claude compute runs on your Agent SDK credit.
The Surf API is also available as an MCP server for Claude Code and other MCP-compatible clients. See the API documentation for details.