Skip to main content

fopost-fastapi

PyPI Python versions CI License: MIT

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

This is a thin wrapper. Every request, model, retry, and error type lives in the fopost SDK — this package wires that client into FastAPI's idioms: settings, dependency injection, a webhook receiver, and an exception handler.

pip install fopost-fastapi

Requires Python 3.10 or newer, FastAPI 0.110 or newer, and pydantic v2.

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 fastapi import FastAPI

from fopost_fastapi import FoPostDep, install_exception_handlers, setup_fopost

app = FastAPI()
setup_fopost(app)              # one client, created at startup, closed at shutdown
install_exception_handlers(app)


@app.get("/workspaces")
def workspaces(fopost: FoPostDep):
    return fopost.workspaces.list()

FoPostDep is Annotated[Fopost, Depends(get_client)]. The client is built once when the app starts and shared by every request — the dependency looks it up, it never constructs one.

If your app already has its own lifespan, setup_fopost wraps it rather than replacing it. To wire FoPost through the lifespan directly instead:

from fopost_fastapi import fopost_lifespan

app = FastAPI(lifespan=fopost_lifespan())

Settings

FoPostSettings is a pydantic-settings model reading FOPOST_-prefixed environment variables (and a .env file, if present).

Field Environment variable Default
api_key FOPOST_API_KEY — (required)
base_url FOPOST_BASE_URL https://api.fopost.com/v1
timeout FOPOST_TIMEOUT 30.0 seconds
max_retries FOPOST_MAX_RETRIES 3 attempts
default_workspace_id FOPOST_DEFAULT_WORKSPACE_ID
webhook_secret FOPOST_WEBHOOK_SECRET

Create an API key at https://app.fopost.com/api-keys. It is sent as X-API-Key.

Pass settings explicitly when you would rather not read the environment:

setup_fopost(app, FoPostSettings(api_key="fp_...", base_url="https://api.fopost.com/v1"))

FoPostSettingsDep injects the resolved settings into a route, which is how you reach default_workspace_id.

Sync or async? The SDK is synchronous

The fopost package ships a blocking client only — there is no async variant, and this package deliberately does not write one. That leaves two shapes:

# A `def` route — FastAPI already runs it in a worker thread. Call the SDK directly.
@app.get("/accounts")
def accounts(fopost: FoPostDep, settings: FoPostSettingsDep):
    return fopost.accounts.list(workspace_id=settings.default_workspace_id)


# An `async def` route — the call must leave the event loop, or it stalls the server.
from fopost_fastapi import run_fopost

@app.post("/posts")
async def create(fopost: FoPostDep, settings: FoPostSettingsDep):
    return await run_fopost(
        fopost.posts.create,
        workspace_id=settings.default_workspace_id,
        content="Hello from FastAPI",
        accounts=["<account id>"],
    )

run_fopost is a thin wrapper over fastapi.concurrency.run_in_threadpool. Never call the SDK straight from an async def route: a 30-second timeout would block every other request.

Receiving webhooks

from fopost_fastapi import WebhookEvent, on_event, webhook_router

app.include_router(webhook_router, prefix="/fopost")   # POST /fopost/webhooks


@on_event("post.published")
async def published(event: WebhookEvent) -> None:
    print(event.data["id"], event.timestamp)


@on_event("post.failed")
def failed(event: WebhookEvent) -> None:      # a `def` handler runs in a worker thread
    ...

Point a FoPost webhook at https://<your host>/fopost/webhooks and put its secret in FOPOST_WEBHOOK_SECRET.

FoPost signs each delivery with HMAC-SHA256 over the raw request body using that webhook's secret, and sends it as X-FoPost-Signature: sha256=<hex> alongside X-FoPost-Event and X-FoPost-Delivery. The router reads the raw bytes before any parsing, compares with hmac.compare_digest, and answers 401 on a mismatch or a missing header — no handler runs. With no secret configured at all it answers 500 rather than accepting unverifiable traffic.

Events: post.published, post.failed, post.partially_failed, delivery.published, delivery.failed, delivery.delayed, account.health_changed. @on_event() with no argument subscribes to all of them.

Run several receivers, or keep the secret out of the environment, by building your own router:

from fopost_fastapi import FoPostWebhookRouter

router = FoPostWebhookRouter(secret="whsec_...", path="/callbacks")
app.include_router(router, prefix="/fopost")

sign_payload(body, secret) and verify_webhook_signature(body, header, secret) are exported if you need to verify a delivery somewhere else.

Error handling

install_exception_handlers(app) turns an SDK exception into the status the FoPost API actually answered with, instead of a 500 and a stack trace.

SDK error Response
AuthenticationError (401), PermissionDeniedError (403), NotFoundError (404) the same status
PaymentRequiredError (402) 402, body keeps upgrade_url
RateLimitError (429) 429 with a Retry-After header
any 4xx the same status
any 5xx or transport failure 502 — your app is fine, its dependency is not

The body is the API's own envelope: {"error": "<machine code>", "message": "<human text>"}.

Retries are the SDK's job, not this package's: a 429 is retried up to max_retries attempts, honouring Retry-After, before the error ever reaches the handler.

The rest of the API

Everything you can call on the injected client — posts, accounts, workspaces, labels, ai, and the request() escape hatch for endpoints the SDK does not wrap — is documented in the fopost SDK. This package adds no resources of its own and stores nothing.

Example

examples/main.py is a complete app: settings from the environment, the injected client in both a def and an async def route, and the webhook receiver.

Development

python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
pytest
ruff check . && ruff format --check .
mypy

The suite is fully offline — it stubs the SDK's HTTP transport and never reaches the network.

Links

MIT licensed. Copyright (c) 2026 Porter Bridge, LLC.

Download files

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

Source Distribution

fopost_fastapi-0.1.0.tar.gz (14.7 kB view details)

Uploaded Source

Built Distribution

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

fopost_fastapi-0.1.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file fopost_fastapi-0.1.0.tar.gz.

File metadata

  • Download URL: fopost_fastapi-0.1.0.tar.gz
  • Upload date:
  • Size: 14.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fopost_fastapi-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0a57f890ac9db8601016b6ba33fd6440e54b3502a6f6c01e70ef1d5b3c53be64
MD5 20133a10c04cb580d21da4708efc644e
BLAKE2b-256 c1b5260c41533136a0f2b22f3f972ca3b07a72d5e73734511cfa10d4bad4fd25

See more details on using hashes here.

Provenance

The following attestation bundles were made for fopost_fastapi-0.1.0.tar.gz:

Publisher: release.yml on fopost/fopost-fastapi

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

File details

Details for the file fopost_fastapi-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: fopost_fastapi-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fopost_fastapi-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c81593ad9d2359e2e24297fa8709774ec27c347bbbad596121e3e7894b3201f8
MD5 8d7b74f6fbf50252fa4566c2ad3da083
BLAKE2b-256 2bc1c5b53256d7c17d038b3ba5f1c4e1b43ca23b629598dea700707fb07e2ea0

See more details on using hashes here.

Provenance

The following attestation bundles were made for fopost_fastapi-0.1.0-py3-none-any.whl:

Publisher: release.yml on fopost/fopost-fastapi

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

Release history Release notifications | RSS feed

0.1.1

2 files

This release

0.1.0 This release

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