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.2.tar.gz (20.1 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.2-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: fopost-0.1.2.tar.gz
  • Upload date:
  • Size: 20.1 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.2.tar.gz
Algorithm Hash digest
SHA256 032b4fb016cc14ae642121cc91f03efab835dd39cd107493205e17002266e50f
MD5 3eb77441f4cab2ab4cf78d80243de4cb
BLAKE2b-256 bea50212fd11da505eeae959a12df52f4fca0dce4097823c02a677c901119983

See more details on using hashes here.

File details

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

File metadata

  • Download URL: fopost-0.1.2-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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 eca119c42e94b33e161cfd455ae63ed61e22f5a538cce63690a81db384eeb488
MD5 cb12a09dd73392919e1a84d53dd8d5f3
BLAKE2b-256 cc0ff2396497033b6d80ea4c0000281a04e88dbddd49dd6874a5c6ba58d3a25b

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.3

2 files

This release

0.1.2 This release

2 files

0.1.1

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