Guides/Python

Social media API from Python

Complete Python guide: install the SDK, connect social accounts via OAuth, post to Instagram, Facebook, Threads, TikTok, LinkedIn, YouTube, and Google Business, schedule with datetime, pull analytics, manage the inbox, and handle webhooks with Flask.

~15 minPython 3.9+Flask (optional)
Prerequisites
  • • Python 3.9+ with pip
  • • An Aether account — free, no credit card required
  • • At least one connected social profile (Business/Creator accounts for Instagram)

Step 1 — Install the SDK

pip install aether

Set your API key as an environment variable:

# Set your API key in the environment
export AETHER_API_KEY="your_api_key_here"

# Or use a .env file with python-dotenv:
# pip install python-dotenv
# AETHER_API_KEY=your_api_key_here

Step 2 — Instantiate the client

import os
from aether import Aether

client = Aether(api_key=os.environ["AETHER_API_KEY"])

# Verify the connection
profiles = client.profiles.list()
print(f"Connected profiles: {len(profiles.data)}")

Step 3 — Connect a social account

Each platform requires OAuth. Aether's Connect Links handle the entire flow — generate a URL, open it in a browser, authenticate on the platform, and the profile appears in your account immediately:

import os
import webbrowser
from aether import Aether

client = Aether(api_key=os.environ["AETHER_API_KEY"])

# Generate an OAuth Connect Link for Instagram
link = client.connect_links.create(
    platform="instagram",
    # After authentication, Instagram redirects here
    redirect_url="https://your-app.com/oauth/callback",
)

print(f"Connect URL: {link.url}")
# Open in the browser so the user can authenticate
webbrowser.open(link.url)

# After OAuth, the profile appears immediately:
profiles = client.profiles.list()
instagram = next(p for p in profiles.data if p.platform == "instagram")
print(f"Connected: {instagram.display_name} ({instagram.id})")
# ig_abc123

Step 4 — Post immediately

Pass an array of profile IDs to post to multiple platforms in one call:

import os
from aether import Aether

client = Aether(api_key=os.environ["AETHER_API_KEY"])

# Post immediately to multiple platforms
post = client.posts.create(
    text="New release is live — check the changelog 🚀",
    profile_ids=[
        "ig_abc123",   # Instagram
        "li_comp789",  # LinkedIn
        "th_user456",  # Threads
    ],
    media_urls=["https://your-cdn.com/release-screenshot.png"],
)

print(post.data.id)      # post_abc123
print(post.data.status)  # "publishing"

Step 5 — Schedule for a future time

Pass scheduled_for as an ISO 8601 string. Python's datetime module makes this straightforward:

import os
from datetime import datetime, timezone, timedelta
from aether import Aether

client = Aether(api_key=os.environ["AETHER_API_KEY"])

# Schedule for tomorrow at 9am UTC
tomorrow_9am = (
    datetime.now(timezone.utc).replace(hour=9, minute=0, second=0, microsecond=0)
    + timedelta(days=1)
).isoformat()

post = client.posts.create(
    text="Good morning — here's what we shipped this week.",
    profile_ids=["ig_abc123", "li_comp789"],
    scheduled_for=tomorrow_9am,  # "2026-07-16T09:00:00+00:00"
)

print(post.data.status)       # "scheduled"
print(post.data.scheduled_for)  # 2026-07-16T09:00:00+00:00

Per-platform content overrides

Use the overrides dict to write different copy per platform — all in one API call:

# Per-platform overrides — tailor content per profile in one call
post = client.posts.create(
    text="Default caption — shown if no override is set for a profile.",
    profile_ids=["ig_abc123", "li_comp789", "tt_xyz789"],
    overrides={
        "ig_abc123": {
            "text": "Launch day 🎉 #buildinpublic #saas #startup",
        },
        "li_comp789": {
            "text": (
                "Today we shipped a major product update. "
                "Here's what changed and what's coming next:"
            ),
        },
        "tt_xyz789": {
            "text": "we shipped something wild. let me explain 👀",
        },
    },
)

