Skip to main content

Official Python SDK for SocialAPI -- unified social media inbox API

Project description

SocialAPI Python SDK

CI PyPI version Python License: MIT

The official Python client for the SocialAPI REST API -- a unified inbox for comments, DMs, reviews, mentions, and publishing across Instagram, Facebook, Threads, TikTok, Google Business Profile, and LinkedIn.

Installation

pip install socialapi

Requires Python 3.10+.

Quick Start

from socialapi import SocialAPI

client = SocialAPI(api_key="sapi_key_...")

# List connected accounts
for account in client.accounts.list():
    print(f"{account.platform}: {account.name}")

# Reply to a comment via the resource API
client.comments.reply("ip_123", account_id="acc_ig_001", text="Thanks for the feedback!")

# Or use the active-record API: each returned object is bound to the client
posts = client.comments.list_posts(account_id="acc_ig_001").data
last_post = posts[0]

for comment in last_post.list_comments():
    if "spam" in comment.text:
        comment.hide()
    else:
        comment.reply(text="Thanks!")

# Publish a post to multiple platforms
post = client.publishing.create(
    text="Hello from the API!",
    targets=[
        {"account_id": "acc_ig_001"},
        {"account_id": "acc_fb_002"},
    ],
)

Two ways to call the API

Every list / get response returns models bound to the client, so action methods work directly on the object — comment.reply(...), post.update(...), brand.delete(). The resource API (client.comments.reply(...)) is still available and equivalent. Pick whichever reads better for the call site.

# Resource style — explicit, takes all IDs as arguments
client.comments.hide("ip_123", "cmt_456", account_id="acc_ig_001")

# Active-record style — IDs are inferred from the bound object
comment.hide()

Bound models built from raw JSON (InboxComment.model_validate(payload)) have no client and will raise UnboundModelError if you try to call action methods on them — fall back to the resource API in that case.

Authentication

Pass your API key directly or set it as an environment variable:

# Option 1: Constructor
client = SocialAPI(api_key="sapi_key_...")

# Option 2: Environment variable
#   export SOCIALAPI_API_KEY=sapi_key_...
client = SocialAPI()

You can generate API keys from the SocialAPI dashboard.

Async Support

Every method has an async equivalent via AsyncSocialAPI:

import asyncio
from socialapi import AsyncSocialAPI

async def main():
    async with AsyncSocialAPI(api_key="sapi_key_...") as client:
        async for comment in await client.conversations.list():
            await comment.send_message(text="hi")

asyncio.run(main())

Async resources return Async* model variants (AsyncInboxComment, AsyncPost, AsyncConversation, …) whose action methods are awaitable. Field shapes match the sync models exactly — the suffix only changes how the methods dispatch.

Usage Examples

Brands

# Create a brand to group accounts
brand = client.brands.create(name="Acme Corp")

# List all brands
for brand in client.brands.list():
    print(f"{brand.name} ({brand.accounts_count} accounts)")

# Update or delete
client.brands.update(brand.id, name="Acme Corporation")
client.brands.delete(brand.id)

Comments

# List posts with comments
posts = client.comments.list_posts(platform="instagram")

# Walk into a post's comments and act on them directly
for post in posts:
    for comment in post.list_comments():
        comment.reply(text="Thanks!")
        comment.like()
        # Threaded replies
        for reply in comment.list_replies():
            print(reply.text)

# Or stick with the resource API
client.comments.reply("ip_123", account_id="acc_ig_001", text="Thanks!", comment_id="cmt_456")
client.comments.hide("ip_123", "cmt_456", account_id="acc_ig_001")
client.comments.delete("ip_123", "cmt_456", account_id="acc_ig_001")

Direct Messages

# Walk into a conversation and reply on it directly
for conv in client.conversations.list(platform="instagram"):
    for message in conv.list_messages():
        print(f"{message.sender_name}: {message.text}")
    conv.send_message(text="Hi there!")
    conv.mark_as_read()

Reviews

# List reviews across Google Business Profile
for review in client.reviews.list(platform="google"):
    if review.rating >= 4:
        review.reply(text="Thank you!")

Publishing

from datetime import datetime, timezone

# Publish immediately
post = client.publishing.create(
    text="Check out our new product!",
    targets=[{"account_id": "acc_ig_001"}, {"account_id": "acc_fb_002"}],
)

# Schedule for later (pass a datetime directly)
post = client.publishing.create(
    text="Scheduled post!",
    targets=[{"account_id": "acc_ig_001"}],
    scheduled_at=datetime(2026, 4, 1, 12, 0, tzinfo=timezone.utc),
)

# Per-account text overrides
post = client.publishing.create(
    text="Default text",
    targets=[
        {"account_id": "acc_ig_001", "text": "Instagram-specific text"},
        {"account_id": "acc_li_002", "title": "LinkedIn Title", "visibility": "connections_only"},
    ],
)

# Validate before publishing
result = client.publishing.validate(text="Check this post", platforms=["instagram"])
if not result.valid:
    for issue in result.errors:
        print(f"{issue.platform}: {issue.message}")

Media

# Upload media for use in posts
upload = client.media.get_upload_url(media_type="image/jpeg", filename="photo.jpg")
# PUT the file to upload.upload_url, then verify:
client.media.verify(upload.media_id)

# List uploaded files
for item in client.media.list():
    print(f"{item.filename} ({item.size_bytes} bytes)")

# Check storage usage
usage = client.media.get_storage_usage()
print(f"Using {usage.used_bytes} of {usage.limit_bytes} bytes")

Account Management

# Inspect platform-specific creator settings (TikTok)
info = client.accounts.get_creator_info("acc_tt_001")
print(info.privacy_level_options, info.max_video_duration_sec)

