Skip to main content

fopost

PyPI Python versions CI License: MIT

Official Python SDK for the FoPost API. Schedule and publish to +30 social platforms from your code.

pip install fopost

Requires Python 3.10 or newer. Built on httpx and pydantic v2, fully typed.

0.x release. The public API is still settling and minor versions may contain breaking changes. Pin an exact version if that matters to you.

Quick start

from fopost import Fopost

client = Fopost(api_key="fp_...")  # or set FOPOST_API_KEY

workspace = client.workspaces.list()[0]
accounts = client.accounts.list(workspace_id=workspace.id)

post = client.posts.create(
    workspace_id=workspace.id,
    content="Hello from Python",
    accounts=[a.id for a in accounts],
)

client.posts.publish(post.id)

content takes a string for a single block, or a list for a thread:

client.posts.create(
    workspace_id=workspace.id,
    content=[
        "First post in the thread",
        {
            "text": "Second one, with an image",
            "media": [
                {"type": "image", "name": "chart.png", "url": "https://.../chart.png"},
            ],
        },
    ],
    accounts=[a.id for a in accounts],
)

Scheduling

status is "draft" or "scheduled"; a scheduled post needs schedule_at. To send something out now, create it and call publish.

from datetime import datetime, timezone

client.posts.create(
    workspace_id=workspace.id,
    status="scheduled",
    schedule_at=datetime(2026, 9, 1, 10, 0, tzinfo=timezone.utc),
    content="Scheduled with the SDK",
    accounts=[accounts[0].id],
)

Pagination

posts.list returns one page and iterates over its items directly. posts.iter walks every page for you:

page = client.posts.list(workspace_id=workspace.id, status="published", per_page=50)
print(f"{page.meta.total} published posts")
for post in page:
    print(post.id, post.status)

# Every post, one page fetched at a time
for post in client.posts.iter(workspace_id=workspace.id):
    print(post.id)

# Or page by page, when you want the meta
for page in client.posts.iter_pages(workspace_id=workspace.id):
    print(page.meta.current_page, len(page))

AI features

balance = client.ai.credits()
print(f"{balance.credits_remaining} of {balance.credits_total} credits left")

result = client.ai.generate_caption(
    current_caption="shipping a new feature",
    platforms=["twitter", "linkedin"],
)
print(result.caption)

rewrite and repurpose_url are wired the same way:

rewrites = client.ai.rewrite(
    content="Long article-style draft...",
    platforms=["twitter", "linkedin", "bluesky"],
)
for variant in rewrites.results:
    print(variant.platform, variant.content)

repurposed = client.ai.repurpose_url(
    url="https://example.com/blog/post",
    platforms=["twitter", "linkedin", "bluesky", "threads"],
)

API keys reach credits and generate_caption. rewrite and repurpose_url currently require a signed-in dashboard session and answer 401 to an API key. They are here so the surface is complete once the server opens them up.

Configuration

Fopost(
    api_key="fp_...",  # or FOPOST_API_KEY
    base_url="https://api.fopost.com/api/v1",  # override for a dev server
    timeout=30.0,  # seconds, or an httpx.Timeout
    max_retries=3,  # total attempts on a 429
    http_client=my_httpx_client,  # bring your own transport
)
Env var Used for
FOPOST_API_KEY API key, when not passed to the constructor

The client is a context manager, and closes its transport on exit:

with Fopost() as client:
    client.posts.list(workspace_id=workspace.id)

A 429 is retried automatically, waiting for the interval the API asks for in Retry-After (delta-seconds or an HTTP date, capped at 60s). max_retries counts total attempts, so the default of 3 means two retries.

Error handling

Every non-2xx response raises FopostError or one of its subclasses, carrying the API's status, code, and message.

from fopost import Fopost, FopostError, PaymentRequiredError, RateLimitError

try:
    client.posts.publish("9b2f6c1e-...")
except PaymentRequiredError as err:
    print(f"Out of credits — upgrade at {err.upgrade_url}")
except RateLimitError as err:
    print(f"Rate limited, retry in {err.retry_after}s")
except FopostError as err:
    print(f"API {err.status} ({err.code}): {err.message}")
Status Exception
401 AuthenticationError
402 PaymentRequiredError
403 PermissionDeniedError
404 NotFoundError
429 RateLimitError
other FopostError

Resources

Namespace Methods
posts list, iter, iter_pages, get, create, update, delete, publish, cancel, retry, preflight, deliveries
accounts list, get, health
workspaces list, get
labels list
ai credits, generate_caption, rewrite, repurpose_url

For an endpoint the SDK does not wrap yet, client.request sends an authenticated call and hands back the decoded body:

client.request("GET", "/analytics/summary", params={"workspace_id": workspace.id})

Example

examples/create_post.py creates a post against a running API:

export FOPOST_API_KEY=fp_...
export FOPOST_BASE_URL=http://localhost:8080/api/v1
python examples/create_post.py "Hello from the Python SDK" --publish

Contributing

Issues and pull requests are welcome at fopost/fopost-python.

uv sync --group dev
uv run pytest
uv run ruff check .
uv run mypy

License

MIT

Questions or a problem: fopost.com/contact.

Download files

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

Source Distribution

fopost-0.1.1.tar.gz (20.0 kB view details)

Uploaded Source

Built Distribution

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

fopost-0.1.1-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file fopost-0.1.1.tar.gz.

File metadata

  • Download URL: fopost-0.1.1.tar.gz
  • Upload date:
  • Size: 20.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.2

File hashes

Hashes for fopost-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f4adecfe38d2dda12edf632f9fe92f39fd4a8fa2116343fee788f1456dc20f25
MD5 9a99bfc60b7d284deee112dc40af728d
BLAKE2b-256 f82d055ac535486fbce8a5e17371d248840c8b94e05ce63bed3b7f8dbef9827e

See more details on using hashes here.

File details

Details for the file fopost-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: fopost-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 18.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.2

File hashes

Hashes for fopost-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0097919e5db84ad2cf8faef78dbaf36eab3e25dd2fe94d0de83702dc284df2f9
MD5 faf86622885d72d6e188e1792f8d100e
BLAKE2b-256 68dad6b2c92d7c661250ed632525a97d831754de6beb0dc0e8f02671f1f4b761

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.3

2 files

0.1.2

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page