Pull analytics

Account-level and post-level metrics for connected accounts:

import os
from aether import Aether

client = Aether(api_key=os.environ["AETHER_API_KEY"])

# Account-level metrics for the last 30 days
metrics = client.analytics.get_account_metrics(
    from_date="2026-06-01",
    to_date="2026-06-30",
    granularity="day",
    platform="instagram",  # optional — omit to list all connected profiles
)

for point in metrics.data:
    print(f"{point.date}: {point.impressions} impressions, {point.engagement} engagements")

# Post-level metrics
post_metrics = client.analytics.get_post_metrics("post_abc123")
for m in post_metrics.data:
    print(f"{m.platform}: {m.metric_type} = {m.value}")

Read and reply to the inbox

DMs and comments from all platforms in one unified API:

# Read and reply to DMs for connected accounts
messages = client.inbox.list(status="unread", limit=20)

for msg in messages.data:
    print(f"[{msg.platform}] {msg.sender_name}: {msg.text}")

    # Reply to the message
    if "pricing" in msg.text.lower():
        client.inbox.reply(
            message_id=msg.id,
            text="Thanks for reaching out! Here's our pricing: https://aetherhq.dev/pricing",
        )

Handle webhooks with Flask

Build a Flask endpoint to receive real-time publish confirmations and incoming messages. Always verify the HMAC-SHA256 signature:

# Flask webhook handler with HMAC verification
import os
import hmac
import hashlib
from flask import Flask, request, jsonify

app = Flask(__name__)

def verify_signature(body: bytes, signature: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.route("/webhooks/aether", methods=["POST"])
def webhook():
    sig = request.headers.get("X-Aether-Signature", "")

    if not verify_signature(request.data, sig, os.environ["AETHER_WEBHOOK_SECRET"]):
        return jsonify({"error": "Invalid signature"}), 401

    payload = request.get_json(force=True)
    event   = payload.get("event")
    data    = payload.get("data", {})

    if event == "post.published":
        print(f"Published on {data['platform']}: {data.get('platformPostUrl')}")
        # Update your DB, notify users, etc.

    elif event == "post.failed":
        print(f"Failed on {data['platform']}: {data['error']['message']}")
        # Alert the user, schedule retry, etc.

    elif event == "message.created":
        print(f"New DM from {data['senderName']} on {data['platform']}")
        # Trigger auto-reply flow, alert support team, etc.

    return jsonify({"received": True}), 200

if __name__ == "__main__":
    app.run(port=5000)

Async usage

The SDK ships an AsyncAether client for use with asyncio:

# Async usage with httpx (Aether's Python SDK supports async)
import os
import asyncio
from aether import AsyncAether

async def main():
    client = AsyncAether(api_key=os.environ["AETHER_API_KEY"])

    # Post to 3 platforms concurrently
    post = await client.posts.create(
        text="Shipped something new today 🚀",
        profile_ids=["ig_abc123", "li_comp789", "th_user456"],
        scheduled_for="2026-07-20T09:00:00Z",
    )
    print(post.data.status)

    # Pull analytics while waiting on post confirmation
    metrics, profiles = await asyncio.gather(
        client.analytics.get_account_metrics(
            from_date="2026-07-01",
            to_date="2026-07-14",
        ),
        client.profiles.list(),
    )
    print(f"{len(profiles.data)} profiles, {len(metrics.data)} data points")

asyncio.run(main())
What you've covered
  • pip install aether + API key setup
  • Connecting social accounts via Connect Links
  • Immediate and scheduled posting to multiple platforms
  • Per-platform content overrides in one call
  • Account and post analytics
  • Unified inbox read and reply
  • Flask webhook receiver with HMAC-SHA256 verification
  • Async usage with AsyncAether

Start building

Free API key — 3 connected accounts, all endpoints, no credit card.