# Manage Facebook Pages attached to an account
for page in client.accounts.list_pages("acc_fb_001"):
    if not page.is_default:
        page.update(is_default=True)

# Per-account platform quotas (e.g. Instagram posts_remaining)
limits = client.accounts.get_limits("acc_ig_001")

Analytics Exports

# Enqueue an export for a connected account (returns a bound Export)
export = client.accounts.export("acc_ig_001", include_transcript=True)

# Poll until done
while export.status not in ("completed", "failed"):
    export = export.refresh()

if export.status == "completed":
    print("Download:", export.download_url)
    for video in export.list_videos():
        print(video.url)

# Or list all recent jobs
for job in client.exports.list(status="completed"):
    print(job.id, job.completed_at)

OAuth Redirect URIs

If you're building a multi-tenant app that redirects end-users through SocialAPI's OAuth flow, you need to whitelist your callback URLs:

# Whitelist a callback
uri = client.oauth.create_redirect_uri(
    uri="https://app.example.com/oauth/done",
    label="production",
)

# List and clean up
for u in client.oauth.list_redirect_uris():
    if "staging" in (u.label or ""):
        u.delete()

Webhooks

# Subscribe to events
webhook = client.webhooks.create(
    url="https://example.com/webhook",
    events=["comment.received", "dm.received"],
)
print(f"Secret: {webhook.secret}")  # shown only once

# Bound list returns objects you can act on directly
for hook in client.webhooks.list():
    if not hook.is_active:
        hook.delete()

Pagination

List endpoints return a CursorPage that auto-paginates:

# Iterate through all pages automatically
for post in client.posts.list(status="published"):
    print(post.text)

# Or control pagination manually
page = client.posts.list(limit=10)
print(f"Page has {len(page)} items, has_more={page.has_more}")
if page.has_more:
    next_page = page.next_page()

Error Handling

The SDK raises typed exceptions mapped to API error codes:

from socialapi import (
    SocialAPIError,
    AuthenticationError,
    NotFoundError,
    RateLimitError,
)

try:
    client.comments.reply("ip_123", account_id="acc_001", text="Hello")
except AuthenticationError:
    print("Invalid API key")
except NotFoundError:
    print("Post not found")
except RateLimitError:
    print("Rate limited -- retry after backoff")
except SocialAPIError as e:
    print(f"API error {e.status_code}: {e.message}")
HTTP Status Exception When
400 BadRequestError Invalid parameters
401 AuthenticationError Bad or missing API key
403 ForbiddenError Permission denied
404 NotFoundError Resource doesn't exist
409 ConflictError Account already linked
413 StorageQuotaExceededError Storage quota exceeded
429 RateLimitError Rate limit hit
500 InternalServerError Server error
501 NotSupportedError Platform doesn't support this

Network and timeout errors raise APIConnectionError and APITimeoutError.

When using the active-record API, UnboundModelError is raised if you call an action method on a model that wasn't built by a client (e.g. one constructed via model_validate()), and MissingContextError is raised if a required contextual ID (like account_id) wasn't seeded — fall back to the resource API in those cases.

Configuration

client = SocialAPI(
    api_key="sapi_key_...",
    base_url="https://api.social-api.ai",  # default
    timeout=30.0,                           # seconds, default
    max_retries=2,                          # default
    debug=False,                            # log raw HTTP requests/responses
)

# Per-request timeout override
post = client.posts.get("p_123", timeout=60.0)

The client automatically retries on 429 (rate limit) and 5xx errors with exponential backoff and jitter. The Retry-After header is respected when present.

Resource Cleanup

Always close the client when done, or use it as a context manager:

# Context manager (recommended)
with SocialAPI(api_key="...") as client:
    client.posts.list()

# Manual close
client = SocialAPI(api_key="...")
try:
    client.posts.list()
finally:
    client.close()

Typed Enums

The SDK exports typed enums for API constants, enabling IDE autocomplete:

from socialapi import Platform, PostStatus, WebhookEvent

# Use in filters
posts = client.posts.list(platform=Platform.INSTAGRAM, status=PostStatus.PUBLISHED)

# Use in webhook subscriptions
client.webhooks.create(url="...", events=[WebhookEvent.COMMENT_RECEIVED])

API Reference

See the full API documentation at docs.social-api.ai.

Contributing

See CONTRIBUTING.md for development setup and guidelines.

License

MIT -- see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

socialapi-0.4.0.tar.gz (88.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

socialapi-0.4.0-py3-none-any.whl (72.3 kB view details)

Uploaded Python 3

File details

Details for the file socialapi-0.4.0.tar.gz.

File metadata

  • Download URL: socialapi-0.4.0.tar.gz
  • Upload date:
  • Size: 88.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for socialapi-0.4.0.tar.gz
Algorithm Hash digest
SHA256 b6f24539e172873efce47596666461e340fa67cec1144955cbb71e3f99fcfa07
MD5 f792229c5bfc011291fe2347c7750ec2
BLAKE2b-256 b1d651f5bb6a11fecbcf02a176ad95e41d5d1650b44f9626bccaf22d2e79fea4

See more details on using hashes here.

Provenance

The following attestation bundles were made for socialapi-0.4.0.tar.gz:

Publisher: publish.yml on SocialAPI-AI/socialapi-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file socialapi-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: socialapi-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 72.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for socialapi-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1d4745640ee88fa273952aecb358289edf9f3a4684b09dc7b83664af5c74767c
MD5 4d71c5b6380562b601dd8dd24b718b25
BLAKE2b-256 79a2c75fb7278c8cc2f5d987d55462c6be184d0f75f6e6c50f85431e2e0a3fb0

See more details on using hashes here.

Provenance

The following attestation bundles were made for socialapi-0.4.0-py3-none-any.whl:

Publisher: publish.yml on SocialAPI-AI/socialapi-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page